diff --git a/packages/web/package.json b/packages/web/package.json index 1a3085746c1d3d..de0a32e3029af1 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -32,6 +32,7 @@ "dependencies": { "chalk": "^4.1.0", "chokidar": "^3.5.1", + "detect-port": "^1.5.1", "http-server": "^14.1.0", "ignore": "^5.0.4", "tslib": "^2.3.0", diff --git a/packages/web/src/executors/file-server/file-server.impl.ts b/packages/web/src/executors/file-server/file-server.impl.ts index b998060c392d93..50280a4d034890 100644 --- a/packages/web/src/executors/file-server/file-server.impl.ts +++ b/packages/web/src/executors/file-server/file-server.impl.ts @@ -14,6 +14,7 @@ import { watch } from 'chokidar'; import { platform } from 'os'; import { join, resolve } from 'path'; import { readModulePackageJson } from 'nx/src/utils/package-json'; +import * as detectPort from 'detect-port'; // platform specific command name const pmCmd = platform() === 'win32' ? `npx.cmd` : 'npx'; @@ -24,10 +25,6 @@ function getHttpServerArgs(options: Schema) { if (options.cors) { args.push(`--cors`); } - - if (options.port) { - args.push(`-p=${options.port}`); - } if (options.host) { args.push(`-a=${options.host}`); } @@ -182,6 +179,10 @@ export default async function* fileServerExecutor( pathToHttpServerBin ); + // detect port as close to when used to prevent port being used by another process + // when running in parallel + const port = await detectPort(options.port || 8080); + args.push(`-p=${port}`); const serve = fork(pathToHttpServer, [outputPath, ...args], { stdio: 'pipe', cwd: context.root, @@ -203,7 +204,34 @@ export default async function* fileServerExecutor( }; process.on('exit', processExitListener); process.on('SIGTERM', processExitListener); + + // TODO(caleb): should this be in devkit? + function stripConsoleColors(log: string): string { + return log?.replace( + /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, + '' + ); + } + serve.stdout.on('data', (chunk) => { + // const str = chunk.toString(); + // // need to strip colors other wise the port includes color codes + // // which cause cypress to throw reading the url; + // const lines = stripConsoleColors(str).split('\n'); + // // Available on: + // // http://localhost:8081 + // // Hit CTRL-C to stop the server + // const line = lines?.find((l) => l.includes(options.host))?.trim(); + // if (line) { + // const u = new URL(line); + + // if (u.port) { + // res(u.port); + // } else { + // rej('Could not find port'); + // } + // } + if (chunk.toString().indexOf('GET') === -1) { process.stdout.write(chunk); } @@ -215,7 +243,7 @@ export default async function* fileServerExecutor( yield { success: true, baseUrl: `${options.ssl ? 'https' : 'http'}://${options.host}:${ - options.port + port || options.port }`, };