diff --git a/src/cli/__tests__/index.test.ts b/src/cli/__tests__/index.test.ts index 458b5fa5f..14a1a3c09 100644 --- a/src/cli/__tests__/index.test.ts +++ b/src/cli/__tests__/index.test.ts @@ -116,6 +116,20 @@ describe('CLI', () => { }); }); + it('should respect passing --port', async () => { + const expectedPort = 3100; + mockArgv('--port', String(expectedPort)); + await importCli(); + + expect(createServerMock).toBeCalledWith({ + dev: { + server: { + port: expectedPort, + }, + }, + }); + }); + it('should respect passing --debug', async () => { mockArgv('--debug'); await importCli(); diff --git a/src/cli/commands.ts b/src/cli/commands.ts index d087c3601..c17a39d05 100644 --- a/src/cli/commands.ts +++ b/src/cli/commands.ts @@ -16,6 +16,7 @@ cli .option('-c, --config ', 'use specified config file') .option('-m, --mode ', 'set env mode') .option('-b, --browser ', 'specify a browser') + .option('-p, --port ', 'specify a port for the dev server') .option( '-e, --filter-entrypoint ', 'only build specific entrypoints', @@ -35,6 +36,14 @@ cli configFile: flags.config, debug: flags.debug, filterEntrypoints: getArrayFromFlags(flags, 'filterEntrypoint'), + dev: + flags.port == null + ? undefined + : { + server: { + port: parseInt(flags.port), + }, + }, }); await server.start(); return { isOngoing: true }; diff --git a/src/core/create-server.ts b/src/core/create-server.ts index 6e5c1c085..54419e8b9 100644 --- a/src/core/create-server.ts +++ b/src/core/create-server.ts @@ -40,9 +40,8 @@ import { mapWxtOptionsToRegisteredContentScript } from './utils/content-scripts' export async function createServer( inlineConfig?: InlineConfig, ): Promise { - await registerWxt('serve', inlineConfig, async (_config) => { - const port = await getPort(); - const hostname = 'localhost'; + await registerWxt('serve', inlineConfig, async (config) => { + const { port, hostname } = config.dev.server!; const serverInfo: ServerInfo = { port, hostname, @@ -138,11 +137,6 @@ export async function createServer( return server; } -async function getPort(): Promise { - const { default: getPort, portNumbers } = await import('get-port'); - return await getPort({ port: portNumbers(3000, 3010) }); -} - /** * Returns a function responsible for reloading different parts of the extension when a file * changes. diff --git a/src/core/utils/building/resolve-config.ts b/src/core/utils/building/resolve-config.ts index b62917838..e692ef687 100644 --- a/src/core/utils/building/resolve-config.ts +++ b/src/core/utils/building/resolve-config.ts @@ -110,6 +110,19 @@ export async function resolveConfig( }).map(([key, value]) => [key, path.resolve(root, value)]), ); + let devServerConfig: ResolvedConfig['dev']['server']; + if (command === 'serve') { + let port = mergedConfig.dev?.server?.port; + if (port == null || !isFinite(port)) { + const { default: getPort, portNumbers } = await import('get-port'); + port = await getPort({ port: portNumbers(3000, 3010) }); + } + devServerConfig = { + port, + hostname: 'localhost', + }; + } + return { browser, command, @@ -141,6 +154,7 @@ export async function resolveConfig( includeBrowserPolyfill: true, }), dev: { + server: devServerConfig, reloadCommand, }, hooks: mergedConfig.hooks ?? {}, diff --git a/src/types/index.ts b/src/types/index.ts index 0eead0d6a..23a49b940 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -309,6 +309,12 @@ export interface InlineConfig { * Config effecting dev mode only. */ dev?: { + server?: { + /** + * Port to run the dev server on. Defaults to the first open port from 3000 to 3010. + */ + port?: number; + }; /** * Controls whether a custom keyboard shortcut command, `Alt+R`, is added during dev mode to * quickly reload the extension. @@ -1077,6 +1083,11 @@ export interface ResolvedConfig { includeBrowserPolyfill: boolean; }; dev: { + /** Only defined during dev command */ + server?: { + port: number; + hostname: string; + }; reloadCommand: string | false; }; hooks: NestedHooks;