diff --git a/packages/cli/package.json b/packages/cli/package.json index 5999a55fc1..7889f3ab17 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -133,6 +133,7 @@ "webpack": "^5.70.0", "webpack-dev-server": "^4.7.3", "webpack-node-externals": "^3.0.0", + "webpack-virtual-modules": "^0.5.0", "yaml": "^2.0.0", "yml-loader": "^2.1.0", "yn": "^4.0.0", diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 7f629b9e11..6ebfeae99e 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -22,6 +22,7 @@ import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; import webpack, { ProvidePlugin } from 'webpack'; import nodeExternals from 'webpack-node-externals'; +import VirtualModulesPlugin from 'webpack-virtual-modules'; import { isChildPath } from '@backstage/cli-common'; import { getPackages } from '@manypkg/get-packages'; import { optimization } from './optimization'; @@ -39,6 +40,7 @@ import pickBy from 'lodash/pickBy'; import yn from 'yn'; import { readEntryPoints } from '../entryPoints'; +const PACKAGES_GLOBAL = '__backstage_detected_packages__'; const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE'; export function resolveBaseUrl(config: Config): URL { @@ -84,7 +86,7 @@ export async function createConfig( paths: BundlingPaths, options: BundlingOptions, ): Promise { - const { checksEnabled, isDev, frontendConfig, extraPackages } = options; + const { checksEnabled, isDev, frontendConfig, extraPackages = [] } = options; const { plugins, loaders } = transforms(options); // Any package that is part of the monorepo but outside the monorepo root dir need @@ -127,19 +129,17 @@ export async function createConfig( }), ); - plugins.push( - new ProvidePlugin( - Object.fromEntries( - extraPackages?.map(name => [ - `__backstageLoadedPackage_${name}`, - name, - ]) ?? [], - ), - ), - ); + if (extraPackages.length > 0) { + const requirePackageScript = extraPackages + ?.map(pkg => `require('${pkg}')`) + .join(','); - // In browser - // const packageKeys = Object.keys(window).filter(key => key.startsWith('__backstageLoadedPackage_')) + plugins.push( + new VirtualModulesPlugin({ + [`node_modules/${PACKAGES_GLOBAL}.js`]: `window['${PACKAGES_GLOBAL}'] = { modules: [${requirePackageScript}] }`, + }), + ); + } const buildInfo = await readBuildInfo(); plugins.push( @@ -177,7 +177,10 @@ export async function createConfig( }, devtool: isDev ? 'eval-cheap-module-source-map' : 'source-map', context: paths.targetPath, - entry: [paths.targetEntry, ...(extraPackages ?? [])], + entry: [ + ...(extraPackages.length > 0 ? [`${PACKAGES_GLOBAL}.js`] : []), + paths.targetEntry, + ], resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx', '.json', '.wasm'], mainFields: ['browser', 'module', 'main'], diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 878d9d971d..d51ab7dc30 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -33,8 +33,34 @@ import { forbiddenDuplicatesFilter, includedFilter, } from '../../commands/versions/lint'; +import { BackstagePackageJson } from '@backstage/cli-node'; export async function serveBundle(options: ServeOptions) { + const paths = resolveBundlingPaths(options); + const pkgPath = paths.targetPackageJson; + const pkg: BackstagePackageJson = await fs.readJson(pkgPath); + + // TODO: proper + // Assumption for config string based on https://github.com/backstage/backstage/issues/18372 ^ + const packageDetectionMode = options.fullConfig.getOptionalString( + 'app.experimental.packages', + ); + const extraPackages = []; + if (packageDetectionMode === 'all') { + for (const depName of Object.keys(pkg.dependencies ?? {})) { + const depPackageJson: BackstagePackageJson = require(require.resolve( + `${depName}/package.json`, + { paths: [paths.targetPath] }, + )); + if ( + ['frontend-plugin', 'frontend-plugin-module'].includes( + depPackageJson.backstage?.role || '', + ) + ) { + extraPackages.push(depName); + } + } + } if (options.verifyVersions) { const lockfile = await Lockfile.load( libPaths.resolveTargetRoot('yarn.lock'), @@ -107,7 +133,6 @@ export async function serveBundle(options: ServeOptions) { const { frontendConfig, fullConfig } = cliConfig; // TODO: proper - const extraPackages = ['@backstage/plugin-org']; const url = resolveBaseUrl(frontendConfig); const host = @@ -117,9 +142,6 @@ export async function serveBundle(options: ServeOptions) { Number(url.port) || (url.protocol === 'https:' ? 443 : 80); - const paths = resolveBundlingPaths(options); - const pkgPath = paths.targetPackageJson; - const pkg = await fs.readJson(pkgPath); const config = await createConfig(paths, { ...options, checksEnabled: options.checksEnabled, diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index dd82169e40..da26cd4db0 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -98,7 +98,5 @@ export function createPlugin< >( config: PluginConfig, ): BackstagePlugin { - const plugin = new PluginImpl(config); - window.allPlugins.push(plugin); - return plugin; + return new PluginImpl(config); } diff --git a/plugins/graphiql/dev/index.tsx b/plugins/graphiql/dev/index.tsx index 2aabfc51ba..209a9a5c86 100644 --- a/plugins/graphiql/dev/index.tsx +++ b/plugins/graphiql/dev/index.tsx @@ -28,65 +28,8 @@ import { graphQlBrowseApiRef, GraphiQLPage, } from '../src'; -// import * as orgPlugin from '@backstage/plugin-org'; -// console.log(`DEBUG: orgPlugin=`, orgPlugin); - -// // (process.env.EXTRA_PACKAGE_IMPORTS as string[]).map(name => require(name)) -// console.log( -// `DEBUG: process.env.EXTRA_PACKAGE_IMPORTS=`, -// process.env.EXTRA_PACKAGE_IMPORTS, -// ); - -// require.ensure(process.env.EXTRA_PACKAGE_IMPORTS as string[], innerRequire => { -// console.log(`DEBUG: innerRequire=`, innerRequire); -// const path3 = require.resolve('@backstage/plugin-org'); -// console.log(`DEBUG: path3=`, path3); -// const loadedModules = (process.env.EXTRA_PACKAGE_IMPORTS as string[]).map( -// name => console.log('require', name) || require(name), -// ); -// console.log(`DEBUG: loadedModules=`, loadedModules); -// }); - -console.log(process.env); -console.log( - `DEBUG: process.env.EXTRA_PACKAGE_IMPORTS=`, - process.env.EXTRA_PACKAGE_IMPORTS, -); -// const orgPlugin = require([ -// '@backstage/plugin-org', -// '@backstage/plugin-todo', -// ], modules => { -// console.log(`DEBUG: modules=`, modules); -// }); -// require.ensure( -// process.env.EXTRA_PACKAGE_IMPORTS, -// innerRequire => { -// console.log( -// `DEBUG: module1=`, -// require(process.env.EXTRA_PACKAGE_IMPORTS[0]), -// ); -// // console.log( -// // `DEBUG: module2=`, -// // innerRequire(require.resolve('@backstage/plugin-todo')), -// // ); -// }, -// err => console.error('ERROR CALLBACK: ', err), -// ); - -// console.log(`DEBUG: orgPlugin=`, orgPlugin); - -// const orgPlugin2 = require(process.env.EXTRA_PACKAGE_IMPORTS, modules => { -// console.log(`DEBUG: modules=`, modules); -// }); -// console.log(`DEBUG: orgPlugin2=`, orgPlugin2); -// __webpack_require__( -// process.env.EXTRA_PACKAGE_IMPORTS as string[], -// loadedModules => { -// console.log(`DEBUG: loadedModules=`, loadedModules); -// }, -// ); -// require.context() +console.log('modules', window.__backstage_detected_packages__.modules); createDevApp() .registerPlugin(graphiqlPlugin) diff --git a/plugins/org/src/plugin.ts b/plugins/org/src/plugin.ts index a6715801f5..ea6856b6b4 100644 --- a/plugins/org/src/plugin.ts +++ b/plugins/org/src/plugin.ts @@ -27,8 +27,6 @@ export const orgPlugin = createPlugin({ }, }); -window.iAmTheOrgPlugin = orgPlugin; - /** @public */ export const EntityGroupProfileCard = orgPlugin.provide( createComponentExtension({ diff --git a/yarn.lock b/yarn.lock index 73bf45dd3e..3f730e9f31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3882,6 +3882,7 @@ __metadata: webpack: ^5.70.0 webpack-dev-server: ^4.7.3 webpack-node-externals: ^3.0.0 + webpack-virtual-modules: ^0.5.0 yaml: ^2.0.0 yml-loader: ^2.1.0 yn: ^4.0.0 @@ -42801,6 +42802,13 @@ __metadata: languageName: node linkType: hard +"webpack-virtual-modules@npm:^0.5.0": + version: 0.5.0 + resolution: "webpack-virtual-modules@npm:0.5.0" + checksum: 22b59257b55c89d11ae295b588b683ee9fdf3aeb591bc7b6f88ac1d69cb63f4fcb507666ea986866dfae161a1fa534ad6fb4e2ea91bbcd0a6d454368d7d4c64b + languageName: node + linkType: hard + "webpack@npm:^5, webpack@npm:^5.70.0": version: 5.88.2 resolution: "webpack@npm:5.88.2"