'use strict'; var role = require('./role-6YZbMsXe.cjs.js'); var fs = require('fs-extra'); var index = require('./index-CCLafGQH.cjs.js'); var webpack = require('webpack'); var packageDetection = require('./packageDetection-C__AGK-g.cjs.js'); require('yn'); var path = require('path'); require('react-dev-utils/FileSizeReporter'); require('react-dev-utils/formatWebpackMessages'); require('eslint-webpack-plugin'); require('fork-ts-checker-webpack-plugin'); require('html-webpack-plugin'); require('@backstage/cli-common'); require('react-dev-utils/ModuleScopePlugin'); require('run-script-webpack-plugin'); require('@manypkg/get-packages'); require('webpack-node-externals'); require('lodash/pickBy'); require('./run-BcxUFacd.cjs.js'); require('mini-css-extract-plugin'); require('@pmmmwh/react-refresh-webpack-plugin'); var chalk = require('chalk'); var cliNode = require('@backstage/cli-node'); var uniq = require('lodash/uniq'); var openBrowser = require('react-dev-utils/openBrowser'); var WebpackDevServer = require('webpack-dev-server'); require('semver'); require('@yarnpkg/parsers'); require('@yarnpkg/lockfile'); require('minimatch'); require('./yarn-BDZCENk5.cjs.js'); require('lodash/partition'); require('@backstage/config-loader'); require('@backstage/config'); var chokidar = require('chokidar'); var ctrlcWindows = require('ctrlc-windows'); var errors = require('@backstage/errors'); var debounce = require('lodash/debounce'); var url = require('url'); var spawn = require('cross-spawn'); var lint = require('./lint-BHw1vR1K.cjs.js'); var config = require('./config-OeQcmdz6.cjs.js'); var Lockfile = require('./Lockfile-C7rtIlD6.cjs.js'); require('commander'); require('./entryPoints-CoHH4lBA.cjs.js'); require('./svgrTemplate-BTjBQ3by.cjs.js'); require('p-queue'); require('child_process'); require('util'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } var fs__default = /*#__PURE__*/_interopDefaultCompat(fs); var webpack__default = /*#__PURE__*/_interopDefaultCompat(webpack); var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk); var uniq__default = /*#__PURE__*/_interopDefaultCompat(uniq); var openBrowser__default = /*#__PURE__*/_interopDefaultCompat(openBrowser); var WebpackDevServer__default = /*#__PURE__*/_interopDefaultCompat(WebpackDevServer); var debounce__default = /*#__PURE__*/_interopDefaultCompat(debounce); var spawn__default = /*#__PURE__*/_interopDefaultCompat(spawn); async function serveBackend(options) { const paths = packageDetection.resolveBundlingPaths(options); const config = await packageDetection.createBackendConfig(paths, { ...options, isDev: true }); process.env.NODE_ENV = "development"; const compiler = webpack__default.default(config, (err) => { if (err) { console.error(err); } else console.log("Build succeeded"); }); const waitForExit = async () => { for (const signal of ["SIGINT", "SIGTERM"]) { process.on(signal, () => { compiler.close(() => process.exit()); }); } return new Promise(() => { }); }; return waitForExit; } async function serveBundle(options) { var _a, _b, _c, _d, _e, _f, _g, _h; const paths = packageDetection.resolveBundlingPaths(options); const targetPkg = await fs__default.default.readJson(paths.targetPackageJson); if (options.verifyVersions) { const lockfile = await Lockfile.Lockfile.load( index.paths.resolveTargetRoot("yarn.lock") ); const result = lockfile.analyze({ filter: lint.includedFilter, localPackages: cliNode.PackageGraph.fromPackages( await cliNode.PackageGraph.listTargetPackages() ) }); const problemPackages = [...result.newVersions, ...result.newRanges].map(({ name: name2 }) => name2).filter(lint.forbiddenDuplicatesFilter); if (problemPackages.length > 1) { console.log( chalk__default.default.yellow( `\u26A0\uFE0F Some of the following packages may be outdated or have duplicate installations: ${uniq__default.default(problemPackages).join(", ")} ` ) ); console.log( chalk__default.default.yellow( `\u26A0\uFE0F This can be resolved using the following command: yarn backstage-cli versions:check --fix ` ) ); } if (((_b = (_a = targetPkg.dependencies) == null ? void 0 : _a["react-router"]) == null ? void 0 : _b.includes("beta")) || ((_d = (_c = targetPkg.dependencies) == null ? void 0 : _c["react-router-dom"]) == null ? void 0 : _d.includes("beta"))) { console.warn( chalk__default.default.yellow(` DEPRECATION WARNING: React Router Beta is deprecated and support for it will be removed in a future release. Please migrate to use React Router v6 stable. See https://backstage.io/docs/tutorials/react-router-stable-migration `) ); } } checkReactVersion(); const { name } = await fs__default.default.readJson(index.paths.resolveTarget("package.json")); let webpackServer = void 0; let viteServer = void 0; let latestFrontendAppConfigs = []; const cliConfig = await config.loadCliConfig({ args: options.configPaths, fromPackage: name, withFilteredKeys: true, watch(appConfigs) { latestFrontendAppConfigs = appConfigs; webpackServer == null ? void 0 : webpackServer.invalidate(); viteServer == null ? void 0 : viteServer.restart(); } }); latestFrontendAppConfigs = cliConfig.frontendAppConfigs; const appBaseUrl = cliConfig.frontendConfig.getOptionalString("app.baseUrl"); const backendBaseUrl = cliConfig.frontendConfig.getOptionalString("backend.baseUrl"); if (appBaseUrl && appBaseUrl === backendBaseUrl) { console.log( chalk__default.default.yellow( `\u26A0\uFE0F Conflict between app baseUrl and backend baseUrl: app.baseUrl: ${appBaseUrl} backend.baseUrl: ${backendBaseUrl} Must have unique hostname and/or ports. This can be resolved by changing app.baseUrl and backend.baseUrl to point to their respective local development ports. ` ) ); } const { frontendConfig, fullConfig } = cliConfig; const url = packageDetection.resolveBaseUrl(frontendConfig); const host = frontendConfig.getOptionalString("app.listen.host") || url.hostname; const port = frontendConfig.getOptionalNumber("app.listen.port") || Number(url.port) || (url.protocol === "https:" ? 443 : 80); const detectedModulesEntryPoint = await packageDetection.createDetectedModulesEntryPoint({ config: fullConfig, targetPath: paths.targetPath, watch() { webpackServer == null ? void 0 : webpackServer.invalidate(); viteServer == null ? void 0 : viteServer.restart(); } }); const commonConfigOptions = { ...options, checksEnabled: options.checksEnabled, isDev: true, baseUrl: url, frontendConfig, getFrontendAppConfigs: () => { return latestFrontendAppConfigs; } }; const config$1 = await packageDetection.createConfig(paths, { ...commonConfigOptions, additionalEntryPoints: detectedModulesEntryPoint }); if (process.env.EXPERIMENTAL_VITE) { const { default: vite } = await import('vite'); const { default: viteReact } = await import('@vitejs/plugin-react'); const { nodePolyfills: viteNodePolyfills } = await import('vite-plugin-node-polyfills'); const { createHtmlPlugin: viteHtml } = await import('vite-plugin-html'); viteServer = await vite.createServer({ define: { global: "window", "process.argv": JSON.stringify(process.argv), "process.env.APP_CONFIG": JSON.stringify(cliConfig.frontendAppConfigs), // This allows for conditional imports of react-dom/client, since there's no way // to check for presence of it in source code without module resolution errors. "process.env.HAS_REACT_DOM_CLIENT": JSON.stringify(packageDetection.hasReactDomClient()) }, plugins: [ viteReact(), viteNodePolyfills(), viteHtml({ entry: paths.targetEntry, // todo(blam): we should look at contributing to thPe plugin here // to support absolute paths, but works in the interim at least. template: "public/index.html", inject: { data: { config: frontendConfig, publicPath: (_e = config$1.output) == null ? void 0 : _e.publicPath } } }) ], server: { host, port }, publicDir: paths.targetPublic, root: paths.targetPath }); } else { const publicPaths = await packageDetection.resolveOptionalBundlingPaths({ entry: "src/index-public-experimental", dist: "dist/public" }); if (publicPaths) { console.log( chalk__default.default.yellow( `\u26A0\uFE0F WARNING: The app /public entry point is an experimental feature that may receive immediate breaking changes.` ) ); } const compiler = publicPaths ? webpack__default.default([config$1, await packageDetection.createConfig(publicPaths, commonConfigOptions)]) : webpack__default.default(config$1); webpackServer = new WebpackDevServer__default.default( { hot: !process.env.CI, devMiddleware: { publicPath: (_f = config$1.output) == null ? void 0 : _f.publicPath, stats: "errors-warnings" }, static: paths.targetPublic ? { publicPath: (_g = config$1.output) == null ? void 0 : _g.publicPath, directory: paths.targetPublic } : void 0, historyApiFallback: { // Paths with dots should still use the history fallback. // See https://github.com/facebookincubator/create-react-app/issues/387. disableDotRule: true, // The index needs to be rewritten relative to the new public path, including subroutes. index: `${(_h = config$1.output) == null ? void 0 : _h.publicPath}index.html` }, server: url.protocol === "https:" ? { type: "https", options: { cert: fullConfig.getString("app.https.certificate.cert"), key: fullConfig.getString("app.https.certificate.key") } } : {}, host, port, proxy: targetPkg.proxy, // When the dev server is behind a proxy, the host and public hostname differ allowedHosts: [url.hostname], client: { webSocketURL: "auto://0.0.0.0:0/ws" } }, compiler ); } await (viteServer == null ? void 0 : viteServer.listen()); await new Promise(async (resolve, reject) => { if (webpackServer) { webpackServer.startCallback((err) => { if (err) { reject(err); return; } resolve(); }); } else { resolve(); } }); openBrowser__default.default(url.href); const waitForExit = async () => { for (const signal of ["SIGINT", "SIGTERM"]) { process.on(signal, () => { webpackServer == null ? void 0 : webpackServer.stop(); viteServer == null ? void 0 : viteServer.close(); process.exit(); }); } return new Promise(() => { }); }; return waitForExit; } function checkReactVersion() { try { const reactPkgPath = require.resolve("react/package.json", { paths: [index.paths.targetRoot] }); const reactPkg = require(reactPkgPath); if (reactPkg.version.startsWith("16.")) { console.log( chalk__default.default.yellow( ` \u26A0\uFE0F \u26A0\uFE0F \u26A0\uFE0F You are using React version 16, which is deprecated for use in Backstage. \u26A0\uFE0F \u26A0\uFE0F Please upgrade to React 17 by updating your packages/app dependencies. \u26A0\uFE0F \u26A0\uFE0F \u26A0\uFE0F ` ) ); } } catch { } } var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); setter ? setter.call(obj, value) : member.set(obj, value); return value; }; var __privateWrapper = (obj, member, setter, getter) => ({ set _(value) { __privateSet(obj, member, value, setter); }, get _() { return __privateGet(obj, member, getter); } }); var _generation, _methods; const requestType = "@backstage/cli/channel/request"; const responseType = "@backstage/cli/channel/response"; class IpcServer { constructor() { __privateAdd(this, _generation, 1); __privateAdd(this, _methods, /* @__PURE__ */ new Map()); } addChild(child) { var _a; const generation = __privateWrapper(this, _generation)._++; const sendMessage = (_a = child.send) == null ? void 0 : _a.bind(child); if (!sendMessage) { return; } const messageListener = (request) => { if (request.type !== requestType) { return; } const handler = __privateGet(this, _methods).get(request.method); if (!handler) { sendMessage({ type: responseType, id: request.id, error: { name: "NotFoundError", message: `No handler registered for method ${request.method}` } }); return; } Promise.resolve().then(() => handler(request.body, { generation })).then( (response) => sendMessage({ type: responseType, id: request.id, body: response }) ).catch( (error) => sendMessage({ type: responseType, id: request.id, error: errors.serializeError(error) }) ); }; child.addListener("message", messageListener); child.addListener("exit", () => { child.removeListener("message", messageListener); }); } registerMethod(method, handler) { if (__privateGet(this, _methods).has(method)) { throw new Error(`A handler is already registered for method ${method}`); } __privateGet(this, _methods).set(method, handler); } } _generation = new WeakMap(); _methods = new WeakMap(); class ServerDataStore { static bind(server) { const store = /* @__PURE__ */ new Map(); server.registerMethod( "DevDataStore.save", async (request, { generation }) => { const { key, data } = request; if (!key) { throw new Error("Key is required in DevDataStore.save"); } const item = store.get(key); if (!item) { store.set(key, { generation, data }); return { saved: true }; } if (item.generation > generation) { return { saved: false }; } store.set(key, { generation, data }); return { saved: true }; } ); server.registerMethod( "DevDataStore.load", async (request) => { const item = store.get(request.key); return { loaded: Boolean(item), data: item == null ? void 0 : item.data }; } ); } } const loaderArgs = [ "--enable-source-maps", "--require", require.resolve("@backstage/cli/config/nodeTransform.cjs") // TODO: Support modules, although there's currently no way to load them since import() is transpiled tp require() ]; async function startBackendExperimental(options) { const envEnv = process.env; if (!envEnv.NODE_ENV) { envEnv.NODE_ENV = "development"; } const server = new IpcServer(); ServerDataStore.bind(server); let exiting = false; let firstStart = true; let child; let watcher = void 0; let shutdownPromise = void 0; const watchedPaths = /* @__PURE__ */ new Set(); const restart = debounce__default.default(async () => { if (firstStart) { firstStart = false; } else { console.log(); console.log("Change detected, restarting the development server..."); console.log(); } if (shutdownPromise) { return; } if (child && !child.killed && child.exitCode === null) { shutdownPromise = new Promise((resolve) => child.once("exit", resolve)); if (process.platform === "win32" && child.pid) { ctrlcWindows.ctrlc(child.pid); } else { child.kill(); } await shutdownPromise; shutdownPromise = void 0; } if (exiting) { return; } const optionArgs = new Array(); if (options.inspectEnabled) { const inspect = typeof options.inspectEnabled === "string" ? `--inspect=${options.inspectEnabled}` : "--inspect"; optionArgs.push(inspect); } else if (options.inspectBrkEnabled) { const inspect = typeof options.inspectBrkEnabled === "string" ? `--inspect-brk=${options.inspectBrkEnabled}` : "--inspect-brk"; optionArgs.push(inspect); } const userArgs = process.argv.slice(["node", "backstage-cli", "package", "start"].length).filter((arg) => !optionArgs.includes(arg)); child = spawn__default.default( process.execPath, [...loaderArgs, ...optionArgs, options.entry, ...userArgs], { stdio: ["ignore", "inherit", "inherit", "ipc"], env: { ...process.env, BACKSTAGE_CLI_CHANNEL: "1", ESBK_TSCONFIG_PATH: index.paths.resolveTargetRoot("tsconfig.json") }, serialization: "advanced" } ); server.addChild(child); child.on("message", (data) => { if (!watcher) { return; } if (typeof data === "object" && (data == null ? void 0 : data.type) === "watch") { let path$1 = data.path; if (path$1.startsWith("file:")) { path$1 = url.fileURLToPath(path$1); } if (path.isAbsolute(path$1) && !watchedPaths.has(path$1)) { watchedPaths.add(path$1); watcher.add(path$1); } } }); }, 100); restart(); watcher = chokidar.watch(["./package.json"], { cwd: process.cwd(), ignoreInitial: true, ignorePermissionErrors: true }).on("all", restart); process.stdin.on("data", restart); const exitPromise = new Promise((resolveExitPromise) => { async function handleSignal(signal) { exiting = true; if (child && child.exitCode === null) { await new Promise((resolve) => { child.on("close", resolve); child.kill(signal); }); } resolveExitPromise(); } process.once("SIGINT", handleSignal); process.once("SIGTERM", handleSignal); }); return () => exitPromise; } async function startBackend(options) { if (!process.env.LEGACY_BACKEND_START) { const waitForExit = await startBackendExperimental({ entry: "src/index", checksEnabled: false, // not supported inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled }); await waitForExit(); } else { const waitForExit = await cleanDistAndServeBackend({ entry: "src/index", checksEnabled: options.checksEnabled, inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled }); await waitForExit(); } } async function startBackendPlugin(options) { if (!process.env.LEGACY_BACKEND_START) { const hasDevIndexEntry = await fs__default.default.pathExists( index.paths.resolveTarget("dev", "index.ts") ); const hasSrcIndexEntry = await fs__default.default.pathExists( index.paths.resolveTarget("src", "run.ts") ); if (!hasDevIndexEntry && !hasSrcIndexEntry) { console.warn( hasSrcIndexEntry ? `The 'dev' directory is missing. The plugin might not be updated for the new backend system. To run, use "LEGACY_BACKEND_START=1 yarn start".` : `The 'dev' directory is missing. Please create a proper dev/index.ts in order to start the plugin.` ); return; } const waitForExit = await startBackendExperimental({ entry: "dev/index", checksEnabled: false, // not supported inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled }); await waitForExit(); } else { const hasEntry = await fs__default.default.pathExists(index.paths.resolveTarget("src", "run.ts")); if (!hasEntry) { console.warn( `src/run.ts is missing. Please create the file or run the command without LEGACY_BACKEND_START` ); return; } const waitForExit = await cleanDistAndServeBackend({ entry: "src/run", checksEnabled: options.checksEnabled, inspectEnabled: options.inspectEnabled, inspectBrkEnabled: options.inspectBrkEnabled }); await waitForExit(); } } async function cleanDistAndServeBackend(options) { await fs__default.default.remove(index.paths.resolveTarget("dist")); return serveBackend(options); } async function startFrontend(options) { const waitForExit = await serveBundle({ entry: options.entry, checksEnabled: options.checksEnabled, configPaths: options.configPaths, verifyVersions: options.verifyVersions }); await waitForExit(); } async function command(opts) { const role$1 = await role.findRoleFromCommand(opts); const options = { configPaths: opts.config, checksEnabled: Boolean(opts.check), inspectEnabled: opts.inspect, inspectBrkEnabled: opts.inspectBrk }; switch (role$1) { case "backend": return startBackend(options); case "backend-plugin": case "backend-plugin-module": case "node-library": return startBackendPlugin(options); case "frontend": return startFrontend({ ...options, entry: "src/index", verifyVersions: true }); case "web-library": case "frontend-plugin": case "frontend-plugin-module": return startFrontend({ entry: "dev/index", ...options }); default: throw new Error( `Start command is not supported for package role '${role$1}'` ); } } exports.command = command; //# sourceMappingURL=index-BVuheGHy.cjs.js.map