cli: remove legacy backend start
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `LEGACY_BACKEND_START` flag has been removed, along with support for `src/run.ts` as the development entry point.
|
||||
@@ -141,7 +141,6 @@
|
||||
"rollup-plugin-esbuild": "^6.1.1",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-pluginutils": "^2.8.2",
|
||||
"run-script-webpack-plugin": "^0.2.0",
|
||||
"semver": "^7.5.3",
|
||||
"style-loader": "^3.3.1",
|
||||
"sucrase": "^3.20.2",
|
||||
@@ -152,7 +151,6 @@
|
||||
"util": "^0.12.3",
|
||||
"webpack": "^5.70.0",
|
||||
"webpack-dev-server": "^5.0.0",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"yaml": "^2.0.0",
|
||||
"yargs": "^16.2.0",
|
||||
"yml-loader": "^2.1.0",
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import { paths } from '../../lib/paths';
|
||||
import { serveBackend } from '../../lib/bundler';
|
||||
import { startBackendExperimental } from '../../lib/experimental/startBackendExperimental';
|
||||
|
||||
interface StartBackendOptions {
|
||||
@@ -27,89 +26,35 @@ interface StartBackendOptions {
|
||||
}
|
||||
|
||||
export async function startBackend(options: StartBackendOptions) {
|
||||
if (!process.env.LEGACY_BACKEND_START) {
|
||||
const waitForExit = await startBackendExperimental({
|
||||
entry: 'src/index',
|
||||
checksEnabled: false, // not supported
|
||||
inspectEnabled: options.inspectEnabled,
|
||||
inspectBrkEnabled: options.inspectBrkEnabled,
|
||||
require: options.require,
|
||||
});
|
||||
const waitForExit = await startBackendExperimental({
|
||||
entry: 'src/index',
|
||||
checksEnabled: false, // not supported
|
||||
inspectEnabled: options.inspectEnabled,
|
||||
inspectBrkEnabled: options.inspectBrkEnabled,
|
||||
require: options.require,
|
||||
});
|
||||
|
||||
await waitForExit();
|
||||
} else {
|
||||
console.warn(
|
||||
'LEGACY_BACKEND_START is deprecated and will be removed in a future release',
|
||||
);
|
||||
|
||||
const waitForExit = await cleanDistAndServeBackend({
|
||||
entry: 'src/index',
|
||||
checksEnabled: options.checksEnabled,
|
||||
inspectEnabled: options.inspectEnabled,
|
||||
inspectBrkEnabled: options.inspectBrkEnabled,
|
||||
require: options.require,
|
||||
});
|
||||
|
||||
await waitForExit();
|
||||
}
|
||||
await waitForExit();
|
||||
}
|
||||
|
||||
export async function startBackendPlugin(options: StartBackendOptions) {
|
||||
if (!process.env.LEGACY_BACKEND_START) {
|
||||
const hasDevIndexEntry = await fs.pathExists(
|
||||
paths.resolveTarget('dev', 'index.ts'),
|
||||
);
|
||||
if (!hasDevIndexEntry) {
|
||||
console.warn(
|
||||
`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,
|
||||
require: options.require,
|
||||
});
|
||||
|
||||
await waitForExit();
|
||||
} else {
|
||||
const hasEntry = await fs.pathExists(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 hasDevIndexEntry = await fs.pathExists(
|
||||
paths.resolveTarget('dev', 'index.ts'),
|
||||
);
|
||||
if (!hasDevIndexEntry) {
|
||||
console.warn(
|
||||
'LEGACY_BACKEND_START is deprecated and will be removed in a future release',
|
||||
`The 'dev' directory is missing. Please create a proper dev/index.ts in order to start the plugin.`,
|
||||
);
|
||||
|
||||
const waitForExit = await cleanDistAndServeBackend({
|
||||
entry: 'src/run',
|
||||
checksEnabled: options.checksEnabled,
|
||||
inspectEnabled: options.inspectEnabled,
|
||||
inspectBrkEnabled: options.inspectBrkEnabled,
|
||||
require: options.require,
|
||||
});
|
||||
|
||||
await waitForExit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function cleanDistAndServeBackend(options: {
|
||||
entry: string;
|
||||
checksEnabled: boolean;
|
||||
inspectEnabled: boolean;
|
||||
inspectBrkEnabled: boolean;
|
||||
require?: string;
|
||||
}) {
|
||||
// Cleaning dist/ before we start the dev process helps work around an issue
|
||||
// where we end up with the entrypoint executing multiple times, causing
|
||||
// a port bind conflict among other things.
|
||||
await fs.remove(paths.resolveTarget('dist'));
|
||||
const waitForExit = await startBackendExperimental({
|
||||
entry: 'dev/index',
|
||||
checksEnabled: false, // not supported
|
||||
inspectEnabled: options.inspectEnabled,
|
||||
inspectBrkEnabled: options.inspectBrkEnabled,
|
||||
require: options.require,
|
||||
});
|
||||
|
||||
return serveBackend(options);
|
||||
await waitForExit();
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import webpack from 'webpack';
|
||||
import { createBackendConfig } from './config';
|
||||
import { resolveBundlingPaths } from './paths';
|
||||
import { BackendServeOptions } from './types';
|
||||
|
||||
export async function serveBackend(options: BackendServeOptions) {
|
||||
const paths = resolveBundlingPaths(options);
|
||||
const config = await createBackendConfig(paths, {
|
||||
...options,
|
||||
isDev: true,
|
||||
});
|
||||
|
||||
// Webpack only replaces occurrences of this in code it touches, which does
|
||||
// not include dependencies in node_modules. So we set it here at runtime as well.
|
||||
(process.env as { NODE_ENV: string }).NODE_ENV = 'development';
|
||||
|
||||
const compiler = webpack(config, (err: Error | null) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else console.log('Build succeeded');
|
||||
});
|
||||
|
||||
const waitForExit = async () => {
|
||||
for (const signal of ['SIGINT', 'SIGTERM'] as const) {
|
||||
process.on(signal, () => {
|
||||
// exit instead of resolve. The process is shutting down and resolving a promise here logs an error
|
||||
compiler.close(() => process.exit());
|
||||
});
|
||||
}
|
||||
|
||||
// Block indefinitely and wait for the interrupt signal
|
||||
return new Promise(() => {});
|
||||
};
|
||||
|
||||
return waitForExit;
|
||||
}
|
||||
@@ -14,16 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
BackendBundlingOptions,
|
||||
BundlingOptions,
|
||||
ModuleFederationOptions,
|
||||
} from './types';
|
||||
import { posix as posixPath, resolve as resolvePath, dirname } from 'path';
|
||||
import { BundlingOptions, ModuleFederationOptions } from './types';
|
||||
import { resolve as resolvePath, dirname } from 'path';
|
||||
import chalk from 'chalk';
|
||||
import webpack, { ProvidePlugin } from 'webpack';
|
||||
|
||||
import { BackstagePackage } from '@backstage/cli-node';
|
||||
import { BundlingPaths } from './paths';
|
||||
import { Config } from '@backstage/config';
|
||||
import ESLintPlugin from 'eslint-webpack-plugin';
|
||||
@@ -32,16 +27,13 @@ import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
|
||||
import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin';
|
||||
import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin';
|
||||
import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin';
|
||||
import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||
import { paths as cliPaths } from '../../lib/paths';
|
||||
import fs from 'fs-extra';
|
||||
import { getPackages } from '@manypkg/get-packages';
|
||||
import { isChildPath } from '@backstage/cli-common';
|
||||
import nodeExternals from 'webpack-node-externals';
|
||||
import { optimization as optimizationConfig } from './optimization';
|
||||
import pickBy from 'lodash/pickBy';
|
||||
import { readEntryPoints } from '../entryPoints';
|
||||
import { runPlain } from '../run';
|
||||
import { transforms } from './transforms';
|
||||
import { version } from '../../lib/version';
|
||||
@@ -432,154 +424,3 @@ export async function createConfig(
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
export async function createBackendConfig(
|
||||
paths: BundlingPaths,
|
||||
options: BackendBundlingOptions,
|
||||
): Promise<webpack.Configuration> {
|
||||
const { checksEnabled, isDev } = options;
|
||||
|
||||
// Find all local monorepo packages and their node_modules, and mark them as external.
|
||||
const { packages } = await getPackages(cliPaths.targetDir);
|
||||
const localPackageEntryPoints = packages.flatMap(p => {
|
||||
const entryPoints = readEntryPoints((p as BackstagePackage).packageJson);
|
||||
return entryPoints.map(e => posixPath.join(p.packageJson.name, e.mount));
|
||||
});
|
||||
const moduleDirs = packages.map(p => resolvePath(p.dir, 'node_modules'));
|
||||
// See frontend config
|
||||
const externalPkgs = packages.filter(p => !isChildPath(paths.root, p.dir));
|
||||
|
||||
const { loaders } = transforms({ ...options, isBackend: true });
|
||||
|
||||
const runScriptNodeArgs = new Array<string>();
|
||||
if (options.inspectEnabled) {
|
||||
const inspect =
|
||||
typeof options.inspectEnabled === 'string'
|
||||
? `--inspect=${options.inspectEnabled}`
|
||||
: '--inspect';
|
||||
runScriptNodeArgs.push(inspect);
|
||||
} else if (options.inspectBrkEnabled) {
|
||||
const inspect =
|
||||
typeof options.inspectBrkEnabled === 'string'
|
||||
? `--inspect-brk=${options.inspectBrkEnabled}`
|
||||
: '--inspect-brk';
|
||||
runScriptNodeArgs.push(inspect);
|
||||
}
|
||||
if (options.require) {
|
||||
runScriptNodeArgs.push(`--require=${options.require}`);
|
||||
}
|
||||
|
||||
return {
|
||||
mode: isDev ? 'development' : 'production',
|
||||
profile: false,
|
||||
...(isDev
|
||||
? {
|
||||
watch: true,
|
||||
watchOptions: {
|
||||
ignored: /node_modules\/(?!\@backstage)/,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
externals: [
|
||||
nodeExternalsWithResolve({
|
||||
modulesDir: paths.rootNodeModules,
|
||||
additionalModuleDirs: moduleDirs,
|
||||
allowlist: ['webpack/hot/poll?100', ...localPackageEntryPoints],
|
||||
}),
|
||||
],
|
||||
target: 'node' as const,
|
||||
node: {
|
||||
/* eslint-disable-next-line no-restricted-syntax */
|
||||
__dirname: true,
|
||||
__filename: true,
|
||||
global: true,
|
||||
},
|
||||
bail: false,
|
||||
performance: {
|
||||
hints: false, // we check the gzip size instead
|
||||
},
|
||||
devtool: isDev ? 'eval-cheap-module-source-map' : 'source-map',
|
||||
context: paths.targetPath,
|
||||
entry: [
|
||||
'webpack/hot/poll?100',
|
||||
paths.targetRunFile ? paths.targetRunFile : paths.targetEntry,
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.ts', '.mjs', '.js', '.json'],
|
||||
mainFields: ['main'],
|
||||
modules: [paths.rootNodeModules, ...moduleDirs],
|
||||
plugins: [
|
||||
new LinkedPackageResolvePlugin(paths.rootNodeModules, externalPkgs),
|
||||
new ModuleScopePlugin(
|
||||
[paths.targetSrc, paths.targetDev],
|
||||
[paths.targetPackageJson],
|
||||
),
|
||||
],
|
||||
},
|
||||
module: {
|
||||
rules: loaders,
|
||||
},
|
||||
output: {
|
||||
path: paths.targetDist,
|
||||
filename: isDev ? '[name].js' : '[name].[hash:8].js',
|
||||
chunkFilename: isDev
|
||||
? '[name].chunk.js'
|
||||
: '[name].[chunkhash:8].chunk.js',
|
||||
...(isDev
|
||||
? {
|
||||
devtoolModuleFilenameTemplate: (info: any) =>
|
||||
`file:///${resolvePath(info.absoluteResourcePath).replace(
|
||||
/\\/g,
|
||||
'/',
|
||||
)}`,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
plugins: [
|
||||
new RunScriptWebpackPlugin({
|
||||
name: 'main.js',
|
||||
nodeArgs: runScriptNodeArgs.length > 0 ? runScriptNodeArgs : undefined,
|
||||
args: process.argv.slice(3), // drop `node backstage-cli backend:dev`
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
...(checksEnabled
|
||||
? [
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: { configFile: paths.targetTsConfig },
|
||||
}),
|
||||
new ESLintPlugin({
|
||||
files: ['**/*.(ts|tsx|mts|cts|js|jsx|mjs|cjs)'],
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// This makes the module resolution happen from the context of each non-external module, rather
|
||||
// than the main entrypoint. This fixes a bug where dependencies would be resolved from the backend
|
||||
// package rather than each individual backend package and plugin.
|
||||
//
|
||||
// TODO(Rugvip): Feature suggestion/contribute this to webpack-externals
|
||||
function nodeExternalsWithResolve(
|
||||
options: Parameters<typeof nodeExternals>[0],
|
||||
) {
|
||||
let currentContext: string;
|
||||
const externals = nodeExternals({
|
||||
...options,
|
||||
importType(request) {
|
||||
const resolved = require.resolve(request, {
|
||||
paths: [currentContext],
|
||||
});
|
||||
return `commonjs ${resolved}`;
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
{ context, request }: { context?: string; request?: string },
|
||||
callback: any,
|
||||
) => {
|
||||
currentContext = context!;
|
||||
return externals(context, request, callback);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { serveBackend } from './backend';
|
||||
export { buildBundle } from './bundle';
|
||||
export { getModuleFederationOptions } from './moduleFederation';
|
||||
export { serveBundle } from './server';
|
||||
|
||||
@@ -4037,7 +4037,6 @@ __metadata:
|
||||
rollup-plugin-esbuild: ^6.1.1
|
||||
rollup-plugin-postcss: ^4.0.0
|
||||
rollup-pluginutils: ^2.8.2
|
||||
run-script-webpack-plugin: ^0.2.0
|
||||
semver: ^7.5.3
|
||||
style-loader: ^3.3.1
|
||||
sucrase: ^3.20.2
|
||||
@@ -4051,7 +4050,6 @@ __metadata:
|
||||
vite-plugin-node-polyfills: ^0.22.0
|
||||
webpack: ^5.70.0
|
||||
webpack-dev-server: ^5.0.0
|
||||
webpack-node-externals: ^3.0.0
|
||||
yaml: ^2.0.0
|
||||
yargs: ^16.2.0
|
||||
yml-loader: ^2.1.0
|
||||
@@ -40212,13 +40210,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"run-script-webpack-plugin@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "run-script-webpack-plugin@npm:0.2.0"
|
||||
checksum: 1f5df65b726e098d602b4cc27472d9e2cd88841862f7ca2112f702b01f3c4fc1cd89b54fa63780691d988c9ab36cc9adc08a6fa056cdb9c7b85b027b21ba6cdd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rxjs@npm:7.8.1, rxjs@npm:^7.2.0, rxjs@npm:^7.5.5":
|
||||
version: 7.8.1
|
||||
resolution: "rxjs@npm:7.8.1"
|
||||
@@ -44521,13 +44512,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webpack-node-externals@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "webpack-node-externals@npm:3.0.0"
|
||||
checksum: 355080c35c821115b97dda8c93d9d0565a90a6012a532324eb0d6a64f8f0d609431fd29504fc7ce414755841ac14f601f3eef99472c2c5dc00233b504ebe73f2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webpack-sources@npm:^1.4.3":
|
||||
version: 1.4.3
|
||||
resolution: "webpack-sources@npm:1.4.3"
|
||||
|
||||
Reference in New Issue
Block a user