From 2619f43474cb2825c357cf425e31da0816878c2c Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Thu, 8 Feb 2024 11:13:22 +0100 Subject: [PATCH] Fixed issue with blocked port #671 --- CHANGELOG.md | 1 + src/tooling/piral-cli-webpack5/src/actions.ts | 2 +- .../piral-cli-webpack5/src/webpack/piral.ts | 9 ++++- src/tooling/piral-cli/src/apps/debug-pilet.ts | 13 ++++++-- src/tooling/piral-cli/src/apps/debug-piral.ts | 8 +++-- .../piral-cli/src/build/bundler-calls.ts | 5 ++- src/tooling/piral-cli/src/platforms/web.ts | 33 ++++++++++++++----- src/tooling/piral-cli/src/types/common.ts | 13 +++++--- 8 files changed, 64 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 927180ca8..9e5f8f095 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fixed error when importing `once` without context (#664) - Fixed issue with monorepos using Rush (#667) +- Fixed issue with blocked port in case of full debug reload (#671) - Removed legacy option in `piral-cli-webpack5` to support IE8 - Removed pilet-related options in debug settings when running `piral debug` (#670) - Improved internal navigation Blazor pilets using `piral-blazor` diff --git a/src/tooling/piral-cli-webpack5/src/actions.ts b/src/tooling/piral-cli-webpack5/src/actions.ts index 2af12848c..1e3583d1a 100644 --- a/src/tooling/piral-cli-webpack5/src/actions.ts +++ b/src/tooling/piral-cli-webpack5/src/actions.ts @@ -20,7 +20,7 @@ export const debugPiral: DebugPiralBundlerDefinition = { .default('config', defaultWebpackConfig) .number('hmr-port') .describe('hmr-port', 'Sets the port to be used for HMR for reloading the application.') - .default('hmr-port', 62123); + .default('hmr-port', undefined); }, path: resolve(__dirname, 'webpack', 'piral.js'), }; diff --git a/src/tooling/piral-cli-webpack5/src/webpack/piral.ts b/src/tooling/piral-cli-webpack5/src/webpack/piral.ts index f3af3e114..f5040fb65 100644 --- a/src/tooling/piral-cli-webpack5/src/webpack/piral.ts +++ b/src/tooling/piral-cli-webpack5/src/webpack/piral.ts @@ -83,9 +83,16 @@ async function getConfig( ]; } +function getRandomPort() { + const min = 60000; + const max = 65536; + const rng = max - min; + return ~~(Math.random() * rng) + min; +} + const handler: PiralBuildHandler = { async create(options) { - const { 'hmr-port': defaultHmrPort = 62123, config = defaultWebpackConfig } = options.args._; + const { 'hmr-port': defaultHmrPort = getRandomPort(), config = defaultWebpackConfig } = options.args._; const hmrPort = options.hmr ? await getFreePort(defaultHmrPort) : 0; const otherConfigPath = resolve(options.root, config); const baseConfig = await getConfig( diff --git a/src/tooling/piral-cli/src/apps/debug-pilet.ts b/src/tooling/piral-cli/src/apps/debug-pilet.ts index 39a6a0d4f..78f9775d4 100644 --- a/src/tooling/piral-cli/src/apps/debug-pilet.ts +++ b/src/tooling/piral-cli/src/apps/debug-pilet.ts @@ -1,6 +1,6 @@ import { join, dirname, resolve, relative, basename } from 'path'; import { callDebugPiralFromMonoRepo, callPiletDebug } from '../bundler'; -import { AppDefinition, LogLevels, PiletSchemaVersion } from '../types'; +import { AppDefinition, LogLevels, NetworkSpec, PiletSchemaVersion } from '../types'; import { checkExistingDirectory, retrievePiletData, @@ -230,6 +230,7 @@ export async function debugPilet(baseDir = process.cwd(), options: DebugPiletOpt } = options; const publicUrl = normalizePublicUrl(originalPublicUrl); const fullBase = resolve(process.cwd(), baseDir); + const networks: Array = []; setLogLevel(logLevel); await hooks.onBegin?.({ options, fullBase }); @@ -341,7 +342,13 @@ export async function debugPilet(baseDir = process.cwd(), options: DebugPiletOpt await Promise.all( appInstances.sort(byPort).map(async ([appDir, appPort], i) => { const platform = configurePlatform(); - const suggestedPort = appPort || originalPort + i; + + if (networks.length === i) { + networks.push({ + port: appPort || originalPort + i, + type: 'proposed', + }); + } await platform.startModule({ appDir, @@ -351,7 +358,7 @@ export async function debugPilet(baseDir = process.cwd(), options: DebugPiletOpt fullBase, hooks, open, - originalPort: suggestedPort, + network: networks[i], publicUrl, maxListeners, registerEnd(cb) { diff --git a/src/tooling/piral-cli/src/apps/debug-piral.ts b/src/tooling/piral-cli/src/apps/debug-piral.ts index b412fcad4..445d832bf 100644 --- a/src/tooling/piral-cli/src/apps/debug-piral.ts +++ b/src/tooling/piral-cli/src/apps/debug-piral.ts @@ -1,6 +1,6 @@ import { dirname, join, resolve } from 'path'; import { callPiralDebug } from '../bundler'; -import { LogLevels } from '../types'; +import { LogLevels, NetworkSpec } from '../types'; import { retrievePiletsInfo, retrievePiralRoot, @@ -124,6 +124,10 @@ export async function debugPiral(baseDir = process.cwd(), options: DebugPiralOpt } = options; const publicUrl = normalizePublicUrl(originalPublicUrl); const fullBase = resolve(process.cwd(), baseDir); + const network: NetworkSpec = { + port: originalPort, + type: 'proposed', + }; setLogLevel(logLevel); await hooks.onBegin?.({ options, fullBase }); @@ -187,7 +191,7 @@ export async function debugPiral(baseDir = process.cwd(), options: DebugPiralOpt fullBase, hooks, open, - originalPort, + network, publicUrl, root, targetDir, diff --git a/src/tooling/piral-cli/src/build/bundler-calls.ts b/src/tooling/piral-cli/src/build/bundler-calls.ts index 759a691d9..a38eb297b 100644 --- a/src/tooling/piral-cli/src/build/bundler-calls.ts +++ b/src/tooling/piral-cli/src/build/bundler-calls.ts @@ -38,7 +38,10 @@ function createBundler(cwd: string, ps: ChildProcess, args: any) { } }, stop() { - ps.kill(); + return new Promise(resolve => { + ps.on('exit', resolve); + ps.kill(); + }); }, on(cb: BundleListener) { listeners.push(cb); diff --git a/src/tooling/piral-cli/src/platforms/web.ts b/src/tooling/piral-cli/src/platforms/web.ts index 2d7be8fad..281219a21 100644 --- a/src/tooling/piral-cli/src/platforms/web.ts +++ b/src/tooling/piral-cli/src/platforms/web.ts @@ -6,7 +6,16 @@ import { config } from '../common/config'; import { openBrowser } from '../common/browser'; import { checkExistingDirectory, findFile } from '../common/io'; import { getAvailablePort } from '../common/port'; -import { PlatformStartShellOptions, PlatformStartModuleOptions } from '../types'; +import { PlatformStartShellOptions, PlatformStartModuleOptions, NetworkSpec } from '../types'; + +async function getPort(network: NetworkSpec) { + if (network.type === 'proposed') { + network.port = await getAvailablePort(network.port); + network.type = 'fixed'; + } + + return network.port; +} async function startModule(options: PlatformStartModuleOptions) { const { @@ -16,7 +25,7 @@ async function startModule(options: PlatformStartModuleOptions) { feed, publicUrl, customkrasrc, - originalPort, + network, hooks, registerWatcher, registerEnd, @@ -60,7 +69,8 @@ async function startModule(options: PlatformStartModuleOptions) { configs.forEach(registerWatcher); - const port = await getAvailablePort(originalPort); + const shouldNotify = network.type === 'proposed'; + const port = await getPort(network); const krasConfig = readKrasConfig({ port, initial, required }, ...configs); log('generalVerbose_0004', `Using kras with configuration: ${JSON.stringify(krasConfig, undefined, 2)}`); @@ -68,7 +78,10 @@ async function startModule(options: PlatformStartModuleOptions) { const krasServer = buildKrasWithCli(krasConfig); krasServer.setMaxListeners(maxListeners); krasServer.removeAllListeners('open'); - krasServer.on('open', notifyServerOnline(publicUrl, krasConfig.api)); + + if (shouldNotify) { + krasServer.on('open', notifyServerOnline(publicUrl, krasConfig.api)); + } await hooks.beforeOnline?.({ krasServer, krasConfig, open, port, api, feed, pilets, publicUrl }); await krasServer.start(); @@ -88,7 +101,7 @@ async function startShell(options: PlatformStartShellOptions) { publicUrl, bundler, customkrasrc, - originalPort, + network, hooks, registerWatcher, registerEnd, @@ -123,21 +136,25 @@ async function startShell(options: PlatformStartShellOptions) { configs.forEach(registerWatcher); - const port = await getAvailablePort(originalPort); + const shouldNotify = network.type === 'proposed'; + const port = await getPort(network); const krasConfig = readKrasConfig({ port, initial, required }, ...configs); log('generalVerbose_0004', `Using kras with configuration: ${JSON.stringify(krasConfig, undefined, 2)}`); const krasServer = buildKrasWithCli(krasConfig); krasServer.setMaxListeners(16); krasServer.removeAllListeners('open'); - krasServer.on('open', notifyServerOnline(publicUrl, krasConfig.api)); + + if (shouldNotify) { + krasServer.on('open', notifyServerOnline(publicUrl, krasConfig.api)); + } await hooks.beforeOnline?.({ krasServer, krasConfig, open, port, publicUrl }); await krasServer.start(); openBrowser(open, port, publicUrl, !!krasConfig.ssl); await hooks.afterOnline?.({ krasServer, krasConfig, open, port, publicUrl }); - registerEnd(() => krasServer.stop()); + registerEnd(async () => krasServer.stop()); } export function setup() { diff --git a/src/tooling/piral-cli/src/types/common.ts b/src/tooling/piral-cli/src/types/common.ts index 9edd3c3b0..d0ff724f8 100644 --- a/src/tooling/piral-cli/src/types/common.ts +++ b/src/tooling/piral-cli/src/types/common.ts @@ -112,12 +112,17 @@ export interface BundleDetails { export interface Bundler { readonly bundle: BundleDetails; start(): void; - stop(): void; + stop(): Promise; on(cb: (args: any) => void): void; off(cb: (args: any) => void): void; ready(): Promise; } +export interface NetworkSpec { + port: number; + type: 'proposed' | 'fixed'; +} + export interface PlatformStartModuleOptions { appDir?: string; open: boolean; @@ -125,7 +130,7 @@ export interface PlatformStartModuleOptions { feed: string | Array; publicUrl: string; customkrasrc: string; - originalPort: number; + network: NetworkSpec; hooks: Record; registerWatcher(file: string): void; registerEnd(cb: () => void): void; @@ -143,10 +148,10 @@ export interface PlatformStartShellOptions { publicUrl: string; bundler: Bundler; customkrasrc: string; - originalPort: number; + network: NetworkSpec; hooks: Record; registerWatcher(file: string): void; - registerEnd(cb: () => void): void; + registerEnd(cb: () => void | Promise): void; } export interface ReleaseProvider {