diff --git a/.changeset/violet-tigers-shake.md b/.changeset/violet-tigers-shake.md new file mode 100644 index 000000000000..2116e7a19a8a --- /dev/null +++ b/.changeset/violet-tigers-shake.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Refactor server url logs diff --git a/packages/astro/src/core/dev/index.ts b/packages/astro/src/core/dev/index.ts index 9d4b585803b2..05b59e1a0892 100644 --- a/packages/astro/src/core/dev/index.ts +++ b/packages/astro/src/core/dev/index.ts @@ -60,19 +60,17 @@ export default async function dev( runHookServerSetup({ config: settings.config, server: viteServer, logging: options.logging }); await viteServer.listen(port); - const devServerAddressInfo = viteServer.httpServer!.address() as AddressInfo; const site = settings.config.site ? new URL(settings.config.base, settings.config.site) : undefined; info( options.logging, null, - msg.devStart({ + msg.serverStart({ startupTime: performance.now() - devStart, - config: settings.config, - devServerAddressInfo, + resolvedUrls: viteServer.resolvedUrls || { local: [], network: [] }, + host: settings.config.server.host, site, - https: !!viteConfig.server?.https, isRestart, }) ); @@ -85,6 +83,7 @@ export default async function dev( warn(options.logging, null, msg.fsStrictWarning()); } + const devServerAddressInfo = viteServer.httpServer!.address() as AddressInfo; await runHookServerStart({ config: settings.config, address: devServerAddressInfo, diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index f140e052fb12..a0a53605653b 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -16,9 +16,10 @@ import { } from 'kleur/colors'; import type { AddressInfo } from 'net'; import os from 'os'; +import { ResolvedServerUrls } from 'vite'; import { ZodError } from 'zod'; -import type { AstroConfig } from '../@types/astro'; import { ErrorWithMetadata } from './errors.js'; +import { removeTrailingForwardSlash } from './path.js'; import { emoji, getLocalAddress, padMultilineString } from './util.js'; const PREFIX_PADDING = 6; @@ -51,19 +52,17 @@ export function hmr({ file, style = false }: { file: string; style?: boolean }): return `${green('update'.padStart(PREFIX_PADDING))} ${file}${style ? ` ${dim('style')}` : ''}`; } -/** Display dev server host and startup time */ -export function devStart({ +/** Display server host and startup time */ +export function serverStart({ startupTime, - devServerAddressInfo, - config, - https, + resolvedUrls, + host, site, isRestart = false, }: { startupTime: number; - devServerAddressInfo: AddressInfo; - config: AstroConfig; - https: boolean; + resolvedUrls: ResolvedServerUrls; + host: string | boolean; site: URL | undefined; isRestart?: boolean; }): string { @@ -72,19 +71,61 @@ export function devStart({ const rootPath = site ? site.pathname : '/'; const localPrefix = `${dim('┃')} Local `; const networkPrefix = `${dim('┃')} Network `; + const emptyPrefix = ' '.repeat(11); + + const localUrlMessages = resolvedUrls.local.map((url, i) => { + return `${i === 0 ? localPrefix : emptyPrefix}${bold( + cyan(removeTrailingForwardSlash(url) + rootPath) + )}`; + }); + const networkUrlMessages = resolvedUrls.network.map((url, i) => { + return `${i === 0 ? networkPrefix : emptyPrefix}${bold( + cyan(removeTrailingForwardSlash(url) + rootPath) + )}`; + }); - const { address: networkAddress, port } = devServerAddressInfo; - const localAddress = getLocalAddress(networkAddress, config.server.host); - const networkLogging = getNetworkLogging(config.server.host); - const toDisplayUrl = (hostname: string) => - `${https ? 'https' : 'http'}://${hostname}:${port}${rootPath}`; + if (networkUrlMessages.length === 0) { + const networkLogging = getNetworkLogging(host); + if (networkLogging === 'host-to-expose') { + networkUrlMessages.push(`${networkPrefix}${dim('use --host to expose')}`); + } else if (networkLogging === 'visible') { + networkUrlMessages.push(`${networkPrefix}${dim('unable to find network to expose')}`); + } + } - let local = `${localPrefix}${bold(cyan(toDisplayUrl(localAddress)))}`; - let network = null; + const messages = [ + `${emoji('🚀 ', '')}${bgGreen(black(` astro `))} ${green(`v${version}`)} ${dim( + `${isRestart ? 're' : ''}started in ${Math.round(startupTime)}ms` + )}`, + '', + ...localUrlMessages, + ...networkUrlMessages, + '', + ]; + return messages + .filter((msg) => typeof msg === 'string') + .map((msg) => ` ${msg}`) + .join('\n'); +} - if (networkLogging === 'host-to-expose') { - network = `${networkPrefix}${dim('use --host to expose')}`; - } else if (networkLogging === 'visible') { +export function resolveServerUrls({ + address, + host, + https, +}: { + address: AddressInfo; + host: string | boolean; + https: boolean; +}): ResolvedServerUrls { + const { address: networkAddress, port } = address; + const localAddress = getLocalAddress(networkAddress, host); + const networkLogging = getNetworkLogging(host); + const toDisplayUrl = (hostname: string) => `${https ? 'https' : 'http'}://${hostname}:${port}`; + + let local = toDisplayUrl(localAddress); + let network: string | null = null; + + if (networkLogging === 'visible') { const nodeVersion = Number(process.version.substring(1, process.version.indexOf('.', 5))); const ipv4Networks = Object.values(os.networkInterfaces()) .flatMap((networkInterface) => networkInterface ?? []) @@ -96,29 +137,17 @@ export function devStart({ for (let { address } of ipv4Networks) { if (address.includes('127.0.0.1')) { const displayAddress = address.replace('127.0.0.1', localAddress); - local = `${localPrefix}${bold(cyan(toDisplayUrl(displayAddress)))}`; + local = toDisplayUrl(displayAddress); } else { - network = `${networkPrefix}${bold(cyan(toDisplayUrl(address)))}`; + network = toDisplayUrl(address); } } - if (!network) { - network = `${networkPrefix}${dim('unable to find network to expose')}`; - } } - const messages = [ - `${emoji('🚀 ', '')}${bgGreen(black(` astro `))} ${green(`v${version}`)} ${dim( - `${isRestart ? 're' : ''}started in ${Math.round(startupTime)}ms` - )}`, - '', - local, - network, - '', - ]; - return messages - .filter((msg) => typeof msg === 'string') - .map((msg) => ` ${msg}`) - .join('\n'); + return { + local: [local], + network: network ? [network] : [], + }; } export function telemetryNotice() { diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index 1d81df989f0d..379d44e6f75d 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -113,15 +113,18 @@ export default async function preview( const listen = () => { httpServer = server.listen(port, host, async () => { if (!showedListenMsg) { - const devServerAddressInfo = server.address() as AddressInfo; + const resolvedUrls = msg.resolveServerUrls({ + address: server.address() as AddressInfo, + host: settings.config.server.host, + https: false, + }); info( logging, null, - msg.devStart({ + msg.serverStart({ startupTime: performance.now() - timerStart, - config: settings.config, - devServerAddressInfo, - https: false, + resolvedUrls, + host: settings.config.server.host, site: baseURL, }) ); diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js index 50364bd57193..553292f6df43 100644 --- a/packages/astro/test/cli.test.js +++ b/packages/astro/test/cli.test.js @@ -83,10 +83,17 @@ describe('astro cli', () => { 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` - ); + if (cmd === 'dev') { + expect(localURL.hostname).to.be.oneOf( + ['localhost', '127.0.0.1'], + `Expected local URL to be on localhost` + ); + } else { + 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, @@ -112,7 +119,17 @@ describe('astro cli', () => { 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`); + if (cmd === 'dev') { + expect(localURL.hostname).to.be.oneOf( + ['localhost', '127.0.0.1'], + `Expected local URL to be on localhost` + ); + } else { + expect(localURL.hostname).to.be.equal( + 'localhost', + `Expected local URL to be on localhost` + ); + } expect(() => new URL(networkURL)).to.throw(); }); }); @@ -129,7 +146,14 @@ describe('astro cli', () => { expect(network).to.be.undefined; const localURL = new URL(local); - expect(localURL.hostname).to.be.equal(flagValue, `Expected local URL to be on localhost`); + if (cmd === 'dev') { + expect(localURL.hostname).to.be.oneOf( + ['localhost', '127.0.0.1'], + `Expected local URL to be on localhost` + ); + } else { + expect(localURL.hostname).to.be.equal(flagValue, `Expected local URL to be on localhost`); + } }); }); });