summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2022-03-11 17:25:26 -0500
committerGravatar GitHub <noreply@github.com> 2022-03-11 17:25:26 -0500
commit77b9c95352f441021b8a0b03f891ea6ad00117ce (patch)
tree988944bbd44038bcab1c4fb4f034ca171b837f60
parent2bb2c2f7d153863319652dbc93396bedd1a16756 (diff)
downloadastro-77b9c95352f441021b8a0b03f891ea6ad00117ce.tar.gz
astro-77b9c95352f441021b8a0b03f891ea6ad00117ce.tar.zst
astro-77b9c95352f441021b8a0b03f891ea6ad00117ce.zip
Feat: expose server on local network with new --host flag (#2760)
* feat: update config to support bool --hostname * fix: show localhost for --hostname=true * feat: address logging feature parity w/ Vite * chore: update type docs * refactor: extract local, network prefs to variable * feat: add --host to --help output * feat: deprecate --hostname, add --host * feat: add --host tests * feat: update preview to support new flags * fix: show --host in dev server log * feat: update config tests for --host flag * chore: test lint * chore: update lock with new fixture * chore: add changeset * refactor: add more details to JSdocs * fix: update path tests * feat: only expose when --host is not local * fix: make flag --help less verbose * fix: address @types comments * fix: lint * chore: remove unused import * fix: use host flag for config test * fix: ensure local logs come before network * refactor: switch up that network logging one last time! * feat: update unit tests * chore: remove debugging block * fix: only parse network logs if network is present
-rw-r--r--.changeset/breezy-walls-guess.md5
-rw-r--r--packages/astro/src/@types/astro.ts18
-rw-r--r--packages/astro/src/cli/index.ts1
-rw-r--r--packages/astro/src/core/config.ts3
-rw-r--r--packages/astro/src/core/dev/index.ts22
-rw-r--r--packages/astro/src/core/dev/util.ts34
-rw-r--r--packages/astro/src/core/messages.ts53
-rw-r--r--packages/astro/src/core/preview/index.ts19
-rw-r--r--packages/astro/src/core/preview/util.ts17
-rw-r--r--packages/astro/test/cli.test.js66
-rw-r--r--packages/astro/test/config.test.js49
-rw-r--r--packages/astro/test/fixtures/config-host/astro.config.mjs6
-rw-r--r--packages/astro/test/fixtures/config-host/package.json8
-rw-r--r--packages/astro/test/fixtures/config-path/config/my-config.mjs2
-rw-r--r--packages/astro/test/test-utils.js14
-rw-r--r--pnpm-lock.yaml6
16 files changed, 238 insertions, 85 deletions
diff --git a/.changeset/breezy-walls-guess.md b/.changeset/breezy-walls-guess.md
new file mode 100644
index 000000000..160423173
--- /dev/null
+++ b/.changeset/breezy-walls-guess.md
@@ -0,0 +1,5 @@
+---
+'astro': minor
+---
+
+Introduce a new --host flag + host devOption to expose your server on a network IP
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 452974d63..400f5070b 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -24,6 +24,7 @@ export interface CLIFlags {
projectRoot?: string;
site?: string;
sitemap?: boolean;
+ host?: string | boolean;
hostname?: string;
port?: number;
config?: string;
@@ -316,10 +317,27 @@ export interface AstroUserConfig {
devOptions?: {
/**
* @docs
+ * @name devOptions.host
+ * @type {string | boolean}
+ * @default `false`
+ * @version 0.24.0
+ * @description
+ * Set which network IP addresses the dev server should listen on (i.e. non-localhost IPs).
+ * - `false` - do not expose on a network IP address
+ * - `true` - listen on all addresses, including LAN and public addresses
+ * - `[custom-address]` - expose on a network IP address at `[custom-address]`
+ */
+ host?: string | boolean;
+
+ /**
+ * @docs
* @name devOptions.hostname
* @type {string}
* @default `'localhost'`
+ * @deprecated Use `host` instead
* @description
+ * > **This option is deprecated.** Consider using `host` instead.
+ *
* Set which IP addresses the dev server should listen on. Set this to 0.0.0.0 to listen on all addresses, including LAN and public addresses.
*/
hostname?: string;
diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts
index afb564847..ffa1071cc 100644
--- a/packages/astro/src/cli/index.ts
+++ b/packages/astro/src/cli/index.ts
@@ -38,6 +38,7 @@ function printHelp() {
title('Flags');
table(
[
+ ['--host [optional IP]', 'Expose server on network'],
['--config <path>', 'Specify the path to the Astro config file.'],
['--project-root <path>', 'Specify the path to the project root folder.'],
['--no-sitemap', 'Disable sitemap generation (build only).'],
diff --git a/packages/astro/src/core/config.ts b/packages/astro/src/core/config.ts
index e20bc4132..5400a9514 100644
--- a/packages/astro/src/core/config.ts
+++ b/packages/astro/src/core/config.ts
@@ -65,6 +65,7 @@ export const AstroConfigSchema = z.object({
.default({}),
devOptions: z
.object({
+ host: z.union([z.string(), z.boolean()]).optional().default(false),
hostname: z.string().optional().default('localhost'),
port: z.number().optional().default(3000),
trailingSlash: z
@@ -125,6 +126,7 @@ function resolveFlags(flags: Partial<Flags>): CLIFlags {
port: typeof flags.port === 'number' ? flags.port : undefined,
config: typeof flags.config === 'string' ? flags.config : undefined,
hostname: typeof flags.hostname === 'string' ? flags.hostname : undefined,
+ host: typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
legacyBuild: typeof flags.legacyBuild === 'boolean' ? flags.legacyBuild : false,
experimentalSsr: typeof flags.experimentalSsr === 'boolean' ? flags.experimentalSsr : false,
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : false,
@@ -138,6 +140,7 @@ function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) {
if (typeof flags.sitemap === 'boolean') astroConfig.buildOptions.sitemap = flags.sitemap;
if (typeof flags.site === 'string') astroConfig.buildOptions.site = flags.site;
if (typeof flags.port === 'number') astroConfig.devOptions.port = flags.port;
+ if (typeof flags.host === 'string' || typeof flags.host === 'boolean') astroConfig.devOptions.host = flags.host;
if (typeof flags.hostname === 'string') astroConfig.devOptions.hostname = flags.hostname;
if (typeof flags.legacyBuild === 'boolean') astroConfig.buildOptions.legacyBuild = flags.legacyBuild;
if (typeof flags.experimentalSsr === 'boolean') {
diff --git a/packages/astro/src/core/dev/index.ts b/packages/astro/src/core/dev/index.ts
index 085e5d665..a1b48e1d9 100644
--- a/packages/astro/src/core/dev/index.ts
+++ b/packages/astro/src/core/dev/index.ts
@@ -6,7 +6,7 @@ import { createVite } from '../create-vite.js';
import { defaultLogOptions, info, warn, LogOptions } from '../logger.js';
import * as vite from 'vite';
import * as msg from '../messages.js';
-import { getLocalAddress } from './util.js';
+import { getResolvedHostForVite } from './util.js';
export interface DevOptions {
logging: LogOptions;
@@ -24,13 +24,13 @@ export default async function dev(config: AstroConfig, options: DevOptions = { l
polyfill(globalThis, {
exclude: 'window document',
});
- // start the server
+
+ // TODO: remove call once --hostname is baselined
+ const host = getResolvedHostForVite(config);
const viteUserConfig = vite.mergeConfig(
{
mode: 'development',
- server: {
- host: config.devOptions.hostname,
- },
+ server: { host },
},
config.vite || {}
);
@@ -38,15 +38,9 @@ export default async function dev(config: AstroConfig, options: DevOptions = { l
const viteServer = await vite.createServer(viteConfig);
await viteServer.listen(config.devOptions.port);
- const address = viteServer.httpServer!.address() as AddressInfo;
- const localAddress = getLocalAddress(address.address, config.devOptions.hostname);
- // Log to console
+ const devServerAddressInfo = viteServer.httpServer!.address() as AddressInfo;
const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined;
- info(
- options.logging,
- null,
- msg.devStart({ startupTime: performance.now() - devStart, port: address.port, localAddress, networkAddress: address.address, site, https: !!viteUserConfig.server?.https })
- );
+ info(options.logging, null, msg.devStart({ startupTime: performance.now() - devStart, config, devServerAddressInfo, site, https: !!viteUserConfig.server?.https }));
const currentVersion = process.env.PACKAGE_VERSION ?? '0.0.0';
if (currentVersion.includes('-')) {
@@ -54,7 +48,7 @@ export default async function dev(config: AstroConfig, options: DevOptions = { l
}
return {
- address,
+ address: devServerAddressInfo,
stop: () => viteServer.close(),
};
}
diff --git a/packages/astro/src/core/dev/util.ts b/packages/astro/src/core/dev/util.ts
index 97b622438..9b0c974fd 100644
--- a/packages/astro/src/core/dev/util.ts
+++ b/packages/astro/src/core/dev/util.ts
@@ -1,3 +1,7 @@
+import type { AstroConfig } from '../../@types/astro';
+
+export const localIps = new Set(['localhost', '127.0.0.1']);
+
/** Pad string () */
export function pad(input: string, minLength: number, dir?: 'left' | 'right'): string {
let output = input;
@@ -11,10 +15,36 @@ export function emoji(char: string, fallback: string) {
return process.platform !== 'win32' ? char : fallback;
}
-export function getLocalAddress(serverAddress: string, configHostname: string): string {
- if (configHostname === 'localhost' || serverAddress === '127.0.0.1' || serverAddress === '0.0.0.0') {
+// TODO: remove once --hostname is baselined
+export function getResolvedHostForVite(config: AstroConfig) {
+ if (config.devOptions.host === false && config.devOptions.hostname !== 'localhost') {
+ return config.devOptions.hostname;
+ } else {
+ return config.devOptions.host;
+ }
+}
+
+export function getLocalAddress(serverAddress: string, config: AstroConfig): string {
+ // TODO: remove once --hostname is baselined
+ const host = getResolvedHostForVite(config);
+ if (typeof host === 'boolean' || host === 'localhost') {
return 'localhost';
} else {
return serverAddress;
}
}
+
+export type NetworkLogging = 'none' | 'host-to-expose' | 'visible';
+
+export function getNetworkLogging(config: AstroConfig): NetworkLogging {
+ // TODO: remove once --hostname is baselined
+ const host = getResolvedHostForVite(config);
+
+ if (host === false) {
+ return 'host-to-expose';
+ } else if (typeof host === 'string' && localIps.has(host)) {
+ return 'none';
+ } else {
+ return 'visible';
+ }
+}
diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts
index a538e7bbb..c84a454d1 100644
--- a/packages/astro/src/core/messages.ts
+++ b/packages/astro/src/core/messages.ts
@@ -2,10 +2,12 @@
* Dev server messages (organized here to prevent clutter)
*/
-import type { AddressInfo } from 'net';
import stripAnsi from 'strip-ansi';
import { bold, dim, red, green, underline, yellow, bgYellow, cyan, bgGreen, black } from 'kleur/colors';
-import { pad, emoji } from './dev/util.js';
+import { pad, emoji, getLocalAddress, getNetworkLogging } from './dev/util.js';
+import os from 'os';
+import type { AddressInfo } from 'net';
+import type { AstroConfig } from '../@types/astro';
const PREFIX_PADDING = 6;
@@ -30,31 +32,50 @@ export function hmr({ file }: { file: string }): string {
/** Display dev server host and startup time */
export function devStart({
startupTime,
- port,
- localAddress,
- networkAddress,
+ devServerAddressInfo,
+ config,
https,
site,
}: {
startupTime: number;
- port: number;
- localAddress: string;
- networkAddress: string;
+ devServerAddressInfo: AddressInfo;
+ config: AstroConfig;
https: boolean;
site: URL | undefined;
}): string {
- // PACAKGE_VERSION is injected at build-time
+ // PACKAGE_VERSION is injected at build-time
const version = process.env.PACKAGE_VERSION ?? '0.0.0';
const rootPath = site ? site.pathname : '/';
+ const localPrefix = `${dim('┃')} Local `;
+ const networkPrefix = `${dim('┃')} Network `;
+
+ const { address: networkAddress, port } = devServerAddressInfo;
+ const localAddress = getLocalAddress(networkAddress, config);
+ const networkLogging = getNetworkLogging(config);
const toDisplayUrl = (hostname: string) => `${https ? 'https' : 'http'}://${hostname}:${port}${rootPath}`;
+ let addresses = [];
+
+ if (networkLogging === 'none') {
+ addresses = [`${localPrefix}${bold(cyan(toDisplayUrl(localAddress)))}`];
+ } else if (networkLogging === 'host-to-expose') {
+ addresses = [`${localPrefix}${bold(cyan(toDisplayUrl(localAddress)))}`, `${networkPrefix}${dim('use --host to expose')}`];
+ } else {
+ addresses = Object.values(os.networkInterfaces())
+ .flatMap((networkInterface) => networkInterface ?? [])
+ .filter((networkInterface) => networkInterface?.address && networkInterface?.family === 'IPv4')
+ .map(({ address }) => {
+ if (address.includes('127.0.0.1')) {
+ const displayAddress = address.replace('127.0.0.1', localAddress);
+ return `${localPrefix}${bold(cyan(toDisplayUrl(displayAddress)))}`;
+ } else {
+ return `${networkPrefix}${bold(cyan(toDisplayUrl(address)))}`;
+ }
+ })
+ // ensure Local logs come before Network
+ .sort((msg) => (msg.startsWith(localPrefix) ? -1 : 1));
+ }
- const messages = [
- `${emoji('🚀 ', '')}${bgGreen(black(` astro `))} ${green(`v${version}`)} ${dim(`started in ${Math.round(startupTime)}ms`)}`,
- '',
- `${dim('┃')} Local ${bold(cyan(toDisplayUrl(localAddress)))}`,
- `${dim('┃')} Network ${bold(cyan(toDisplayUrl(networkAddress)))}`,
- '',
- ];
+ const messages = [`${emoji('🚀 ', '')}${bgGreen(black(` astro `))} ${green(`v${version}`)} ${dim(`started in ${Math.round(startupTime)}ms`)}`, '', ...addresses, ''];
return messages.map((msg) => ` ${msg}`).join('\n');
}
diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts
index b686cf3f9..71bdba82e 100644
--- a/packages/astro/src/core/preview/index.ts
+++ b/packages/astro/src/core/preview/index.ts
@@ -1,6 +1,5 @@
import type { AstroConfig } from '../../@types/astro';
import type { LogOptions } from '../logger';
-import type { Stats } from 'fs';
import type { AddressInfo } from 'net';
import http from 'http';
import sirv from 'sirv';
@@ -8,16 +7,15 @@ import { performance } from 'perf_hooks';
import { fileURLToPath } from 'url';
import * as msg from '../messages.js';
import { error, info } from '../logger.js';
-import { appendForwardSlash, trimSlashes } from '../path.js';
-import { getLocalAddress } from '../dev/util.js';
import { subpathNotUsedTemplate, notFoundTemplate } from '../../template/4xx.js';
+import { getResolvedHostForHttpServer } from './util.js';
interface PreviewOptions {
logging: LogOptions;
}
export interface PreviewServer {
- hostname: string;
+ host?: string;
port: number;
server: http.Server;
stop(): Promise<void>;
@@ -75,7 +73,8 @@ export default async function preview(config: AstroConfig, { logging }: PreviewO
}
});
- let { hostname, port } = config.devOptions;
+ let { port } = config.devOptions;
+ const host = getResolvedHostForHttpServer(config);
let httpServer: http.Server;
@@ -85,12 +84,10 @@ export default async function preview(config: AstroConfig, { logging }: PreviewO
let showedListenMsg = false;
return new Promise<void>((resolve, reject) => {
const listen = () => {
- httpServer = server.listen(port, hostname, async () => {
+ httpServer = server.listen(port, host, async () => {
if (!showedListenMsg) {
- const { address: networkAddress } = server.address() as AddressInfo;
- const localAddress = getLocalAddress(networkAddress, hostname);
-
- info(logging, null, msg.devStart({ startupTime: performance.now() - timerStart, port, localAddress, networkAddress, https: false, site: baseURL }));
+ const devServerAddressInfo = server.address() as AddressInfo;
+ info(logging, null, msg.devStart({ startupTime: performance.now() - timerStart, config, devServerAddressInfo, https: false, site: baseURL }));
}
showedListenMsg = true;
resolve();
@@ -121,7 +118,7 @@ export default async function preview(config: AstroConfig, { logging }: PreviewO
await startServer(startServerTime);
return {
- hostname,
+ host,
port,
server: httpServer!,
stop: async () => {
diff --git a/packages/astro/src/core/preview/util.ts b/packages/astro/src/core/preview/util.ts
new file mode 100644
index 000000000..90c42ec32
--- /dev/null
+++ b/packages/astro/src/core/preview/util.ts
@@ -0,0 +1,17 @@
+import type { AstroConfig } from '../../@types/astro';
+
+export function getResolvedHostForHttpServer(config: AstroConfig) {
+ const { host, hostname } = config.devOptions;
+
+ if (host === false && hostname === 'localhost') {
+ // Use a secure default
+ return '127.0.0.1';
+ } else if (host === true) {
+ // If passed --host in the CLI without arguments
+ return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs)
+ } else if (typeof host === 'string') {
+ return host;
+ } else {
+ return hostname;
+ }
+}
diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js
index 0072727a2..a90f26cef 100644
--- a/packages/astro/test/cli.test.js
+++ b/packages/astro/test/cli.test.js
@@ -1,9 +1,15 @@
import { expect } from 'chai';
-import { cli, parseCliDevStart } from './test-utils.js';
+import { cli, parseCliDevStart, cliServerLogSetup } from './test-utils.js';
import { promises as fs } from 'fs';
import { fileURLToPath } from 'url';
+import { isIPv4 } from 'net';
describe('astro cli', () => {
+ const cliServerLogSetupWithFixture = (flags, cmd) => {
+ const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
+ return cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), ...flags], cmd);
+ };
+
it('astro', async () => {
const proc = await cli();
@@ -32,28 +38,52 @@ describe('astro cli', () => {
expect(messages[0]).to.contain('started in');
});
- const hostnames = [undefined, '0.0.0.0', '127.0.0.1'];
+ ['dev', 'preview'].forEach((cmd) => {
+ const networkLogFlags = [['--host'], ['--host', '0.0.0.0'], ['--hostname', '0.0.0.0']];
+ networkLogFlags.forEach(([flag, flagValue]) => {
+ it(`astro ${cmd} ${flag} ${flagValue ?? ''} - network log`, async () => {
+ const { local, network } = await cliServerLogSetupWithFixture(flagValue ? [flag, flagValue] : [flag], cmd);
+
+ expect(local).to.not.be.undefined;
+ expect(network).to.not.be.undefined;
- hostnames.forEach((hostname) => {
- const hostnameArgs = hostname ? ['--hostname', hostname] : [];
- it(`astro dev ${hostnameArgs.join(' ') || '(no --hostname)'}`, async () => {
- const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
- const proc = cli('dev', '--project-root', fileURLToPath(projectRootURL), ...hostnameArgs);
+ const localURL = new URL(local);
+ const networkURL = new URL(network);
+
+ expect(localURL.hostname).to.be.equal(flagValue ?? 'localhost', `Expected local URL to be on localhost`);
+ // Note: our tests run in parallel so this could be 3000+!
+ expect(Number.parseInt(localURL.port)).to.be.greaterThanOrEqual(3000, `Expected Port to be >= 3000`);
+ expect(networkURL.port).to.be.equal(localURL.port, `Expected local and network ports to be equal`);
+ expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --host flag`);
+ });
+ });
- const { messages } = await parseCliDevStart(proc);
- const local = messages[1].replace(/Local\s*/g, '');
- const network = messages[2].replace(/Network\s*/g, '');
+ const hostToExposeFlags = [['', ''], ['--hostname', 'localhost']];
+ hostToExposeFlags.forEach(([flag, flagValue]) => {
+ it(`astro ${cmd} ${flag} ${flagValue} - host to expose`, async () => {
+ const { local, network } = await cliServerLogSetupWithFixture([flag, flagValue], cmd);
+
+ expect(local).to.not.be.undefined;
+ expect(network).to.not.be.undefined;
+ const localURL = new URL(local);
+
+ expect(localURL.hostname).to.be.equal('localhost', `Expected local URL to be on localhost`);
+ expect(() => new URL(networkURL)).to.throw();
+ });
+ });
+
+ const noNetworkLogFlags = [['--host', 'localhost'], ['--host', '127.0.0.1'], ['--hostname', '127.0.0.1']];
+ noNetworkLogFlags.forEach(([flag, flagValue]) => {
+ it(`astro ${cmd} ${flag} ${flagValue} - no network log`, async () => {
+ const { local, network } = await cliServerLogSetupWithFixture([flag, flagValue], cmd);
- expect(local).to.not.be.undefined;
- expect(network).to.not.be.undefined;
- const localURL = new URL(local);
- const networkURL = new URL(network);
+ expect(local).to.not.be.undefined;
+ expect(network).to.be.undefined;
- expect(localURL.hostname).to.be.equal('localhost', `Expected local URL to be on localhost`);
- // Note: our tests run in parallel so this could be 3000+!
- expect(Number.parseInt(localURL.port)).to.be.greaterThanOrEqual(3000, `Expected Port to be >= 3000`);
- expect(networkURL.hostname).to.be.equal(hostname ?? '127.0.0.1', `Expected Network URL to use passed hostname`);
+ const localURL = new URL(local);
+ expect(localURL.hostname).to.be.equal(flagValue, `Expected local URL to be on localhost`);
+ });
});
});
diff --git a/packages/astro/test/config.test.js b/packages/astro/test/config.test.js
index c8a491e11..84193694a 100644
--- a/packages/astro/test/config.test.js
+++ b/packages/astro/test/config.test.js
@@ -1,15 +1,22 @@
import { expect } from 'chai';
-import { cli, loadFixture } from './test-utils.js';
+import { cli, loadFixture, cliServerLogSetup } from './test-utils.js';
import { fileURLToPath } from 'url';
+import { isIPv4 } from 'net';
describe('config', () => {
let hostnameFixture;
+ let hostFixture;
let portFixture;
before(async () => {
- [hostnameFixture, portFixture] = await Promise.all([loadFixture({ projectRoot: './fixtures/config-hostname/' }), loadFixture({ projectRoot: './fixtures/config-port/' })]);
+ [hostnameFixture, hostFixture, portFixture] = await Promise.all([
+ loadFixture({ projectRoot: './fixtures/config-hostname/' }),
+ loadFixture({ projectRoot: './fixtures/config-host/' }),
+ loadFixture({ projectRoot: './fixtures/config-port/' }),
+ ]);
});
+ // TODO: remove test once --hostname is baselined
describe('hostname', () => {
it('can be specified in astro.config.mjs', async () => {
expect(hostnameFixture.config.devOptions.hostname).to.equal('0.0.0.0');
@@ -17,19 +24,24 @@ describe('config', () => {
it('can be specified via --hostname flag', async () => {
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
- const proc = cli('dev', '--project-root', fileURLToPath(projectRootURL), '--hostname', '127.0.0.1');
+ const { network } = await cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), '--hostname', '0.0.0.0']);
- let stdout = '';
-
- for await (const chunk of proc.stdout) {
- stdout += chunk;
+ const networkURL = new URL(network);
+ expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --hostname flag`);
+ });
+ });
- if (chunk.includes('Local')) break;
- }
+ describe('host', () => {
+ it('can be specified in astro.config.mjs', async () => {
+ expect(hostFixture.config.devOptions.host).to.equal(true);
+ });
- proc.kill();
+ it('can be specified via --host flag', async () => {
+ const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
+ const { network } = await cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), '--host']);
- expect(stdout).to.include('127.0.0.1');
+ const networkURL = new URL(network);
+ expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --hostname flag`);
});
});
@@ -37,19 +49,10 @@ describe('config', () => {
it('can be passed via --config', async () => {
const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url);
const configFileURL = new URL('./fixtures/config-path/config/my-config.mjs', import.meta.url);
- const proc = cli('dev', '--project-root', fileURLToPath(projectRootURL), '--config', configFileURL.pathname);
-
- let stdout = '';
-
- for await (const chunk of proc.stdout) {
- stdout += chunk;
-
- if (chunk.includes('Local')) break;
- }
-
- proc.kill();
+ const { network } = await cliServerLogSetup(['--project-root', fileURLToPath(projectRootURL), '--config', configFileURL.pathname]);
- expect(stdout).to.include('127.0.0.1');
+ const networkURL = new URL(network);
+ expect(isIPv4(networkURL.hostname)).to.be.equal(true, `Expected network URL to respect --hostname flag`);
});
});
diff --git a/packages/astro/test/fixtures/config-host/astro.config.mjs b/packages/astro/test/fixtures/config-host/astro.config.mjs
new file mode 100644
index 000000000..5dceb4a1f
--- /dev/null
+++ b/packages/astro/test/fixtures/config-host/astro.config.mjs
@@ -0,0 +1,6 @@
+
+export default {
+ devOptions: {
+ host: true
+ }
+}
diff --git a/packages/astro/test/fixtures/config-host/package.json b/packages/astro/test/fixtures/config-host/package.json
new file mode 100644
index 000000000..8ddfe530a
--- /dev/null
+++ b/packages/astro/test/fixtures/config-host/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@astrojs/test-config-host",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/astro/test/fixtures/config-path/config/my-config.mjs b/packages/astro/test/fixtures/config-path/config/my-config.mjs
index e873034e1..c9d45e6c8 100644
--- a/packages/astro/test/fixtures/config-path/config/my-config.mjs
+++ b/packages/astro/test/fixtures/config-path/config/my-config.mjs
@@ -1,6 +1,6 @@
export default {
devOptions: {
- hostname: '127.0.0.1',
+ host: true,
port: 8080,
},
}
diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js
index 69fabacda..340653325 100644
--- a/packages/astro/test/test-utils.js
+++ b/packages/astro/test/test-utils.js
@@ -143,4 +143,18 @@ export async function parseCliDevStart(proc) {
return { messages };
}
+export async function cliServerLogSetup(flags = [], cmd = 'dev') {
+ const proc = cli(cmd, ...flags);
+
+ const { messages } = await parseCliDevStart(proc);
+
+ const localRaw = (messages[1] ?? '').includes('Local') ? messages[1] : undefined;
+ const networkRaw = (messages[2] ?? '').includes('Network') ? messages[2] : undefined;
+
+ const local = localRaw?.replace(/Local\s*/g, '');
+ const network = networkRaw?.replace(/Network\s*/g, '');
+
+ return { local, network };
+}
+
export const isWindows = os.platform() === 'win32';
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 628231b58..c23db5ee6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -754,6 +754,12 @@ importers:
dependencies:
astro: link:../../..
+ packages/astro/test/fixtures/config-host:
+ specifiers:
+ astro: workspace:*
+ dependencies:
+ astro: link:../../..
+
packages/astro/test/fixtures/config-hostname:
specifiers:
astro: workspace:*