diff --git a/.github/workflows/cli-win.yml b/.github/workflows/cli-win.yml index 52ec1b8b27..00c7c26a6c 100644 --- a/.github/workflows/cli-win.yml +++ b/.github/workflows/cli-win.yml @@ -61,5 +61,5 @@ jobs: run: yarn test:e2e:ci working-directory: ${{ runner.temp }}/test-app/packages/app env: - PORT: 3001 + APP_CONFIG_app_baseUrl: '"http://localhost:3001"' BACKSTAGE_E2E_CLI_TEST: true diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 62f91e3259..71b207c0d3 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -64,5 +64,5 @@ jobs: run: yarn test:e2e:ci working-directory: ${{ runner.temp }}/test-app/packages/app env: - PORT: 3001 + APP_CONFIG_app_baseUrl: '"http://localhost:3001"' BACKSTAGE_E2E_CLI_TEST: true diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index ad1a63ebaf..1193ed505e 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -23,7 +23,7 @@ import { printFileSizesAfterBuild, } from 'react-dev-utils/FileSizeReporter'; import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages'; -import { createConfig } from './config'; +import { createConfig, resolveBaseUrl } from './config'; import { BuildOptions } from './types'; import { resolveBundlingPaths } from './paths'; import chalk from 'chalk'; @@ -40,6 +40,7 @@ export async function buildBundle(options: BuildOptions) { ...options, checksEnabled: false, isDev: false, + baseUrl: resolveBaseUrl(options.config), }); const compiler = webpack(config); diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index d46308f043..ba99c49c62 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -18,6 +18,7 @@ import webpack from 'webpack'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; +import { Config } from '@backstage/config'; import { BundlingPaths } from './paths'; import { transforms } from './transforms'; import { optimization } from './optimization'; @@ -28,6 +29,18 @@ import { BundlingOptions } from './types'; // import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware'; // import WatchMissingNodeModulesPlugin from 'react-dev-utils/WatchMissingNodeModulesPlugin'; +export function resolveBaseUrl(config: Config): URL { + const baseUrl = config.getString('app.baseUrl'); + if (!baseUrl) { + throw new Error('app.baseUrl must be set in config'); + } + try { + return new URL(baseUrl, 'http://localhost:3000'); + } catch (error) { + throw new Error(`Invalid app.baseUrl, ${error}`); + } +} + export function createConfig( paths: BundlingPaths, options: BundlingOptions, diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index bf78c9b9fb..64fe823c2d 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -15,30 +15,22 @@ */ import fs from 'fs-extra'; -import yn from 'yn'; import webpack from 'webpack'; import WebpackDevServer from 'webpack-dev-server'; import openBrowser from 'react-dev-utils/openBrowser'; -import { choosePort, prepareUrls } from 'react-dev-utils/WebpackDevServerUtils'; -import { createConfig } from './config'; +import { createConfig, resolveBaseUrl } from './config'; import { ServeOptions } from './types'; import { resolveBundlingPaths } from './paths'; export async function serveBundle(options: ServeOptions) { - const host = process.env.HOST ?? '0.0.0.0'; - const defaultPort = parseInt(process.env.PORT ?? '', 10) || 3000; + const url = resolveBaseUrl(options.config); - const port = await choosePort(host, defaultPort); - if (!port) { - throw new Error(`Invalid or no port set: '${port}'`); - } - - const protocol = yn(process.env.HTTPS, { default: false }) ? 'https' : 'http'; + const port = Number(url.port) || (url.protocol === 'https:' ? 443 : 80); const paths = resolveBundlingPaths(options); const pkgPath = paths.targetPackageJson; const pkg = await fs.readJson(pkgPath); - const config = createConfig(paths, { ...options, isDev: true }); + const config = createConfig(paths, { ...options, isDev: true, baseUrl: url }); const compiler = webpack(config); const server = new WebpackDevServer(compiler, { @@ -49,33 +41,20 @@ export async function serveBundle(options: ServeOptions) { historyApiFallback: true, clientLogLevel: 'warning', stats: 'errors-warnings', - https: protocol === 'https', - host, + https: url.protocol === 'https:', + host: url.hostname, port, proxy: pkg.proxy, }); await new Promise((resolve, reject) => { - server.listen(port, host, (err?: Error) => { + server.listen(port, url.hostname, (err?: Error) => { if (err) { reject(err); return; } - // TODO: This signature is available in 10.2.1 but doesn't have types published yet - const latestPrepareUrls = prepareUrls as ( - protocol: string, - host: string, - port: number, - path?: string, - ) => ReturnType; - const urls = latestPrepareUrls( - protocol, - host, - port, - config.output?.publicPath, - ); - openBrowser(urls.localUrlForBrowser); + openBrowser(url.href); resolve(); }); }); diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 332a105182..c1692ca997 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -22,6 +22,7 @@ export type BundlingOptions = { isDev: boolean; config: Config; appConfigs: AppConfig[]; + baseUrl: URL; }; export type ServeOptions = BundlingPathsOptions & {