@backstage/cli-module-build 0.1.3-next.0 → 0.1.4-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @backstage/cli-module-build
2
2
 
3
+ ## 0.1.4-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - a1971ea: Suppress false-positive `@protobufjs/inquire` "Critical dependency" warning in the bundler. Since `protobufjs` 7.5.9, the dynamic require path in inquire is no longer exercised, but webpack/rspack still flags it during static analysis.
8
+ - 8007b58: Updated dependency `embedded-postgres` to `18.3.0-beta.17`.
9
+
10
+ ## 0.1.3
11
+
12
+ ### Patch Changes
13
+
14
+ - ed4ee6f: Fixed config path resolution for the embedded-postgres database client detection to resolve paths relative to the target package directory rather than the workspace root.
15
+ - be7e4eb: The embedded Postgres database used during local development now respects user-provided connection configuration. If you configure `host`, `port`, `user`, or `password` under `backend.database.connection` alongside the `embedded-postgres` database client, those values will be forwarded to the embedded Postgres instance. Only values that you have not configured will be filled in with defaults. This makes it possible to run the embedded database on a specific host and port, for example to connect to it externally with `psql`.
16
+ - 41070b8: Upgraded `@module-federation/enhanced`, `@module-federation/runtime`, and `@module-federation/sdk` from `^0.21.6` to `^2.3.3` to address known vulnerabilities.
17
+ - Updated dependencies
18
+ - @backstage/errors@1.3.1
19
+ - @backstage/cli-node@0.3.2
20
+ - @backstage/module-federation-common@0.1.4
21
+ - @backstage/cli-common@0.2.2
22
+ - @backstage/config@1.3.8
23
+ - @backstage/config-loader@1.10.11
24
+
3
25
  ## 0.1.3-next.0
4
26
 
5
27
  ### Patch Changes
@@ -300,16 +300,26 @@ async function createConfig(paths, options) {
300
300
  }
301
301
  },
302
302
  plugins,
303
- ...options.moduleFederationRemote && {
303
+ ignoreWarnings: [
304
+ // @protobufjs/inquire uses require(moduleName) with a dynamic argument.
305
+ // Since protobufjs >=7.5.9 this code path is never exercised (the
306
+ // bundler-safe optional module lookups backport replaced all call sites),
307
+ // but webpack/rspack still statically analyzes the source and emits a
308
+ // "Critical dependency" warning. Safe to suppress.
309
+ // See https://github.com/protobufjs/protobuf.js/issues/2057
310
+ {
311
+ module: /@protobufjs[\\/]inquire/,
312
+ message: /Critical dependency: the request of a dependency is an expression/
313
+ },
304
314
  // TODO: remove this warning skipping as soon as the corresponding bundler limitation
305
315
  // described in issue https://github.com/web-infra-dev/rspack/issues/13635 is fixed
306
316
  // when PR: https://github.com/web-infra-dev/rspack/pull/13636 is merged.
307
- ignoreWarnings: [
317
+ ...options.moduleFederationRemote ? [
308
318
  {
309
319
  message: /No version specified and unable to automatically determine one\. No version in description file/
310
320
  }
311
- ]
312
- }
321
+ ] : []
322
+ ]
313
323
  };
314
324
  }
315
325
 
@@ -1 +1 @@
1
- {"version":3,"file":"config.cjs.js","sources":["../../../src/lib/bundler/config.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { resolve as resolvePath } from 'node:path';\nimport { BundlingOptions, ModuleFederationRemoteOptions } from './types';\nimport { rspack, Configuration } from '@rspack/core';\n\nimport { BundlingPaths } from './paths';\nimport { Config } from '@backstage/config';\nimport ESLintRspackPlugin from 'eslint-rspack-plugin';\nimport { TsCheckerRspackPlugin } from 'ts-checker-rspack-plugin';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin';\nimport { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';\n\nimport fs from 'fs-extra';\nimport { optimization as optimizationConfig } from './optimization';\nimport pickBy from 'lodash/pickBy';\nimport { findOwnPaths, runOutput, targetPaths } from '@backstage/cli-common';\n\nimport { transforms } from './transforms';\nimport { version } from '../../../package.json';\nimport yn from 'yn';\nimport { hasReactDomClient } from './hasReactDomClient';\nimport { createWorkspaceLinkingPlugins } from './linkWorkspaces';\nimport { ConfigInjectingHtmlWebpackPlugin } from './ConfigInjectingHtmlWebpackPlugin';\n\nexport function resolveBaseUrl(\n config: Config,\n moduleFederationRemote?: ModuleFederationRemoteOptions,\n): URL {\n const baseUrl = config.getOptionalString('app.baseUrl');\n\n const defaultBaseUrl = moduleFederationRemote\n ? `http://localhost:${process.env.PORT ?? '3000'}`\n : 'http://localhost:3000';\n\n try {\n return new URL(baseUrl ?? '/', defaultBaseUrl);\n } catch (error) {\n throw new Error(`Invalid app.baseUrl, ${error}`);\n }\n}\n\nexport function resolveEndpoint(\n config: Config,\n moduleFederationRemote?: ModuleFederationRemoteOptions,\n): {\n host: string;\n port: number;\n} {\n const url = resolveBaseUrl(config, moduleFederationRemote);\n\n return {\n host: config.getOptionalString('app.listen.host') ?? url.hostname,\n port:\n config.getOptionalNumber('app.listen.port') ??\n Number(url.port) ??\n (url.protocol === 'https:' ? 443 : 80),\n };\n}\n\nasync function readBuildInfo() {\n const timestamp = Date.now();\n\n let commit: string | undefined;\n try {\n commit = await runOutput(['git', 'rev-parse', 'HEAD']);\n } catch (error) {\n // ignore, see below\n }\n\n let gitVersion: string | undefined;\n try {\n gitVersion = await runOutput(['git', 'describe', '--always']);\n } catch (error) {\n // ignore, see below\n }\n\n if (commit === undefined || gitVersion === undefined) {\n console.info(\n 'NOTE: Did not compute git version or commit hash, could not execute the git command line utility',\n );\n }\n\n const { version: packageVersion } = await fs.readJson(\n targetPaths.resolve('package.json'),\n );\n\n return {\n cliVersion: version,\n gitVersion: gitVersion ?? 'unknown',\n packageVersion,\n timestamp,\n commit: commit ?? 'unknown',\n };\n}\n\nexport async function createConfig(\n paths: BundlingPaths,\n options: BundlingOptions,\n): Promise<Configuration> {\n const {\n checksEnabled,\n isDev,\n frontendConfig,\n moduleFederationRemote,\n publicSubPath = '',\n webpack,\n } = options;\n\n const { plugins, loaders } = transforms(options);\n // Any package that is part of the monorepo but outside the monorepo root dir need\n // separate resolution logic.\n\n const validBaseUrl = resolveBaseUrl(frontendConfig, moduleFederationRemote);\n let publicPath = validBaseUrl.pathname.replace(/\\/$/, '');\n if (publicSubPath) {\n publicPath = `${publicPath}${publicSubPath}`.replace('//', '/');\n }\n\n if (isDev) {\n const { host, port } = resolveEndpoint(\n options.frontendConfig,\n options.moduleFederationRemote,\n );\n\n const refreshOptions = {\n overlay: {\n sockProtocol: 'ws',\n sockHost: host,\n sockPort: port,\n },\n } as const;\n\n if (webpack) {\n const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\n plugins.push(new ReactRefreshPlugin(refreshOptions));\n } else {\n const RspackReactRefreshPlugin = require('@rspack/plugin-react-refresh');\n plugins.push(new RspackReactRefreshPlugin(refreshOptions));\n }\n }\n\n if (checksEnabled) {\n const TsCheckerPlugin = webpack\n ? (require('fork-ts-checker-webpack-plugin') as typeof import('fork-ts-checker-webpack-plugin'))\n : TsCheckerRspackPlugin;\n const ESLintPlugin = webpack\n ? (require('eslint-webpack-plugin') as typeof import('eslint-webpack-plugin'))\n : ESLintRspackPlugin;\n plugins.push(\n new TsCheckerPlugin({\n typescript: { configFile: paths.targetTsConfig, memoryLimit: 8192 },\n }),\n new ESLintPlugin({\n cache: false, // Cache seems broken\n context: paths.targetPath,\n files: ['**/*.(ts|tsx|mts|cts|js|jsx|mjs|cjs)'],\n }),\n );\n }\n\n const bundler = webpack ? (webpack as unknown as typeof rspack) : rspack;\n\n // TODO(blam): process is no longer auto polyfilled by webpack in v5.\n // we use the provide plugin to provide this polyfill, but lets look\n // to remove this eventually!\n plugins.push(\n new bundler.ProvidePlugin({\n process: require.resolve('process/browser'),\n Buffer: ['buffer', 'Buffer'],\n }),\n );\n\n if (!options.moduleFederationRemote) {\n const templateOptions = {\n meta: {\n 'backstage-app-mode': options?.appMode ?? 'public',\n },\n template: paths.targetHtml,\n templateParameters: {\n publicPath,\n config: frontendConfig,\n },\n };\n if (webpack) {\n // Config injection via index.html doesn't work across reloads with\n // WebPack, so we rely on the APP_CONFIG injection instead\n plugins.push(new HtmlWebpackPlugin(templateOptions));\n } else {\n // With Rspack we inject config via index.html, this is both because we\n // can't use APP_CONFIG due to the lack of support for runtime values, but\n // also because we are able to do it and it lines up better with what the\n // app-backend is doing.\n //\n // We still use the html plugin from WebPack, since the Rspack one won't\n // let us inject complex objects like the config.\n plugins.push(\n new ConfigInjectingHtmlWebpackPlugin(\n templateOptions,\n options.getFrontendAppConfigs,\n ),\n );\n }\n plugins.push(\n new HtmlWebpackPlugin({\n meta: {\n 'backstage-app-mode': options?.appMode ?? 'public',\n // This is added to be written in the later step, and finally read by the extra entry point\n 'backstage-public-path': '<%= publicPath %>/',\n },\n minify: false,\n publicPath: '<%= publicPath %>',\n filename: 'index.html.tmpl',\n template: `${require.resolve('raw-loader')}!${paths.targetHtml}`,\n }),\n );\n }\n\n if (options.moduleFederationRemote) {\n const AdaptedModuleFederationPlugin = webpack\n ? (require('@module-federation/enhanced/webpack')\n .ModuleFederationPlugin as unknown as typeof ModuleFederationPlugin)\n : ModuleFederationPlugin;\n\n const exposes = options.moduleFederationRemote.exposes\n ? Object.fromEntries(\n Object.entries(options.moduleFederationRemote?.exposes).map(\n ([k, v]) => [k, resolvePath(paths.targetPath, v)],\n ),\n )\n : {\n '.': paths.targetEntry,\n };\n\n plugins.push(\n new AdaptedModuleFederationPlugin({\n filename: 'remoteEntry.js',\n exposes,\n name: options.moduleFederationRemote.name,\n runtime: false,\n shared: options.moduleFederationRemote.sharedDependencies,\n }),\n );\n }\n\n const buildInfo = await readBuildInfo();\n\n plugins.push(\n webpack\n ? new webpack.DefinePlugin({\n 'process.env.BUILD_INFO': JSON.stringify(buildInfo),\n 'process.env.APP_CONFIG': webpack.DefinePlugin.runtimeValue(\n () => JSON.stringify(options.getFrontendAppConfigs()),\n true,\n ),\n // This allows for conditional imports of react-dom/client, since there's no way\n // to check for presence of it in source code without module resolution errors.\n 'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(\n hasReactDomClient(),\n ),\n })\n : new bundler.DefinePlugin({\n 'process.env.BUILD_INFO': JSON.stringify(buildInfo),\n 'process.env.APP_CONFIG': JSON.stringify([]), // Inject via index.html instead\n // This allows for conditional imports of react-dom/client, since there's no way\n // to check for presence of it in source code without module resolution errors.\n 'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(\n hasReactDomClient(),\n ),\n }),\n );\n\n if (options.linkedWorkspace) {\n plugins.push(\n ...(await createWorkspaceLinkingPlugins(\n bundler,\n options.linkedWorkspace,\n )),\n );\n }\n\n // These files are required by the transpiled code when using React Refresh.\n // They need to be excluded to the module scope plugin which ensures that files\n // that exist in the package are required.\n const reactRefreshFiles = webpack\n ? [\n require.resolve(\n '@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js',\n ),\n require.resolve(\n '@pmmmwh/react-refresh-webpack-plugin/overlay/index.js',\n ),\n require.resolve('react-refresh'),\n ]\n : [];\n\n const mode = isDev ? 'development' : 'production';\n const optimization = optimizationConfig(options);\n\n return {\n mode,\n profile: false,\n ...(isDev\n ? {\n watchOptions: {\n ignored: /node_modules\\/(?!__backstage-autodetected-plugins__)/,\n },\n }\n : {}),\n optimization,\n bail: false,\n performance: {\n hints: false, // we check the gzip size instead\n },\n devtool: isDev ? 'eval-cheap-module-source-map' : 'source-map',\n context: paths.targetPath,\n entry: [\n /* eslint-disable-next-line no-restricted-syntax */\n findOwnPaths(__dirname).resolve('config/webpack-public-path'),\n ...(options.additionalEntryPoints ?? []),\n paths.targetEntry,\n ],\n resolve: {\n extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx', '.json', '.wasm'],\n mainFields: ['browser', 'module', 'main'],\n fallback: {\n ...pickBy(require('node-stdlib-browser')),\n module: false,\n dgram: false,\n dns: false,\n fs: false,\n http2: false,\n net: false,\n tls: false,\n child_process: false,\n\n /* new ignores */\n path: false,\n https: false,\n http: false,\n util: require.resolve('util/'),\n },\n // FIXME: see also https://github.com/web-infra-dev/rspack/issues/3408\n ...(webpack && {\n plugins: [\n new ModuleScopePlugin(\n [paths.targetSrc, paths.targetDev],\n [paths.targetPackageJson, ...reactRefreshFiles],\n ),\n ],\n }),\n },\n module: {\n rules: loaders,\n },\n output: {\n uniqueName: options.moduleFederationRemote?.name,\n path: paths.targetDist,\n publicPath: options.moduleFederationRemote ? 'auto' : `${publicPath}/`,\n filename: isDev ? '[name].js' : 'static/[name].[contenthash:8].js',\n chunkFilename: isDev\n ? '[name].chunk.js'\n : 'static/[name].[contenthash:8].chunk.js',\n ...(isDev\n ? {\n devtoolModuleFilenameTemplate: (info: any) =>\n `file:///${resolvePath(info.absoluteResourcePath).replace(\n /\\\\/g,\n '/',\n )}`,\n }\n : {}),\n },\n experiments: {\n lazyCompilation: yn(process.env.EXPERIMENTAL_LAZY_COMPILATION),\n ...(!webpack && {\n // We're still using `style-loader` for custom `insert` option\n css: false,\n }),\n },\n plugins,\n ...(options.moduleFederationRemote && {\n // TODO: remove this warning skipping as soon as the corresponding bundler limitation\n // described in issue https://github.com/web-infra-dev/rspack/issues/13635 is fixed\n // when PR: https://github.com/web-infra-dev/rspack/pull/13636 is merged.\n ignoreWarnings: [\n {\n message:\n /No version specified and unable to automatically determine one\\. No version in description file/,\n },\n ],\n }),\n };\n}\n"],"names":["runOutput","fs","targetPaths","version","transforms","TsCheckerRspackPlugin","ESLintRspackPlugin","rspack","HtmlWebpackPlugin","ConfigInjectingHtmlWebpackPlugin","ModuleFederationPlugin","resolvePath","hasReactDomClient","createWorkspaceLinkingPlugins","optimization","optimizationConfig","findOwnPaths","pickBy","ModuleScopePlugin","yn"],"mappings":"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"}
1
+ {"version":3,"file":"config.cjs.js","sources":["../../../src/lib/bundler/config.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { resolve as resolvePath } from 'node:path';\nimport { BundlingOptions, ModuleFederationRemoteOptions } from './types';\nimport { rspack, Configuration } from '@rspack/core';\n\nimport { BundlingPaths } from './paths';\nimport { Config } from '@backstage/config';\nimport ESLintRspackPlugin from 'eslint-rspack-plugin';\nimport { TsCheckerRspackPlugin } from 'ts-checker-rspack-plugin';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin';\nimport { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';\n\nimport fs from 'fs-extra';\nimport { optimization as optimizationConfig } from './optimization';\nimport pickBy from 'lodash/pickBy';\nimport { findOwnPaths, runOutput, targetPaths } from '@backstage/cli-common';\n\nimport { transforms } from './transforms';\nimport { version } from '../../../package.json';\nimport yn from 'yn';\nimport { hasReactDomClient } from './hasReactDomClient';\nimport { createWorkspaceLinkingPlugins } from './linkWorkspaces';\nimport { ConfigInjectingHtmlWebpackPlugin } from './ConfigInjectingHtmlWebpackPlugin';\n\nexport function resolveBaseUrl(\n config: Config,\n moduleFederationRemote?: ModuleFederationRemoteOptions,\n): URL {\n const baseUrl = config.getOptionalString('app.baseUrl');\n\n const defaultBaseUrl = moduleFederationRemote\n ? `http://localhost:${process.env.PORT ?? '3000'}`\n : 'http://localhost:3000';\n\n try {\n return new URL(baseUrl ?? '/', defaultBaseUrl);\n } catch (error) {\n throw new Error(`Invalid app.baseUrl, ${error}`);\n }\n}\n\nexport function resolveEndpoint(\n config: Config,\n moduleFederationRemote?: ModuleFederationRemoteOptions,\n): {\n host: string;\n port: number;\n} {\n const url = resolveBaseUrl(config, moduleFederationRemote);\n\n return {\n host: config.getOptionalString('app.listen.host') ?? url.hostname,\n port:\n config.getOptionalNumber('app.listen.port') ??\n Number(url.port) ??\n (url.protocol === 'https:' ? 443 : 80),\n };\n}\n\nasync function readBuildInfo() {\n const timestamp = Date.now();\n\n let commit: string | undefined;\n try {\n commit = await runOutput(['git', 'rev-parse', 'HEAD']);\n } catch (error) {\n // ignore, see below\n }\n\n let gitVersion: string | undefined;\n try {\n gitVersion = await runOutput(['git', 'describe', '--always']);\n } catch (error) {\n // ignore, see below\n }\n\n if (commit === undefined || gitVersion === undefined) {\n console.info(\n 'NOTE: Did not compute git version or commit hash, could not execute the git command line utility',\n );\n }\n\n const { version: packageVersion } = await fs.readJson(\n targetPaths.resolve('package.json'),\n );\n\n return {\n cliVersion: version,\n gitVersion: gitVersion ?? 'unknown',\n packageVersion,\n timestamp,\n commit: commit ?? 'unknown',\n };\n}\n\nexport async function createConfig(\n paths: BundlingPaths,\n options: BundlingOptions,\n): Promise<Configuration> {\n const {\n checksEnabled,\n isDev,\n frontendConfig,\n moduleFederationRemote,\n publicSubPath = '',\n webpack,\n } = options;\n\n const { plugins, loaders } = transforms(options);\n // Any package that is part of the monorepo but outside the monorepo root dir need\n // separate resolution logic.\n\n const validBaseUrl = resolveBaseUrl(frontendConfig, moduleFederationRemote);\n let publicPath = validBaseUrl.pathname.replace(/\\/$/, '');\n if (publicSubPath) {\n publicPath = `${publicPath}${publicSubPath}`.replace('//', '/');\n }\n\n if (isDev) {\n const { host, port } = resolveEndpoint(\n options.frontendConfig,\n options.moduleFederationRemote,\n );\n\n const refreshOptions = {\n overlay: {\n sockProtocol: 'ws',\n sockHost: host,\n sockPort: port,\n },\n } as const;\n\n if (webpack) {\n const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');\n plugins.push(new ReactRefreshPlugin(refreshOptions));\n } else {\n const RspackReactRefreshPlugin = require('@rspack/plugin-react-refresh');\n plugins.push(new RspackReactRefreshPlugin(refreshOptions));\n }\n }\n\n if (checksEnabled) {\n const TsCheckerPlugin = webpack\n ? (require('fork-ts-checker-webpack-plugin') as typeof import('fork-ts-checker-webpack-plugin'))\n : TsCheckerRspackPlugin;\n const ESLintPlugin = webpack\n ? (require('eslint-webpack-plugin') as typeof import('eslint-webpack-plugin'))\n : ESLintRspackPlugin;\n plugins.push(\n new TsCheckerPlugin({\n typescript: { configFile: paths.targetTsConfig, memoryLimit: 8192 },\n }),\n new ESLintPlugin({\n cache: false, // Cache seems broken\n context: paths.targetPath,\n files: ['**/*.(ts|tsx|mts|cts|js|jsx|mjs|cjs)'],\n }),\n );\n }\n\n const bundler = webpack ? (webpack as unknown as typeof rspack) : rspack;\n\n // TODO(blam): process is no longer auto polyfilled by webpack in v5.\n // we use the provide plugin to provide this polyfill, but lets look\n // to remove this eventually!\n plugins.push(\n new bundler.ProvidePlugin({\n process: require.resolve('process/browser'),\n Buffer: ['buffer', 'Buffer'],\n }),\n );\n\n if (!options.moduleFederationRemote) {\n const templateOptions = {\n meta: {\n 'backstage-app-mode': options?.appMode ?? 'public',\n },\n template: paths.targetHtml,\n templateParameters: {\n publicPath,\n config: frontendConfig,\n },\n };\n if (webpack) {\n // Config injection via index.html doesn't work across reloads with\n // WebPack, so we rely on the APP_CONFIG injection instead\n plugins.push(new HtmlWebpackPlugin(templateOptions));\n } else {\n // With Rspack we inject config via index.html, this is both because we\n // can't use APP_CONFIG due to the lack of support for runtime values, but\n // also because we are able to do it and it lines up better with what the\n // app-backend is doing.\n //\n // We still use the html plugin from WebPack, since the Rspack one won't\n // let us inject complex objects like the config.\n plugins.push(\n new ConfigInjectingHtmlWebpackPlugin(\n templateOptions,\n options.getFrontendAppConfigs,\n ),\n );\n }\n plugins.push(\n new HtmlWebpackPlugin({\n meta: {\n 'backstage-app-mode': options?.appMode ?? 'public',\n // This is added to be written in the later step, and finally read by the extra entry point\n 'backstage-public-path': '<%= publicPath %>/',\n },\n minify: false,\n publicPath: '<%= publicPath %>',\n filename: 'index.html.tmpl',\n template: `${require.resolve('raw-loader')}!${paths.targetHtml}`,\n }),\n );\n }\n\n if (options.moduleFederationRemote) {\n const AdaptedModuleFederationPlugin = webpack\n ? (require('@module-federation/enhanced/webpack')\n .ModuleFederationPlugin as unknown as typeof ModuleFederationPlugin)\n : ModuleFederationPlugin;\n\n const exposes = options.moduleFederationRemote.exposes\n ? Object.fromEntries(\n Object.entries(options.moduleFederationRemote?.exposes).map(\n ([k, v]) => [k, resolvePath(paths.targetPath, v)],\n ),\n )\n : {\n '.': paths.targetEntry,\n };\n\n plugins.push(\n new AdaptedModuleFederationPlugin({\n filename: 'remoteEntry.js',\n exposes,\n name: options.moduleFederationRemote.name,\n runtime: false,\n shared: options.moduleFederationRemote.sharedDependencies,\n }),\n );\n }\n\n const buildInfo = await readBuildInfo();\n\n plugins.push(\n webpack\n ? new webpack.DefinePlugin({\n 'process.env.BUILD_INFO': JSON.stringify(buildInfo),\n 'process.env.APP_CONFIG': webpack.DefinePlugin.runtimeValue(\n () => JSON.stringify(options.getFrontendAppConfigs()),\n true,\n ),\n // This allows for conditional imports of react-dom/client, since there's no way\n // to check for presence of it in source code without module resolution errors.\n 'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(\n hasReactDomClient(),\n ),\n })\n : new bundler.DefinePlugin({\n 'process.env.BUILD_INFO': JSON.stringify(buildInfo),\n 'process.env.APP_CONFIG': JSON.stringify([]), // Inject via index.html instead\n // This allows for conditional imports of react-dom/client, since there's no way\n // to check for presence of it in source code without module resolution errors.\n 'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(\n hasReactDomClient(),\n ),\n }),\n );\n\n if (options.linkedWorkspace) {\n plugins.push(\n ...(await createWorkspaceLinkingPlugins(\n bundler,\n options.linkedWorkspace,\n )),\n );\n }\n\n // These files are required by the transpiled code when using React Refresh.\n // They need to be excluded to the module scope plugin which ensures that files\n // that exist in the package are required.\n const reactRefreshFiles = webpack\n ? [\n require.resolve(\n '@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js',\n ),\n require.resolve(\n '@pmmmwh/react-refresh-webpack-plugin/overlay/index.js',\n ),\n require.resolve('react-refresh'),\n ]\n : [];\n\n const mode = isDev ? 'development' : 'production';\n const optimization = optimizationConfig(options);\n\n return {\n mode,\n profile: false,\n ...(isDev\n ? {\n watchOptions: {\n ignored: /node_modules\\/(?!__backstage-autodetected-plugins__)/,\n },\n }\n : {}),\n optimization,\n bail: false,\n performance: {\n hints: false, // we check the gzip size instead\n },\n devtool: isDev ? 'eval-cheap-module-source-map' : 'source-map',\n context: paths.targetPath,\n entry: [\n /* eslint-disable-next-line no-restricted-syntax */\n findOwnPaths(__dirname).resolve('config/webpack-public-path'),\n ...(options.additionalEntryPoints ?? []),\n paths.targetEntry,\n ],\n resolve: {\n extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx', '.json', '.wasm'],\n mainFields: ['browser', 'module', 'main'],\n fallback: {\n ...pickBy(require('node-stdlib-browser')),\n module: false,\n dgram: false,\n dns: false,\n fs: false,\n http2: false,\n net: false,\n tls: false,\n child_process: false,\n\n /* new ignores */\n path: false,\n https: false,\n http: false,\n util: require.resolve('util/'),\n },\n // FIXME: see also https://github.com/web-infra-dev/rspack/issues/3408\n ...(webpack && {\n plugins: [\n new ModuleScopePlugin(\n [paths.targetSrc, paths.targetDev],\n [paths.targetPackageJson, ...reactRefreshFiles],\n ),\n ],\n }),\n },\n module: {\n rules: loaders,\n },\n output: {\n uniqueName: options.moduleFederationRemote?.name,\n path: paths.targetDist,\n publicPath: options.moduleFederationRemote ? 'auto' : `${publicPath}/`,\n filename: isDev ? '[name].js' : 'static/[name].[contenthash:8].js',\n chunkFilename: isDev\n ? '[name].chunk.js'\n : 'static/[name].[contenthash:8].chunk.js',\n ...(isDev\n ? {\n devtoolModuleFilenameTemplate: (info: any) =>\n `file:///${resolvePath(info.absoluteResourcePath).replace(\n /\\\\/g,\n '/',\n )}`,\n }\n : {}),\n },\n experiments: {\n lazyCompilation: yn(process.env.EXPERIMENTAL_LAZY_COMPILATION),\n ...(!webpack && {\n // We're still using `style-loader` for custom `insert` option\n css: false,\n }),\n },\n plugins,\n ignoreWarnings: [\n // @protobufjs/inquire uses require(moduleName) with a dynamic argument.\n // Since protobufjs >=7.5.9 this code path is never exercised (the\n // bundler-safe optional module lookups backport replaced all call sites),\n // but webpack/rspack still statically analyzes the source and emits a\n // \"Critical dependency\" warning. Safe to suppress.\n // See https://github.com/protobufjs/protobuf.js/issues/2057\n {\n module: /@protobufjs[\\\\/]inquire/,\n message:\n /Critical dependency: the request of a dependency is an expression/,\n },\n // TODO: remove this warning skipping as soon as the corresponding bundler limitation\n // described in issue https://github.com/web-infra-dev/rspack/issues/13635 is fixed\n // when PR: https://github.com/web-infra-dev/rspack/pull/13636 is merged.\n ...(options.moduleFederationRemote\n ? [\n {\n message:\n /No version specified and unable to automatically determine one\\. No version in description file/,\n },\n ]\n : []),\n ],\n };\n}\n"],"names":["runOutput","fs","targetPaths","version","transforms","TsCheckerRspackPlugin","ESLintRspackPlugin","rspack","HtmlWebpackPlugin","ConfigInjectingHtmlWebpackPlugin","ModuleFederationPlugin","resolvePath","hasReactDomClient","createWorkspaceLinkingPlugins","optimization","optimizationConfig","findOwnPaths","pickBy","ModuleScopePlugin","yn"],"mappings":"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"}
@@ -55,7 +55,7 @@ function prepareRuntimeSharedDependenciesScript(hostSharedDependencies) {
55
55
  name,
56
56
  version: sharedDep.version,
57
57
  lib: name,
58
- // Coverted into import below
58
+ // Converted into import below
59
59
  shareConfig: {
60
60
  singleton: sharedDep.singleton,
61
61
  requiredVersion: sharedDep.requiredVersion,
@@ -1 +1 @@
1
- {"version":3,"file":"moduleFederation.cjs.js","sources":["../../../src/lib/bundler/moduleFederation.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ModuleFederationRemoteOptions } from './types';\nimport { BackstagePackageJson } from '@backstage/cli-node';\nimport { readEntryPoints } from '../entryPoints';\nimport {\n createTypeDistProject,\n getEntryPointDefaultFeatureType,\n} from '../typeDistProject';\nimport {\n BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL,\n defaultRemoteSharedDependencies,\n defaultHostSharedDependencies,\n HostSharedDependencies,\n RuntimeSharedDependenciesGlobal,\n} from '@backstage/module-federation-common';\nimport { dirname, join as joinPath, resolve as resolvePath } from 'node:path';\nimport fs from 'fs-extra';\nimport chokidar from 'chokidar';\nimport PQueue from 'p-queue';\n\n// Remote modules management utilities\n\nexport async function getModuleFederationRemoteOptions(\n packageJson: BackstagePackageJson,\n packageDir: string,\n): Promise<ModuleFederationRemoteOptions | undefined> {\n let exposes: ModuleFederationRemoteOptions['exposes'];\n const packageRole = packageJson.backstage?.role;\n if (packageJson.exports && packageRole) {\n const project = await createTypeDistProject();\n exposes = Object.fromEntries(\n readEntryPoints(packageJson)\n .filter(ep => {\n if (ep.mount === './package.json') {\n return false;\n }\n if (ep.mount === '.') {\n return true;\n }\n // Include this additional entry point in the exposed modules\n // if it exports a feature as default export.\n return (\n getEntryPointDefaultFeatureType(\n packageRole,\n packageDir,\n project,\n ep.path,\n ) !== null\n );\n })\n .map(ep => [ep.mount, ep.path]),\n );\n }\n\n return {\n // The default output mode requires the name to be a usable as a code\n // symbol, there might be better options here but for now we need to\n // sanitize the name.\n name: packageJson.name\n .replaceAll('@', '')\n .replaceAll('/', '__')\n .replaceAll('-', '_'),\n exposes,\n sharedDependencies: defaultRemoteSharedDependencies(),\n };\n}\n\n// Module federation host management utilities\n\n/**\n * Prepares the runtime shared dependencies script for the module federation host,\n * which will be written by the CLI into a Javascript file added as an additional entry point for the frontend bundler.\n * This script is used in the browser to build the list of shared dependencies provided to the module federation runtime.\n *\n * @internal\n */\nexport function prepareRuntimeSharedDependenciesScript(\n hostSharedDependencies: HostSharedDependencies,\n) {\n const items = Object.entries(hostSharedDependencies).map(\n ([name, sharedDep]) => {\n if (!sharedDep.version) {\n throw new Error(`Version is required for shared dependency '${name}'`);\n }\n return {\n name,\n version: sharedDep.version,\n lib: name as unknown as () => Promise<unknown>, // Coverted into import below\n shareConfig: {\n singleton: sharedDep.singleton,\n requiredVersion: sharedDep.requiredVersion,\n eager: sharedDep.eager,\n },\n };\n },\n );\n\n return `window['${BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL}'] = ${JSON.stringify(\n { items, version: 'v1' } satisfies RuntimeSharedDependenciesGlobal,\n null,\n 2,\n ).replace(\n /\"lib\": (\"[^\"]+\")/gm,\n (_, name) => `\"lib\": () => import(${name})`,\n )};`;\n}\n\nconst RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME =\n '__backstage-module-federation-runtime-shared-dependencies__';\n\n// Make sure we're not issuing multiple writes at the same time, which can cause partial overwrites\nconst writeQueue = new PQueue({ concurrency: 1 });\n\nasync function writeRuntimeSharedDependenciesModule(\n targetPath: string,\n runtimeSharedDependencies: HostSharedDependencies,\n) {\n const script = prepareRuntimeSharedDependenciesScript(\n runtimeSharedDependencies,\n );\n\n await writeQueue.add(async () => {\n const path = joinPath(\n targetPath,\n 'node_modules',\n `${RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME}.js`,\n );\n\n await fs.ensureDir(dirname(path));\n await fs.writeFile(path, script);\n });\n}\n\nfunction resolveSharedDependencyVersions(\n targetPath: string,\n hostSharedDependencies: HostSharedDependencies,\n): HostSharedDependencies {\n return Object.fromEntries(\n Object.entries(hostSharedDependencies)\n .filter(([_, sharedDep]) => sharedDep !== undefined)\n .flatMap(([importPath, sharedDep]) => {\n // Remove any sub-path exports from the import path\n const moduleName = importPath.startsWith('@')\n ? importPath.split('/').slice(0, 2).join('/')\n : importPath.split('/')[0];\n\n let version: string;\n try {\n const packagePath = require.resolve(`${moduleName}/package.json`, {\n paths: [targetPath],\n });\n version = require(packagePath).version;\n } catch (e) {\n console.log(\n `Skipping module federation shared dependency '${importPath}' because it could not be resolved.`,\n );\n return [];\n }\n\n return [[importPath, { ...sharedDep, version }]];\n }),\n );\n}\n\nexport async function createRuntimeSharedDependenciesEntryPoint(options: {\n targetPath: string;\n watch?: () => void;\n}): Promise<string[]> {\n const { targetPath, watch } = options;\n\n const doWriteSharedDependenciesModule = async () => {\n const sharedDependencies = defaultHostSharedDependencies();\n await writeRuntimeSharedDependenciesModule(\n targetPath,\n resolveSharedDependencyVersions(targetPath, sharedDependencies),\n );\n };\n\n if (watch) {\n const watcher = chokidar.watch(resolvePath(targetPath, 'package.json'));\n watcher.on('change', async () => {\n await doWriteSharedDependenciesModule();\n watch();\n });\n }\n await doWriteSharedDependenciesModule();\n\n return [RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME];\n}\n"],"names":["createTypeDistProject","readEntryPoints","getEntryPointDefaultFeatureType","defaultRemoteSharedDependencies","BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL","PQueue","joinPath","fs","dirname","defaultHostSharedDependencies","chokidar","resolvePath"],"mappings":"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"}
1
+ {"version":3,"file":"moduleFederation.cjs.js","sources":["../../../src/lib/bundler/moduleFederation.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ModuleFederationRemoteOptions } from './types';\nimport { BackstagePackageJson } from '@backstage/cli-node';\nimport { readEntryPoints } from '../entryPoints';\nimport {\n createTypeDistProject,\n getEntryPointDefaultFeatureType,\n} from '../typeDistProject';\nimport {\n BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL,\n defaultRemoteSharedDependencies,\n defaultHostSharedDependencies,\n HostSharedDependencies,\n RuntimeSharedDependenciesGlobal,\n} from '@backstage/module-federation-common';\nimport { dirname, join as joinPath, resolve as resolvePath } from 'node:path';\nimport fs from 'fs-extra';\nimport chokidar from 'chokidar';\nimport PQueue from 'p-queue';\n\n// Remote modules management utilities\n\nexport async function getModuleFederationRemoteOptions(\n packageJson: BackstagePackageJson,\n packageDir: string,\n): Promise<ModuleFederationRemoteOptions | undefined> {\n let exposes: ModuleFederationRemoteOptions['exposes'];\n const packageRole = packageJson.backstage?.role;\n if (packageJson.exports && packageRole) {\n const project = await createTypeDistProject();\n exposes = Object.fromEntries(\n readEntryPoints(packageJson)\n .filter(ep => {\n if (ep.mount === './package.json') {\n return false;\n }\n if (ep.mount === '.') {\n return true;\n }\n // Include this additional entry point in the exposed modules\n // if it exports a feature as default export.\n return (\n getEntryPointDefaultFeatureType(\n packageRole,\n packageDir,\n project,\n ep.path,\n ) !== null\n );\n })\n .map(ep => [ep.mount, ep.path]),\n );\n }\n\n return {\n // The default output mode requires the name to be a usable as a code\n // symbol, there might be better options here but for now we need to\n // sanitize the name.\n name: packageJson.name\n .replaceAll('@', '')\n .replaceAll('/', '__')\n .replaceAll('-', '_'),\n exposes,\n sharedDependencies: defaultRemoteSharedDependencies(),\n };\n}\n\n// Module federation host management utilities\n\n/**\n * Prepares the runtime shared dependencies script for the module federation host,\n * which will be written by the CLI into a Javascript file added as an additional entry point for the frontend bundler.\n * This script is used in the browser to build the list of shared dependencies provided to the module federation runtime.\n *\n * @internal\n */\nexport function prepareRuntimeSharedDependenciesScript(\n hostSharedDependencies: HostSharedDependencies,\n) {\n const items = Object.entries(hostSharedDependencies).map(\n ([name, sharedDep]) => {\n if (!sharedDep.version) {\n throw new Error(`Version is required for shared dependency '${name}'`);\n }\n return {\n name,\n version: sharedDep.version,\n lib: name as unknown as () => Promise<unknown>, // Converted into import below\n shareConfig: {\n singleton: sharedDep.singleton,\n requiredVersion: sharedDep.requiredVersion,\n eager: sharedDep.eager,\n },\n };\n },\n );\n\n return `window['${BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL}'] = ${JSON.stringify(\n { items, version: 'v1' } satisfies RuntimeSharedDependenciesGlobal,\n null,\n 2,\n ).replace(\n /\"lib\": (\"[^\"]+\")/gm,\n (_, name) => `\"lib\": () => import(${name})`,\n )};`;\n}\n\nconst RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME =\n '__backstage-module-federation-runtime-shared-dependencies__';\n\n// Make sure we're not issuing multiple writes at the same time, which can cause partial overwrites\nconst writeQueue = new PQueue({ concurrency: 1 });\n\nasync function writeRuntimeSharedDependenciesModule(\n targetPath: string,\n runtimeSharedDependencies: HostSharedDependencies,\n) {\n const script = prepareRuntimeSharedDependenciesScript(\n runtimeSharedDependencies,\n );\n\n await writeQueue.add(async () => {\n const path = joinPath(\n targetPath,\n 'node_modules',\n `${RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME}.js`,\n );\n\n await fs.ensureDir(dirname(path));\n await fs.writeFile(path, script);\n });\n}\n\nfunction resolveSharedDependencyVersions(\n targetPath: string,\n hostSharedDependencies: HostSharedDependencies,\n): HostSharedDependencies {\n return Object.fromEntries(\n Object.entries(hostSharedDependencies)\n .filter(([_, sharedDep]) => sharedDep !== undefined)\n .flatMap(([importPath, sharedDep]) => {\n // Remove any sub-path exports from the import path\n const moduleName = importPath.startsWith('@')\n ? importPath.split('/').slice(0, 2).join('/')\n : importPath.split('/')[0];\n\n let version: string;\n try {\n const packagePath = require.resolve(`${moduleName}/package.json`, {\n paths: [targetPath],\n });\n version = require(packagePath).version;\n } catch (e) {\n console.log(\n `Skipping module federation shared dependency '${importPath}' because it could not be resolved.`,\n );\n return [];\n }\n\n return [[importPath, { ...sharedDep, version }]];\n }),\n );\n}\n\nexport async function createRuntimeSharedDependenciesEntryPoint(options: {\n targetPath: string;\n watch?: () => void;\n}): Promise<string[]> {\n const { targetPath, watch } = options;\n\n const doWriteSharedDependenciesModule = async () => {\n const sharedDependencies = defaultHostSharedDependencies();\n await writeRuntimeSharedDependenciesModule(\n targetPath,\n resolveSharedDependencyVersions(targetPath, sharedDependencies),\n );\n };\n\n if (watch) {\n const watcher = chokidar.watch(resolvePath(targetPath, 'package.json'));\n watcher.on('change', async () => {\n await doWriteSharedDependenciesModule();\n watch();\n });\n }\n await doWriteSharedDependenciesModule();\n\n return [RUNTIME_SHARED_DEPENDENCIES_MODULE_NAME];\n}\n"],"names":["createTypeDistProject","readEntryPoints","getEntryPointDefaultFeatureType","defaultRemoteSharedDependencies","BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL","PQueue","joinPath","fs","dirname","defaultHostSharedDependencies","chokidar","resolvePath"],"mappings":";;;;;;;;;;;;;;;;AAqCA,eAAsB,gCAAA,CACpB,aACA,UAAA,EACoD;AACpD,EAAA,IAAI,OAAA;AACJ,EAAA,MAAM,WAAA,GAAc,YAAY,SAAA,EAAW,IAAA;AAC3C,EAAA,IAAI,WAAA,CAAY,WAAW,WAAA,EAAa;AACtC,IAAA,MAAM,OAAA,GAAU,MAAMA,qCAAA,EAAsB;AAC5C,IAAA,OAAA,GAAU,MAAA,CAAO,WAAA;AAAA,MACfC,2BAAA,CAAgB,WAAW,CAAA,CACxB,MAAA,CAAO,CAAA,EAAA,KAAM;AACZ,QAAA,IAAI,EAAA,CAAG,UAAU,gBAAA,EAAkB;AACjC,UAAA,OAAO,KAAA;AAAA,QACT;AACA,QAAA,IAAI,EAAA,CAAG,UAAU,GAAA,EAAK;AACpB,UAAA,OAAO,IAAA;AAAA,QACT;AAGA,QAAA,OACEC,+CAAA;AAAA,UACE,WAAA;AAAA,UACA,UAAA;AAAA,UACA,OAAA;AAAA,UACA,EAAA,CAAG;AAAA,SACL,KAAM,IAAA;AAAA,MAEV,CAAC,EACA,GAAA,CAAI,CAAA,EAAA,KAAM,CAAC,EAAA,CAAG,KAAA,EAAO,EAAA,CAAG,IAAI,CAAC;AAAA,KAClC;AAAA,EACF;AAEA,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,IAAA,EAAM,WAAA,CAAY,IAAA,CACf,UAAA,CAAW,GAAA,EAAK,EAAE,CAAA,CAClB,UAAA,CAAW,GAAA,EAAK,IAAI,CAAA,CACpB,UAAA,CAAW,KAAK,GAAG,CAAA;AAAA,IACtB,OAAA;AAAA,IACA,oBAAoBC,sDAAA;AAAgC,GACtD;AACF;AAWO,SAAS,uCACd,sBAAA,EACA;AACA,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,sBAAsB,CAAA,CAAE,GAAA;AAAA,IACnD,CAAC,CAAC,IAAA,EAAM,SAAS,CAAA,KAAM;AACrB,MAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACtB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,MACvE;AACA,MAAA,OAAO;AAAA,QACL,IAAA;AAAA,QACA,SAAS,SAAA,CAAU,OAAA;AAAA,QACnB,GAAA,EAAK,IAAA;AAAA;AAAA,QACL,WAAA,EAAa;AAAA,UACX,WAAW,SAAA,CAAU,SAAA;AAAA,UACrB,iBAAiB,SAAA,CAAU,eAAA;AAAA,UAC3B,OAAO,SAAA,CAAU;AAAA;AACnB,OACF;AAAA,IACF;AAAA,GACF;AAEA,EAAA,OAAO,CAAA,QAAA,EAAWC,mEAA4C,CAAA,KAAA,EAAQ,IAAA,CAAK,SAAA;AAAA,IACzE,EAAE,KAAA,EAAO,OAAA,EAAS,IAAA,EAAK;AAAA,IACvB,IAAA;AAAA,IACA;AAAA,GACF,CAAE,OAAA;AAAA,IACA,oBAAA;AAAA,IACA,CAAC,CAAA,EAAG,IAAA,KAAS,CAAA,oBAAA,EAAuB,IAAI,CAAA,CAAA;AAAA,GACzC,CAAA,CAAA,CAAA;AACH;AAEA,MAAM,uCAAA,GACJ,6DAAA;AAGF,MAAM,aAAa,IAAIC,uBAAA,CAAO,EAAE,WAAA,EAAa,GAAG,CAAA;AAEhD,eAAe,oCAAA,CACb,YACA,yBAAA,EACA;AACA,EAAA,MAAM,MAAA,GAAS,sCAAA;AAAA,IACb;AAAA,GACF;AAEA,EAAA,MAAM,UAAA,CAAW,IAAI,YAAY;AAC/B,IAAA,MAAM,IAAA,GAAOC,cAAA;AAAA,MACX,UAAA;AAAA,MACA,cAAA;AAAA,MACA,GAAG,uCAAuC,CAAA,GAAA;AAAA,KAC5C;AAEA,IAAA,MAAMC,mBAAA,CAAG,SAAA,CAAUC,iBAAA,CAAQ,IAAI,CAAC,CAAA;AAChC,IAAA,MAAMD,mBAAA,CAAG,SAAA,CAAU,IAAA,EAAM,MAAM,CAAA;AAAA,EACjC,CAAC,CAAA;AACH;AAEA,SAAS,+BAAA,CACP,YACA,sBAAA,EACwB;AACxB,EAAA,OAAO,MAAA,CAAO,WAAA;AAAA,IACZ,OAAO,OAAA,CAAQ,sBAAsB,EAClC,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,SAAS,CAAA,KAAM,SAAA,KAAc,MAAS,CAAA,CAClD,OAAA,CAAQ,CAAC,CAAC,UAAA,EAAY,SAAS,CAAA,KAAM;AAEpC,MAAA,MAAM,UAAA,GAAa,WAAW,UAAA,CAAW,GAAG,IACxC,UAAA,CAAW,KAAA,CAAM,GAAG,CAAA,CAAE,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,KAAK,GAAG,CAAA,GAC1C,WAAW,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AAE3B,MAAA,IAAI,OAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,CAAA,EAAG,UAAU,CAAA,aAAA,CAAA,EAAiB;AAAA,UAChE,KAAA,EAAO,CAAC,UAAU;AAAA,SACnB,CAAA;AACD,QAAA,OAAA,GAAU,OAAA,CAAQ,WAAW,CAAA,CAAE,OAAA;AAAA,MACjC,SAAS,CAAA,EAAG;AACV,QAAA,OAAA,CAAQ,GAAA;AAAA,UACN,iDAAiD,UAAU,CAAA,mCAAA;AAAA,SAC7D;AACA,QAAA,OAAO,EAAC;AAAA,MACV;AAEA,MAAA,OAAO,CAAC,CAAC,UAAA,EAAY,EAAE,GAAG,SAAA,EAAW,OAAA,EAAS,CAAC,CAAA;AAAA,IACjD,CAAC;AAAA,GACL;AACF;AAEA,eAAsB,0CAA0C,OAAA,EAG1C;AACpB,EAAA,MAAM,EAAE,UAAA,EAAY,KAAA,EAAM,GAAI,OAAA;AAE9B,EAAA,MAAM,kCAAkC,YAAY;AAClD,IAAA,MAAM,qBAAqBE,oDAAA,EAA8B;AACzD,IAAA,MAAM,oCAAA;AAAA,MACJ,UAAA;AAAA,MACA,+BAAA,CAAgC,YAAY,kBAAkB;AAAA,KAChE;AAAA,EACF,CAAA;AAEA,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAM,UAAUC,yBAAA,CAAS,KAAA,CAAMC,iBAAA,CAAY,UAAA,EAAY,cAAc,CAAC,CAAA;AACtE,IAAA,OAAA,CAAQ,EAAA,CAAG,UAAU,YAAY;AAC/B,MAAA,MAAM,+BAAA,EAAgC;AACtC,MAAA,KAAA,EAAM;AAAA,IACR,CAAC,CAAA;AAAA,EACH;AACA,EAAA,MAAM,+BAAA,EAAgC;AAEtC,EAAA,OAAO,CAAC,uCAAuC,CAAA;AACjD;;;;;;"}
@@ -8,7 +8,6 @@ var debounce = require('lodash/debounce');
8
8
  var node_url = require('node:url');
9
9
  var node_path = require('node:path');
10
10
  var cliCommon = require('@backstage/cli-common');
11
- var configLoader = require('@backstage/config-loader');
12
11
  var spawn = require('cross-spawn');
13
12
  var startEmbeddedDb = require('./startEmbeddedDb.cjs.js');
14
13
 
@@ -31,17 +30,14 @@ async function runBackend(options) {
31
30
  const server = new IpcServer.IpcServer();
32
31
  ServerDataStore.ServerDataStore.bind(server);
33
32
  const extraEnv = {};
34
- let embeddedDb;
35
- const dbClient = await readDatabaseClient(
36
- options.configPaths,
37
- options.targetDir
38
- );
39
- if (dbClient === "embedded-postgres") {
40
- embeddedDb = await startEmbeddedDb.startEmbeddedDb();
41
- extraEnv.APP_CONFIG_backend_database = JSON.stringify({
42
- client: "pg",
43
- connection: embeddedDb.connection
44
- });
33
+ const embeddedDb = await startEmbeddedDb.startEmbeddedDb({
34
+ configPaths: options.configPaths,
35
+ targetDir: options.targetDir
36
+ });
37
+ if (embeddedDb) {
38
+ extraEnv.APP_CONFIG_backend_database = JSON.stringify(
39
+ embeddedDb.configOverride
40
+ );
45
41
  }
46
42
  let exiting = false;
47
43
  let firstStart = true;
@@ -148,24 +144,6 @@ async function runBackend(options) {
148
144
  });
149
145
  return () => exitPromise;
150
146
  }
151
- async function readDatabaseClient(configPaths, targetDir) {
152
- const rootDir = cliCommon.targetPaths.rootDir;
153
- const configBaseDir = targetDir ?? rootDir;
154
- const source = configLoader.ConfigSources.default({
155
- rootDir,
156
- allowMissingDefaultConfig: true,
157
- argv: (configPaths ?? []).flatMap((p) => [
158
- "--config",
159
- node_path.isAbsolute(p) ? p : node_path.resolve(configBaseDir, p)
160
- ])
161
- });
162
- const config = await configLoader.ConfigSources.toConfig(source);
163
- try {
164
- return config.getOptionalString("backend.database.client");
165
- } finally {
166
- config.close();
167
- }
168
- }
169
147
 
170
148
  exports.runBackend = runBackend;
171
149
  //# sourceMappingURL=runBackend.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runBackend.cjs.js","sources":["../../../src/lib/runner/runBackend.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FSWatcher, watch } from 'chokidar';\nimport type { ChildProcess } from 'node:child_process';\nimport { ctrlc } from 'ctrlc-windows';\nimport { IpcServer, ServerDataStore } from '../ipc';\nimport debounce from 'lodash/debounce';\nimport { fileURLToPath } from 'node:url';\nimport {\n isAbsolute as isAbsolutePath,\n resolve as resolvePath,\n} from 'node:path';\nimport { targetPaths } from '@backstage/cli-common';\nimport { ConfigSources } from '@backstage/config-loader';\n\nimport spawn from 'cross-spawn';\nimport { startEmbeddedDb } from './startEmbeddedDb';\n\nconst loaderArgs = [\n '--enable-source-maps',\n '--require',\n require.resolve('@backstage/cli-node/config/nodeTransform.cjs'),\n // TODO: Support modules, although there's currently no way to load them since import() is transpiled to require()\n];\n\nexport type RunBackendOptions = {\n /** The directory to run the backend process in, defaults to cwd */\n targetDir?: string;\n /** relative entry point path without extension, e.g. 'src/index' */\n entry: string;\n /** Whether to forward the --inspect flag to the node process */\n inspectEnabled?: boolean | string;\n /** Whether to forward the --inspect-brk flag to the node process */\n inspectBrkEnabled?: boolean | string;\n /** Additional module to require via the --require flag to the node process */\n require?: string | string[];\n /** An external linked workspace to override module resolution towards */\n linkedWorkspace?: string;\n /** Config file paths from --config flags */\n configPaths?: string[];\n};\n\nexport async function runBackend(options: RunBackendOptions) {\n const envEnv = process.env as { NODE_ENV: string; NODE_OPTIONS?: string };\n if (!envEnv.NODE_ENV) {\n envEnv.NODE_ENV = 'development';\n }\n\n // Set up the parent IPC server and bind the available services\n const server = new IpcServer();\n ServerDataStore.bind(server);\n\n const extraEnv: Record<string, string> = {};\n\n let embeddedDb: Awaited<ReturnType<typeof startEmbeddedDb>> | undefined;\n\n const dbClient = await readDatabaseClient(\n options.configPaths,\n options.targetDir,\n );\n if (dbClient === 'embedded-postgres') {\n embeddedDb = await startEmbeddedDb();\n extraEnv.APP_CONFIG_backend_database = JSON.stringify({\n client: 'pg',\n connection: embeddedDb.connection,\n });\n }\n\n let exiting = false;\n let firstStart = true;\n let child: ChildProcess | undefined;\n let watcher: FSWatcher | undefined = undefined;\n let shutdownPromise: Promise<void> | undefined = undefined;\n\n const watchedPaths = new Set<string>();\n\n const restart = debounce(async () => {\n if (firstStart) {\n firstStart = false;\n } else {\n console.log();\n console.log('Change detected, restarting the development server...');\n console.log();\n }\n // If a re-trigger happens during an existing shutdown, we just ignore it\n if (shutdownPromise) {\n return;\n }\n\n if (child && !child.killed && child.exitCode === null) {\n // We always wait for the existing process to exit, to make sure we don't get IPC conflicts\n shutdownPromise = new Promise(resolve => child!.once('exit', resolve));\n if (process.platform === 'win32' && child.pid) {\n ctrlc(child.pid);\n } else {\n child.kill();\n }\n await shutdownPromise;\n shutdownPromise = undefined;\n }\n\n // We've received a shutdown signal\n if (exiting) {\n return;\n }\n\n const optionArgs = new Array<string>();\n if (options.inspectEnabled) {\n const inspect =\n typeof options.inspectEnabled === 'string'\n ? `--inspect=${options.inspectEnabled}`\n : '--inspect';\n optionArgs.push(inspect);\n } else if (options.inspectBrkEnabled) {\n const inspect =\n typeof options.inspectBrkEnabled === 'string'\n ? `--inspect-brk=${options.inspectBrkEnabled}`\n : '--inspect-brk';\n optionArgs.push(inspect);\n }\n if (options.require) {\n const requires = [options.require].flat();\n for (const r of requires) {\n optionArgs.push(`--require=${r}`);\n }\n }\n\n // Unless the user explicitly toggles node-snapshot, default to provide --no-node-snapshot to reduce number of steps to run scaffolder\n // on Node LTS.\n if (!envEnv.NODE_OPTIONS?.includes('--node-snapshot')) {\n optionArgs.push('--no-node-snapshot');\n }\n\n const userArgs = process.argv\n .slice(['node', 'backstage-cli', 'package', 'start'].length)\n .filter(arg => !optionArgs.includes(arg));\n\n child = spawn(\n process.execPath,\n [...loaderArgs, ...optionArgs, options.entry, ...userArgs],\n {\n stdio: ['ignore', 'inherit', 'inherit', 'ipc'],\n cwd: options.targetDir,\n env: {\n ...process.env,\n ...extraEnv,\n BACKSTAGE_CLI_LINKED_WORKSPACE: options.linkedWorkspace,\n BACKSTAGE_CLI_CHANNEL: '1',\n ESBK_TSCONFIG_PATH: targetPaths.resolveRoot('tsconfig.json'),\n },\n serialization: 'advanced',\n },\n );\n\n server.addChild(child);\n\n // This captures messages sent by @esbuild-kit/cjs-loader\n child.on('message', (data: { type?: string } | null) => {\n if (!watcher) {\n return;\n }\n if (typeof data === 'object' && data?.type === 'watch') {\n let path = (data as { path: string }).path;\n if (path.startsWith('file:')) {\n path = fileURLToPath(path);\n }\n\n if (isAbsolutePath(path) && !watchedPaths.has(path)) {\n watchedPaths.add(path);\n watcher.add(path);\n }\n }\n });\n }, 100);\n\n restart();\n\n watcher = watch(['./package.json'], {\n cwd: process.cwd(),\n ignoreInitial: true,\n ignorePermissionErrors: true,\n }).on('all', restart);\n\n // Trigger restart on hitting enter in the terminal\n process.stdin.on('data', restart);\n\n const exitPromise = new Promise<void>(resolveExitPromise => {\n async function handleSignal(signal: NodeJS.Signals) {\n exiting = true;\n\n // Forward signals to child and wait for it to exit if still running\n if (child && child.exitCode === null) {\n await new Promise(resolve => {\n child!.on('close', resolve);\n child!.kill(signal);\n });\n }\n\n await embeddedDb?.close();\n resolveExitPromise();\n }\n\n process.once('SIGINT', handleSignal);\n process.once('SIGTERM', handleSignal);\n });\n\n return () => exitPromise;\n}\n\nasync function readDatabaseClient(\n configPaths?: string[],\n targetDir?: string,\n): Promise<string | undefined> {\n const rootDir = targetPaths.rootDir;\n const configBaseDir = targetDir ?? rootDir;\n const source = ConfigSources.default({\n rootDir,\n allowMissingDefaultConfig: true,\n argv: (configPaths ?? []).flatMap(p => [\n '--config',\n isAbsolutePath(p) ? p : resolvePath(configBaseDir, p),\n ]),\n });\n\n const config = await ConfigSources.toConfig(source);\n try {\n return config.getOptionalString('backend.database.client');\n } finally {\n config.close();\n }\n}\n"],"names":["IpcServer","ServerDataStore","startEmbeddedDb","debounce","ctrlc","spawn","targetPaths","fileURLToPath","isAbsolutePath","watch","ConfigSources","resolvePath"],"mappings":"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"}
1
+ {"version":3,"file":"runBackend.cjs.js","sources":["../../../src/lib/runner/runBackend.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FSWatcher, watch } from 'chokidar';\nimport type { ChildProcess } from 'node:child_process';\nimport { ctrlc } from 'ctrlc-windows';\nimport { IpcServer, ServerDataStore } from '../ipc';\nimport debounce from 'lodash/debounce';\nimport { fileURLToPath } from 'node:url';\nimport { isAbsolute as isAbsolutePath } from 'node:path';\nimport { targetPaths } from '@backstage/cli-common';\n\nimport spawn from 'cross-spawn';\nimport { startEmbeddedDb } from './startEmbeddedDb';\n\nconst loaderArgs = [\n '--enable-source-maps',\n '--require',\n require.resolve('@backstage/cli-node/config/nodeTransform.cjs'),\n // TODO: Support modules, although there's currently no way to load them since import() is transpiled to require()\n];\n\nexport type RunBackendOptions = {\n /** The directory to run the backend process in, defaults to cwd */\n targetDir?: string;\n /** relative entry point path without extension, e.g. 'src/index' */\n entry: string;\n /** Whether to forward the --inspect flag to the node process */\n inspectEnabled?: boolean | string;\n /** Whether to forward the --inspect-brk flag to the node process */\n inspectBrkEnabled?: boolean | string;\n /** Additional module to require via the --require flag to the node process */\n require?: string | string[];\n /** An external linked workspace to override module resolution towards */\n linkedWorkspace?: string;\n /** Config file paths from --config flags */\n configPaths?: string[];\n};\n\nexport async function runBackend(options: RunBackendOptions) {\n const envEnv = process.env as { NODE_ENV: string; NODE_OPTIONS?: string };\n if (!envEnv.NODE_ENV) {\n envEnv.NODE_ENV = 'development';\n }\n\n // Set up the parent IPC server and bind the available services\n const server = new IpcServer();\n ServerDataStore.bind(server);\n\n const extraEnv: Record<string, string> = {};\n\n const embeddedDb = await startEmbeddedDb({\n configPaths: options.configPaths,\n targetDir: options.targetDir,\n });\n if (embeddedDb) {\n extraEnv.APP_CONFIG_backend_database = JSON.stringify(\n embeddedDb.configOverride,\n );\n }\n\n let exiting = false;\n let firstStart = true;\n let child: ChildProcess | undefined;\n let watcher: FSWatcher | undefined = undefined;\n let shutdownPromise: Promise<void> | undefined = undefined;\n\n const watchedPaths = new Set<string>();\n\n const restart = debounce(async () => {\n if (firstStart) {\n firstStart = false;\n } else {\n console.log();\n console.log('Change detected, restarting the development server...');\n console.log();\n }\n // If a re-trigger happens during an existing shutdown, we just ignore it\n if (shutdownPromise) {\n return;\n }\n\n if (child && !child.killed && child.exitCode === null) {\n // We always wait for the existing process to exit, to make sure we don't get IPC conflicts\n shutdownPromise = new Promise(resolve => child!.once('exit', resolve));\n if (process.platform === 'win32' && child.pid) {\n ctrlc(child.pid);\n } else {\n child.kill();\n }\n await shutdownPromise;\n shutdownPromise = undefined;\n }\n\n // We've received a shutdown signal\n if (exiting) {\n return;\n }\n\n const optionArgs = new Array<string>();\n if (options.inspectEnabled) {\n const inspect =\n typeof options.inspectEnabled === 'string'\n ? `--inspect=${options.inspectEnabled}`\n : '--inspect';\n optionArgs.push(inspect);\n } else if (options.inspectBrkEnabled) {\n const inspect =\n typeof options.inspectBrkEnabled === 'string'\n ? `--inspect-brk=${options.inspectBrkEnabled}`\n : '--inspect-brk';\n optionArgs.push(inspect);\n }\n if (options.require) {\n const requires = [options.require].flat();\n for (const r of requires) {\n optionArgs.push(`--require=${r}`);\n }\n }\n\n // Unless the user explicitly toggles node-snapshot, default to provide --no-node-snapshot to reduce number of steps to run scaffolder\n // on Node LTS.\n if (!envEnv.NODE_OPTIONS?.includes('--node-snapshot')) {\n optionArgs.push('--no-node-snapshot');\n }\n\n const userArgs = process.argv\n .slice(['node', 'backstage-cli', 'package', 'start'].length)\n .filter(arg => !optionArgs.includes(arg));\n\n child = spawn(\n process.execPath,\n [...loaderArgs, ...optionArgs, options.entry, ...userArgs],\n {\n stdio: ['ignore', 'inherit', 'inherit', 'ipc'],\n cwd: options.targetDir,\n env: {\n ...process.env,\n ...extraEnv,\n BACKSTAGE_CLI_LINKED_WORKSPACE: options.linkedWorkspace,\n BACKSTAGE_CLI_CHANNEL: '1',\n ESBK_TSCONFIG_PATH: targetPaths.resolveRoot('tsconfig.json'),\n },\n serialization: 'advanced',\n },\n );\n\n server.addChild(child);\n\n // This captures messages sent by @esbuild-kit/cjs-loader\n child.on('message', (data: { type?: string } | null) => {\n if (!watcher) {\n return;\n }\n if (typeof data === 'object' && data?.type === 'watch') {\n let path = (data as { path: string }).path;\n if (path.startsWith('file:')) {\n path = fileURLToPath(path);\n }\n\n if (isAbsolutePath(path) && !watchedPaths.has(path)) {\n watchedPaths.add(path);\n watcher.add(path);\n }\n }\n });\n }, 100);\n\n restart();\n\n watcher = watch(['./package.json'], {\n cwd: process.cwd(),\n ignoreInitial: true,\n ignorePermissionErrors: true,\n }).on('all', restart);\n\n // Trigger restart on hitting enter in the terminal\n process.stdin.on('data', restart);\n\n const exitPromise = new Promise<void>(resolveExitPromise => {\n async function handleSignal(signal: NodeJS.Signals) {\n exiting = true;\n\n // Forward signals to child and wait for it to exit if still running\n if (child && child.exitCode === null) {\n await new Promise(resolve => {\n child!.on('close', resolve);\n child!.kill(signal);\n });\n }\n\n await embeddedDb?.close();\n resolveExitPromise();\n }\n\n process.once('SIGINT', handleSignal);\n process.once('SIGTERM', handleSignal);\n });\n\n return () => exitPromise;\n}\n"],"names":["IpcServer","ServerDataStore","startEmbeddedDb","debounce","ctrlc","spawn","targetPaths","fileURLToPath","isAbsolutePath","watch"],"mappings":"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"}
@@ -5,6 +5,8 @@ var fs = require('fs-extra');
5
5
  var node_path = require('node:path');
6
6
  var portfinder = require('portfinder');
7
7
  var errors = require('@backstage/errors');
8
+ var configLoader = require('@backstage/config-loader');
9
+ var cliCommon = require('@backstage/cli-common');
8
10
  var chalk = require('chalk');
9
11
 
10
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -39,7 +41,17 @@ async function cleanStaleDatabases() {
39
41
  })
40
42
  );
41
43
  }
42
- async function startEmbeddedDb() {
44
+ async function startEmbeddedDb(options) {
45
+ const dbConfig = await readDatabaseConfig(
46
+ options.configPaths,
47
+ options.targetDir
48
+ );
49
+ if (dbConfig?.client !== "embedded-postgres") {
50
+ return void 0;
51
+ }
52
+ return startEmbeddedDbInternal(dbConfig.connection);
53
+ }
54
+ async function startEmbeddedDbInternal(userConfig) {
43
55
  console.warn(
44
56
  chalk__default.default.yellow(
45
57
  "WARNING: Using embedded-postgres for local development is experimental and subject to change"
@@ -54,10 +66,10 @@ async function startEmbeddedDb() {
54
66
  }
55
67
  );
56
68
  await cleanStaleDatabases();
57
- const host = "localhost";
58
- const user = "postgres";
59
- const password = "password";
60
- const port = await portfinder.getPortPromise();
69
+ const host = userConfig?.host ?? "localhost";
70
+ const user = userConfig?.user ?? "postgres";
71
+ const password = userConfig?.password ?? "postgres";
72
+ const port = userConfig?.port ?? await portfinder.getPortPromise();
61
73
  const tmpDir = await fs__default.default.mkdtemp(node_path.resolve(os__default.default.tmpdir(), TEMP_DIR_PREFIX));
62
74
  const pg = new EmbeddedPostgres({
63
75
  databaseDir: tmpDir,
@@ -82,19 +94,66 @@ async function startEmbeddedDb() {
82
94
  });
83
95
  throw error;
84
96
  }
97
+ const configOverride = {
98
+ client: "pg"
99
+ };
100
+ const defaultedConnection = {};
101
+ if (!userConfig?.host) {
102
+ defaultedConnection.host = host;
103
+ }
104
+ if (!userConfig?.user) {
105
+ defaultedConnection.user = user;
106
+ }
107
+ if (!userConfig?.password) {
108
+ defaultedConnection.password = password;
109
+ }
110
+ if (!userConfig?.port) {
111
+ defaultedConnection.port = port;
112
+ }
113
+ if (Object.keys(defaultedConnection).length > 0) {
114
+ configOverride.connection = defaultedConnection;
115
+ }
85
116
  return {
86
- connection: {
87
- host,
88
- user,
89
- password,
90
- port
91
- },
117
+ configOverride,
92
118
  async close() {
93
119
  await pg.stop();
94
120
  await fs__default.default.remove(tmpDir);
95
121
  }
96
122
  };
97
123
  }
124
+ async function readDatabaseConfig(configPaths, targetDir) {
125
+ const rootDir = cliCommon.targetPaths.rootDir;
126
+ const configBaseDir = targetDir ?? rootDir;
127
+ const source = configLoader.ConfigSources.default({
128
+ rootDir,
129
+ allowMissingDefaultConfig: true,
130
+ argv: (configPaths ?? []).flatMap((p) => [
131
+ "--config",
132
+ node_path.isAbsolute(p) ? p : node_path.resolve(configBaseDir, p)
133
+ ])
134
+ });
135
+ const config = await configLoader.ConfigSources.toConfig(source);
136
+ try {
137
+ const client = config.getOptionalString("backend.database.client");
138
+ if (!client) {
139
+ return void 0;
140
+ }
141
+ const rawConnection = config.getOptional("backend.database.connection");
142
+ if (typeof rawConnection === "string" || rawConnection === void 0) {
143
+ return { client };
144
+ }
145
+ const host = config.getOptionalString("backend.database.connection.host");
146
+ const port = config.getOptionalNumber("backend.database.connection.port");
147
+ const user = config.getOptionalString("backend.database.connection.user");
148
+ const password = config.getOptionalString(
149
+ "backend.database.connection.password"
150
+ );
151
+ const connection = host !== void 0 || port !== void 0 || user !== void 0 || password !== void 0 ? { host, port, user, password } : void 0;
152
+ return { client, connection };
153
+ } finally {
154
+ config.close();
155
+ }
156
+ }
98
157
 
99
158
  exports.startEmbeddedDb = startEmbeddedDb;
100
159
  //# sourceMappingURL=startEmbeddedDb.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"startEmbeddedDb.cjs.js","sources":["../../../src/lib/runner/startEmbeddedDb.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport os from 'node:os';\nimport fs from 'fs-extra';\nimport { resolve as resolvePath } from 'node:path';\nimport { getPortPromise } from 'portfinder';\nimport { ForwardedError } from '@backstage/errors';\nimport chalk from 'chalk';\n\nconst TEMP_DIR_PREFIX = 'backstage-dev-db-';\nconst PID_FILE = 'backstage.pid';\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function cleanStaleDatabases() {\n const tmpBase = os.tmpdir();\n const entries = (await fs.readdir(tmpBase)).filter(d =>\n d.startsWith(TEMP_DIR_PREFIX),\n );\n await Promise.all(\n entries.map(async d => {\n const dir = resolvePath(tmpBase, d);\n const raw = await fs\n .readFile(resolvePath(dir, PID_FILE), 'utf8')\n .catch(() => undefined);\n const pid = raw ? Number(raw.trim()) : NaN;\n if (!pid || !isProcessAlive(pid)) {\n await fs.remove(dir);\n }\n }),\n );\n}\n\nexport async function startEmbeddedDb() {\n console.warn(\n chalk.yellow(\n 'WARNING: Using embedded-postgres for local development is experimental and subject to change',\n ),\n );\n\n const { default: EmbeddedPostgres } = await import('embedded-postgres').catch(\n error => {\n throw new ForwardedError(\n `Failed to load 'embedded-postgres' which is required when using ` +\n `'embedded-postgres' as the database client. It must be installed ` +\n `as an explicit dependency in your project`,\n error,\n );\n },\n );\n\n await cleanStaleDatabases();\n\n const host = 'localhost';\n const user = 'postgres';\n const password = 'password';\n const port = await getPortPromise();\n const tmpDir = await fs.mkdtemp(resolvePath(os.tmpdir(), TEMP_DIR_PREFIX));\n\n const pg = new EmbeddedPostgres({\n databaseDir: tmpDir,\n user,\n password,\n port,\n persistent: false,\n onError(messageOrError) {\n console.error(`[embedded-postgres]`, messageOrError);\n },\n onLog() {},\n });\n\n try {\n await pg.initialise();\n await fs.writeFile(resolvePath(tmpDir, PID_FILE), String(process.pid));\n await pg.start();\n } catch (error) {\n await pg.stop().catch(() => {});\n await fs.remove(tmpDir).catch(() => {});\n throw error;\n }\n\n return {\n connection: {\n host,\n user,\n password,\n port,\n },\n async close() {\n await pg.stop();\n await fs.remove(tmpDir);\n },\n };\n}\n"],"names":["os","fs","resolvePath","chalk","ForwardedError","getPortPromise"],"mappings":"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"}
1
+ {"version":3,"file":"startEmbeddedDb.cjs.js","sources":["../../../src/lib/runner/startEmbeddedDb.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport os from 'node:os';\nimport fs from 'fs-extra';\nimport {\n isAbsolute as isAbsolutePath,\n resolve as resolvePath,\n} from 'node:path';\nimport { getPortPromise } from 'portfinder';\nimport { ForwardedError } from '@backstage/errors';\nimport { ConfigSources } from '@backstage/config-loader';\nimport { targetPaths } from '@backstage/cli-common';\nimport chalk from 'chalk';\n\nconst TEMP_DIR_PREFIX = 'backstage-dev-db-';\nconst PID_FILE = 'backstage.pid';\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function cleanStaleDatabases() {\n const tmpBase = os.tmpdir();\n const entries = (await fs.readdir(tmpBase)).filter(d =>\n d.startsWith(TEMP_DIR_PREFIX),\n );\n await Promise.all(\n entries.map(async d => {\n const dir = resolvePath(tmpBase, d);\n const raw = await fs\n .readFile(resolvePath(dir, PID_FILE), 'utf8')\n .catch(() => undefined);\n const pid = raw ? Number(raw.trim()) : NaN;\n if (!pid || !isProcessAlive(pid)) {\n await fs.remove(dir);\n }\n }),\n );\n}\n\nexport interface EmbeddedDbConnectionConfig {\n host?: string;\n port?: number;\n user?: string;\n password?: string;\n}\n\nexport interface StartEmbeddedDbOptions {\n configPaths?: string[];\n targetDir?: string;\n}\n\n/**\n * Reads the database configuration from the app config and, if the client is\n * `embedded-postgres`, starts an embedded Postgres instance. Returns the config\n * override to inject into the child process, or `undefined` if the database\n * client is not `embedded-postgres`.\n */\nexport async function startEmbeddedDb(options: StartEmbeddedDbOptions): Promise<\n | {\n configOverride: Record<string, unknown>;\n close(): Promise<void>;\n }\n | undefined\n> {\n const dbConfig = await readDatabaseConfig(\n options.configPaths,\n options.targetDir,\n );\n if (dbConfig?.client !== 'embedded-postgres') {\n return undefined;\n }\n\n return startEmbeddedDbInternal(dbConfig.connection);\n}\n\nasync function startEmbeddedDbInternal(\n userConfig?: EmbeddedDbConnectionConfig,\n) {\n console.warn(\n chalk.yellow(\n 'WARNING: Using embedded-postgres for local development is experimental and subject to change',\n ),\n );\n\n const { default: EmbeddedPostgres } = await import('embedded-postgres').catch(\n error => {\n throw new ForwardedError(\n `Failed to load 'embedded-postgres' which is required when using ` +\n `'embedded-postgres' as the database client. It must be installed ` +\n `as an explicit dependency in your project`,\n error,\n );\n },\n );\n\n await cleanStaleDatabases();\n\n const host = userConfig?.host ?? 'localhost';\n const user = userConfig?.user ?? 'postgres';\n const password = userConfig?.password ?? 'postgres';\n const port = userConfig?.port ?? (await getPortPromise());\n const tmpDir = await fs.mkdtemp(resolvePath(os.tmpdir(), TEMP_DIR_PREFIX));\n\n const pg = new EmbeddedPostgres({\n databaseDir: tmpDir,\n user,\n password,\n port,\n persistent: false,\n onError(messageOrError) {\n console.error(`[embedded-postgres]`, messageOrError);\n },\n onLog() {},\n });\n\n try {\n await pg.initialise();\n await fs.writeFile(resolvePath(tmpDir, PID_FILE), String(process.pid));\n await pg.start();\n } catch (error) {\n await pg.stop().catch(() => {});\n await fs.remove(tmpDir).catch(() => {});\n throw error;\n }\n\n const configOverride: Record<string, unknown> = {\n client: 'pg',\n };\n const defaultedConnection: Record<string, string | number> = {};\n if (!userConfig?.host) {\n defaultedConnection.host = host;\n }\n if (!userConfig?.user) {\n defaultedConnection.user = user;\n }\n if (!userConfig?.password) {\n defaultedConnection.password = password;\n }\n if (!userConfig?.port) {\n defaultedConnection.port = port;\n }\n if (Object.keys(defaultedConnection).length > 0) {\n configOverride.connection = defaultedConnection;\n }\n\n return {\n configOverride,\n async close() {\n await pg.stop();\n await fs.remove(tmpDir);\n },\n };\n}\n\nasync function readDatabaseConfig(\n configPaths?: string[],\n targetDir?: string,\n): Promise<\n | {\n client: string;\n connection?: EmbeddedDbConnectionConfig;\n }\n | undefined\n> {\n const rootDir = targetPaths.rootDir;\n const configBaseDir = targetDir ?? rootDir;\n const source = ConfigSources.default({\n rootDir,\n allowMissingDefaultConfig: true,\n argv: (configPaths ?? []).flatMap(p => [\n '--config',\n isAbsolutePath(p) ? p : resolvePath(configBaseDir, p),\n ]),\n });\n\n const config = await ConfigSources.toConfig(source);\n try {\n const client = config.getOptionalString('backend.database.client');\n if (!client) {\n return undefined;\n }\n\n // Only read structured connection config if the value is an object;\n // it can also be a plain string (e.g. ':memory:' for better-sqlite3).\n const rawConnection = config.getOptional('backend.database.connection');\n if (typeof rawConnection === 'string' || rawConnection === undefined) {\n return { client };\n }\n\n const host = config.getOptionalString('backend.database.connection.host');\n const port = config.getOptionalNumber('backend.database.connection.port');\n const user = config.getOptionalString('backend.database.connection.user');\n const password = config.getOptionalString(\n 'backend.database.connection.password',\n );\n\n const connection =\n host !== undefined ||\n port !== undefined ||\n user !== undefined ||\n password !== undefined\n ? { host, port, user, password }\n : undefined;\n\n return { client, connection };\n } finally {\n config.close();\n }\n}\n"],"names":["os","fs","resolvePath","chalk","ForwardedError","getPortPromise","targetPaths","ConfigSources","isAbsolutePath"],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var name = "@backstage/cli-module-build";
6
- var version = "0.1.3-next.0";
6
+ var version = "0.1.4-next.0";
7
7
  var description = "CLI module for Backstage CLI";
8
8
  var backstage = {
9
9
  role: "cli-module"
@@ -111,7 +111,7 @@ var devDependencies = {
111
111
  "@types/lodash": "^4.14.151",
112
112
  "@types/npm-packlist": "^3.0.0",
113
113
  "@types/shell-quote": "^1.7.5",
114
- "embedded-postgres": "18.3.0-beta.16"
114
+ "embedded-postgres": "18.3.0-beta.17"
115
115
  };
116
116
  var peerDependencies = {
117
117
  "embedded-postgres": "^18.3.0-beta.16"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/cli-module-build",
3
- "version": "0.1.3-next.0",
3
+ "version": "0.1.4-next.0",
4
4
  "description": "CLI module for Backstage CLI",
5
5
  "backstage": {
6
6
  "role": "cli-module"
@@ -40,12 +40,12 @@
40
40
  ]
41
41
  },
42
42
  "dependencies": {
43
- "@backstage/cli-common": "0.2.2-next.0",
44
- "@backstage/cli-node": "0.3.2-next.0",
45
- "@backstage/config": "1.3.8-next.0",
46
- "@backstage/config-loader": "1.10.11-next.0",
47
- "@backstage/errors": "1.3.1-next.0",
48
- "@backstage/module-federation-common": "0.1.4-next.0",
43
+ "@backstage/cli-common": "0.2.2",
44
+ "@backstage/cli-node": "0.3.2",
45
+ "@backstage/config": "1.3.8",
46
+ "@backstage/config-loader": "1.10.11",
47
+ "@backstage/errors": "1.3.1",
48
+ "@backstage/module-federation-common": "0.1.4",
49
49
  "@manypkg/get-packages": "^1.1.3",
50
50
  "@module-federation/enhanced": "^2.3.3",
51
51
  "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0",
@@ -102,13 +102,13 @@
102
102
  "yn": "^4.0.0"
103
103
  },
104
104
  "devDependencies": {
105
- "@backstage/backend-test-utils": "1.11.3-next.0",
106
- "@backstage/cli": "0.36.2-next.0",
105
+ "@backstage/backend-test-utils": "1.11.4-next.0",
106
+ "@backstage/cli": "0.36.3-next.0",
107
107
  "@types/fs-extra": "^11.0.0",
108
108
  "@types/lodash": "^4.14.151",
109
109
  "@types/npm-packlist": "^3.0.0",
110
110
  "@types/shell-quote": "^1.7.5",
111
- "embedded-postgres": "18.3.0-beta.16"
111
+ "embedded-postgres": "18.3.0-beta.17"
112
112
  },
113
113
  "peerDependencies": {
114
114
  "embedded-postgres": "^18.3.0-beta.16"