1 | 'use strict';
|
2 |
|
3 | var fs = require('fs-extra');
|
4 | var path = require('path');
|
5 | var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
6 | var HtmlWebpackPlugin = require('html-webpack-plugin');
|
7 | var ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
8 | var runScriptWebpackPlugin = require('run-script-webpack-plugin');
|
9 | var webpack = require('webpack');
|
10 | var nodeExternals = require('webpack-node-externals');
|
11 | var cliCommon = require('@backstage/cli-common');
|
12 | var getPackages = require('@manypkg/get-packages');
|
13 | var MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
14 | var svgrTemplate = require('./svgrTemplate-550efce6.cjs.js');
|
15 | var index = require('./index-09611511.cjs.js');
|
16 | var run = require('./run-a95417b1.cjs.js');
|
17 | var ESLintPlugin = require('eslint-webpack-plugin');
|
18 | var pickBy = require('lodash/pickBy');
|
19 |
|
20 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
21 |
|
22 | var fs__default = _interopDefaultLegacy(fs);
|
23 | var ForkTsCheckerWebpackPlugin__default = _interopDefaultLegacy(ForkTsCheckerWebpackPlugin);
|
24 | var HtmlWebpackPlugin__default = _interopDefaultLegacy(HtmlWebpackPlugin);
|
25 | var ModuleScopePlugin__default = _interopDefaultLegacy(ModuleScopePlugin);
|
26 | var webpack__default = _interopDefaultLegacy(webpack);
|
27 | var nodeExternals__default = _interopDefaultLegacy(nodeExternals);
|
28 | var MiniCssExtractPlugin__default = _interopDefaultLegacy(MiniCssExtractPlugin);
|
29 | var ESLintPlugin__default = _interopDefaultLegacy(ESLintPlugin);
|
30 | var pickBy__default = _interopDefaultLegacy(pickBy);
|
31 |
|
32 | const { ESBuildMinifyPlugin } = require("esbuild-loader");
|
33 | const optimization = (options) => {
|
34 | const { isDev } = options;
|
35 | return {
|
36 | minimize: !isDev,
|
37 | minimizer: [
|
38 | new ESBuildMinifyPlugin({
|
39 | target: "es2019",
|
40 | format: "iife"
|
41 | })
|
42 | ],
|
43 | runtimeChunk: "single",
|
44 | splitChunks: {
|
45 | automaticNameDelimiter: "-",
|
46 | cacheGroups: {
|
47 | default: false,
|
48 | packages: {
|
49 | chunks: "initial",
|
50 | test(module) {
|
51 | var _a;
|
52 | return Boolean((_a = module == null ? void 0 : module.resource) == null ? void 0 : _a.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/));
|
53 | },
|
54 | name(module) {
|
55 | const packageName = module.resource.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
|
56 | return packageName.replace("@", "");
|
57 | },
|
58 | filename: isDev ? "module-[name].js" : "static/module-[name].[chunkhash:8].js",
|
59 | priority: 10,
|
60 | minSize: 1e5,
|
61 | minChunks: 1,
|
62 | maxAsyncRequests: Infinity,
|
63 | maxInitialRequests: Infinity
|
64 | },
|
65 | vendor: {
|
66 | chunks: "initial",
|
67 | test: /[\\/]node_modules[\\/]/,
|
68 | name: "vendor",
|
69 | priority: 5,
|
70 | enforce: true
|
71 | }
|
72 | }
|
73 | }
|
74 | };
|
75 | };
|
76 |
|
77 | const transforms = (options) => {
|
78 | const { isDev, isBackend } = options;
|
79 | const extraTransforms = isDev && !isBackend ? ["react-hot-loader"] : [];
|
80 | function insertBeforeJssStyles(element) {
|
81 | const head = document.head;
|
82 | const firstJssNode = head.querySelector("style[data-jss]");
|
83 | if (!firstJssNode) {
|
84 | head.appendChild(element);
|
85 | } else {
|
86 | head.insertBefore(element, firstJssNode);
|
87 | }
|
88 | }
|
89 | const loaders = [
|
90 | {
|
91 | test: /\.(tsx?)$/,
|
92 | exclude: /node_modules/,
|
93 | loader: require.resolve("@sucrase/webpack-loader"),
|
94 | options: {
|
95 | transforms: ["typescript", "jsx", ...extraTransforms],
|
96 | disableESTransforms: true,
|
97 | production: !isDev
|
98 | }
|
99 | },
|
100 | {
|
101 | test: /\.(jsx?|mjs|cjs)$/,
|
102 | exclude: /node_modules/,
|
103 | loader: require.resolve("@sucrase/webpack-loader"),
|
104 | options: {
|
105 | transforms: ["jsx", ...extraTransforms],
|
106 | disableESTransforms: true,
|
107 | production: !isDev
|
108 | }
|
109 | },
|
110 | {
|
111 | test: /\.(js|mjs|cjs)/,
|
112 | resolve: {
|
113 | fullySpecified: false
|
114 | }
|
115 | },
|
116 | {
|
117 | test: [/\.icon\.svg$/],
|
118 | use: [
|
119 | {
|
120 | loader: require.resolve("@sucrase/webpack-loader"),
|
121 | options: {
|
122 | transforms: ["jsx", ...extraTransforms],
|
123 | disableESTransforms: true,
|
124 | production: !isDev
|
125 | }
|
126 | },
|
127 | {
|
128 | loader: require.resolve("@svgr/webpack"),
|
129 | options: { babel: false, template: svgrTemplate.svgrTemplate }
|
130 | }
|
131 | ]
|
132 | },
|
133 | {
|
134 | test: [
|
135 | /\.bmp$/,
|
136 | /\.gif$/,
|
137 | /\.jpe?g$/,
|
138 | /\.png$/,
|
139 | /\.frag/,
|
140 | { and: [/\.svg/, { not: [/\.icon\.svg/] }] },
|
141 | /\.xml/
|
142 | ],
|
143 | type: "asset/resource",
|
144 | generator: {
|
145 | filename: "static/[name].[hash:8].[ext]"
|
146 | }
|
147 | },
|
148 | {
|
149 | test: /\.(eot|woff|woff2|ttf)$/i,
|
150 | type: "asset/resource",
|
151 | generator: {
|
152 | filename: "static/[name].[hash][ext][query]"
|
153 | }
|
154 | },
|
155 | {
|
156 | test: /\.ya?ml$/,
|
157 | use: require.resolve("yml-loader")
|
158 | },
|
159 | {
|
160 | include: /\.(md)$/,
|
161 | type: "asset/resource",
|
162 | generator: {
|
163 | filename: "static/[name].[hash][ext][query]"
|
164 | }
|
165 | },
|
166 | {
|
167 | test: /\.css$/i,
|
168 | use: [
|
169 | isDev ? {
|
170 | loader: require.resolve("style-loader"),
|
171 | options: {
|
172 | insert: insertBeforeJssStyles
|
173 | }
|
174 | } : MiniCssExtractPlugin__default["default"].loader,
|
175 | {
|
176 | loader: require.resolve("css-loader"),
|
177 | options: {
|
178 | sourceMap: true
|
179 | }
|
180 | }
|
181 | ]
|
182 | }
|
183 | ];
|
184 | const plugins = new Array();
|
185 | if (isDev) {
|
186 | plugins.push(new webpack__default["default"].HotModuleReplacementPlugin());
|
187 | } else {
|
188 | plugins.push(new MiniCssExtractPlugin__default["default"]({
|
189 | filename: "static/[name].[contenthash:8].css",
|
190 | chunkFilename: "static/[name].[id].[contenthash:8].css",
|
191 | insert: insertBeforeJssStyles
|
192 | }));
|
193 | }
|
194 | return { loaders, plugins };
|
195 | };
|
196 |
|
197 | class LinkedPackageResolvePlugin {
|
198 | constructor(targetModules, packages) {
|
199 | this.targetModules = targetModules;
|
200 | this.packages = packages;
|
201 | }
|
202 | apply(resolver) {
|
203 | resolver.hooks.resolve.tapAsync("LinkedPackageResolvePlugin", (data, context, callback) => {
|
204 | var _a;
|
205 | const pkg = this.packages.find((pkge) => data.path && cliCommon.isChildPath(pkge.dir, data.path));
|
206 | if (!pkg) {
|
207 | callback();
|
208 | return;
|
209 | }
|
210 | const modulesLocation = path.resolve(this.targetModules, pkg.packageJson.name);
|
211 | const newContext = ((_a = data.context) == null ? void 0 : _a.issuer) ? {
|
212 | ...data.context,
|
213 | issuer: data.context.issuer.replace(pkg.dir, modulesLocation)
|
214 | } : data.context;
|
215 | resolver.doResolve(resolver.hooks.resolve, {
|
216 | ...data,
|
217 | context: newContext,
|
218 | path: data.path && data.path.replace(pkg.dir, modulesLocation)
|
219 | }, `resolve ${data.request} in ${modulesLocation}`, context, callback);
|
220 | });
|
221 | }
|
222 | }
|
223 |
|
224 | function resolveBaseUrl(config) {
|
225 | const baseUrl = config.getString("app.baseUrl");
|
226 | try {
|
227 | return new URL(baseUrl);
|
228 | } catch (error) {
|
229 | throw new Error(`Invalid app.baseUrl, ${error}`);
|
230 | }
|
231 | }
|
232 | async function readBuildInfo() {
|
233 | const timestamp = Date.now();
|
234 | let commit = "unknown";
|
235 | try {
|
236 | commit = await run.runPlain("git", "rev-parse", "HEAD");
|
237 | } catch (error) {
|
238 | console.warn(`WARNING: Failed to read git commit, ${error}`);
|
239 | }
|
240 | let gitVersion = "unknown";
|
241 | try {
|
242 | gitVersion = await run.runPlain("git", "describe", "--always");
|
243 | } catch (error) {
|
244 | console.warn(`WARNING: Failed to describe git version, ${error}`);
|
245 | }
|
246 | const { version: packageVersion } = await fs__default["default"].readJson(index.paths.resolveTarget("package.json"));
|
247 | return {
|
248 | cliVersion: index.version,
|
249 | gitVersion,
|
250 | packageVersion,
|
251 | timestamp,
|
252 | commit
|
253 | };
|
254 | }
|
255 | async function createConfig(paths, options) {
|
256 | const { checksEnabled, isDev, frontendConfig } = options;
|
257 | const { plugins, loaders } = transforms(options);
|
258 | const { packages } = await getPackages.getPackages(index.paths.targetDir);
|
259 | const externalPkgs = packages.filter((p) => !cliCommon.isChildPath(paths.root, p.dir));
|
260 | const baseUrl = frontendConfig.getString("app.baseUrl");
|
261 | const validBaseUrl = new URL(baseUrl);
|
262 | const publicPath = validBaseUrl.pathname.replace(/\/$/, "");
|
263 | if (checksEnabled) {
|
264 | plugins.push(new ForkTsCheckerWebpackPlugin__default["default"]({
|
265 | typescript: { configFile: paths.targetTsConfig, memoryLimit: 4096 }
|
266 | }), new ESLintPlugin__default["default"]({
|
267 | context: paths.targetPath,
|
268 | files: ["**", "!**/__tests__/**", "!**/?(*.)(spec|test).*"]
|
269 | }));
|
270 | }
|
271 | plugins.push(new webpack.ProvidePlugin({
|
272 | process: "process/browser",
|
273 | Buffer: ["buffer", "Buffer"]
|
274 | }));
|
275 | plugins.push(new webpack__default["default"].EnvironmentPlugin({
|
276 | APP_CONFIG: options.frontendAppConfigs
|
277 | }));
|
278 | plugins.push(new HtmlWebpackPlugin__default["default"]({
|
279 | template: paths.targetHtml,
|
280 | templateParameters: {
|
281 | publicPath,
|
282 | config: frontendConfig
|
283 | }
|
284 | }));
|
285 | const buildInfo = await readBuildInfo();
|
286 | plugins.push(new webpack__default["default"].DefinePlugin({
|
287 | "process.env.BUILD_INFO": JSON.stringify(buildInfo)
|
288 | }));
|
289 | const resolveAliases = {};
|
290 | try {
|
291 | const { version: reactDomVersion } = require("react-dom/package.json");
|
292 | if (reactDomVersion.startsWith("16.")) {
|
293 | resolveAliases["react-dom"] = "@hot-loader/react-dom-v16";
|
294 | } else {
|
295 | resolveAliases["react-dom"] = "@hot-loader/react-dom-v17";
|
296 | }
|
297 | } catch (error) {
|
298 | console.warn(`WARNING: Failed to read react-dom version, ${error}`);
|
299 | }
|
300 | return {
|
301 | mode: isDev ? "development" : "production",
|
302 | profile: false,
|
303 | optimization: optimization(options),
|
304 | bail: false,
|
305 | performance: {
|
306 | hints: false
|
307 | },
|
308 | devtool: isDev ? "eval-cheap-module-source-map" : "source-map",
|
309 | context: paths.targetPath,
|
310 | entry: [require.resolve("react-hot-loader/patch"), paths.targetEntry],
|
311 | resolve: {
|
312 | extensions: [".ts", ".tsx", ".mjs", ".js", ".jsx"],
|
313 | mainFields: ["browser", "module", "main"],
|
314 | fallback: {
|
315 | ...pickBy__default["default"](require("node-libs-browser")),
|
316 | module: false,
|
317 | dgram: false,
|
318 | dns: false,
|
319 | fs: false,
|
320 | http2: false,
|
321 | net: false,
|
322 | tls: false,
|
323 | child_process: false,
|
324 | path: false,
|
325 | https: false,
|
326 | http: false,
|
327 | util: require.resolve("util/")
|
328 | },
|
329 | plugins: [
|
330 | new LinkedPackageResolvePlugin(paths.rootNodeModules, externalPkgs),
|
331 | new ModuleScopePlugin__default["default"]([paths.targetSrc, paths.targetDev], [paths.targetPackageJson])
|
332 | ],
|
333 | alias: resolveAliases
|
334 | },
|
335 | module: {
|
336 | rules: loaders
|
337 | },
|
338 | output: {
|
339 | path: paths.targetDist,
|
340 | publicPath: `${publicPath}/`,
|
341 | filename: isDev ? "[name].js" : "static/[name].[fullhash:8].js",
|
342 | chunkFilename: isDev ? "[name].chunk.js" : "static/[name].[chunkhash:8].chunk.js",
|
343 | ...isDev ? {
|
344 | devtoolModuleFilenameTemplate: (info) => `file:///${path.resolve(info.absoluteResourcePath).replace(/\\/g, "/")}`
|
345 | } : {}
|
346 | },
|
347 | plugins
|
348 | };
|
349 | }
|
350 | async function createBackendConfig(paths, options) {
|
351 | const { checksEnabled, isDev } = options;
|
352 | const { packages } = await getPackages.getPackages(index.paths.targetDir);
|
353 | const localPackageNames = packages.map((p) => p.packageJson.name);
|
354 | const moduleDirs = packages.map((p) => path.resolve(p.dir, "node_modules"));
|
355 | const externalPkgs = packages.filter((p) => !cliCommon.isChildPath(paths.root, p.dir));
|
356 | const { loaders } = transforms({ ...options, isBackend: true });
|
357 | const runScriptNodeArgs = new Array();
|
358 | if (options.inspectEnabled) {
|
359 | runScriptNodeArgs.push("--inspect");
|
360 | } else if (options.inspectBrkEnabled) {
|
361 | runScriptNodeArgs.push("--inspect-brk");
|
362 | }
|
363 | return {
|
364 | mode: isDev ? "development" : "production",
|
365 | profile: false,
|
366 | ...isDev ? {
|
367 | watch: true,
|
368 | watchOptions: {
|
369 | ignored: /node_modules\/(?!\@backstage)/
|
370 | }
|
371 | } : {},
|
372 | externals: [
|
373 | nodeExternalsWithResolve({
|
374 | modulesDir: paths.rootNodeModules,
|
375 | additionalModuleDirs: moduleDirs,
|
376 | allowlist: ["webpack/hot/poll?100", ...localPackageNames]
|
377 | })
|
378 | ],
|
379 | target: "node",
|
380 | node: {
|
381 | __dirname: true,
|
382 | __filename: true,
|
383 | global: true
|
384 | },
|
385 | bail: false,
|
386 | performance: {
|
387 | hints: false
|
388 | },
|
389 | devtool: isDev ? "eval-cheap-module-source-map" : "source-map",
|
390 | context: paths.targetPath,
|
391 | entry: [
|
392 | "webpack/hot/poll?100",
|
393 | paths.targetRunFile ? paths.targetRunFile : paths.targetEntry
|
394 | ],
|
395 | resolve: {
|
396 | extensions: [".ts", ".tsx", ".mjs", ".js", ".jsx"],
|
397 | mainFields: ["main"],
|
398 | modules: [paths.rootNodeModules, ...moduleDirs],
|
399 | plugins: [
|
400 | new LinkedPackageResolvePlugin(paths.rootNodeModules, externalPkgs),
|
401 | new ModuleScopePlugin__default["default"]([paths.targetSrc, paths.targetDev], [paths.targetPackageJson])
|
402 | ],
|
403 | alias: {
|
404 | "react-dom": "@hot-loader/react-dom"
|
405 | }
|
406 | },
|
407 | module: {
|
408 | rules: loaders
|
409 | },
|
410 | output: {
|
411 | path: paths.targetDist,
|
412 | filename: isDev ? "[name].js" : "[name].[hash:8].js",
|
413 | chunkFilename: isDev ? "[name].chunk.js" : "[name].[chunkhash:8].chunk.js",
|
414 | ...isDev ? {
|
415 | devtoolModuleFilenameTemplate: (info) => `file:///${path.resolve(info.absoluteResourcePath).replace(/\\/g, "/")}`
|
416 | } : {}
|
417 | },
|
418 | plugins: [
|
419 | new runScriptWebpackPlugin.RunScriptWebpackPlugin({
|
420 | name: "main.js",
|
421 | nodeArgs: runScriptNodeArgs.length > 0 ? runScriptNodeArgs : void 0,
|
422 | args: process.argv.slice(3)
|
423 | }),
|
424 | new webpack__default["default"].HotModuleReplacementPlugin(),
|
425 | ...checksEnabled ? [
|
426 | new ForkTsCheckerWebpackPlugin__default["default"]({
|
427 | typescript: { configFile: paths.targetTsConfig }
|
428 | }),
|
429 | new ESLintPlugin__default["default"]({
|
430 | files: ["**", "!**/__tests__/**", "!**/?(*.)(spec|test).*"]
|
431 | })
|
432 | ] : []
|
433 | ]
|
434 | };
|
435 | }
|
436 | function nodeExternalsWithResolve(options) {
|
437 | let currentContext;
|
438 | const externals = nodeExternals__default["default"]({
|
439 | ...options,
|
440 | importType(request) {
|
441 | const resolved = require.resolve(request, {
|
442 | paths: [currentContext]
|
443 | });
|
444 | return `commonjs ${resolved}`;
|
445 | }
|
446 | });
|
447 | return ({ context, request }, callback) => {
|
448 | currentContext = context;
|
449 | return externals(context, request, callback);
|
450 | };
|
451 | }
|
452 |
|
453 | function resolveBundlingPaths(options) {
|
454 | const { entry, targetDir = index.paths.targetDir } = options;
|
455 | const resolveTargetModule = (pathString) => {
|
456 | for (const ext of ["mjs", "js", "ts", "tsx", "jsx"]) {
|
457 | const filePath = path.resolve(targetDir, `${pathString}.${ext}`);
|
458 | if (fs__default["default"].pathExistsSync(filePath)) {
|
459 | return filePath;
|
460 | }
|
461 | }
|
462 | return path.resolve(targetDir, `${pathString}.js`);
|
463 | };
|
464 | let targetPublic = void 0;
|
465 | let targetHtml = path.resolve(targetDir, "public/index.html");
|
466 | if (fs__default["default"].pathExistsSync(targetHtml)) {
|
467 | targetPublic = path.resolve(targetDir, "public");
|
468 | } else {
|
469 | targetHtml = path.resolve(targetDir, `${entry}.html`);
|
470 | if (!fs__default["default"].pathExistsSync(targetHtml)) {
|
471 | targetHtml = index.paths.resolveOwn("templates/serve_index.html");
|
472 | }
|
473 | }
|
474 | const targetRunFile = path.resolve(targetDir, "src/run.ts");
|
475 | const runFileExists = fs__default["default"].pathExistsSync(targetRunFile);
|
476 | return {
|
477 | targetHtml,
|
478 | targetPublic,
|
479 | targetPath: path.resolve(targetDir, "."),
|
480 | targetRunFile: runFileExists ? targetRunFile : void 0,
|
481 | targetDist: path.resolve(targetDir, "dist"),
|
482 | targetAssets: path.resolve(targetDir, "assets"),
|
483 | targetSrc: path.resolve(targetDir, "src"),
|
484 | targetDev: path.resolve(targetDir, "dev"),
|
485 | targetEntry: resolveTargetModule(entry),
|
486 | targetTsConfig: index.paths.resolveTargetRoot("tsconfig.json"),
|
487 | targetPackageJson: path.resolve(targetDir, "package.json"),
|
488 | rootNodeModules: index.paths.resolveTargetRoot("node_modules"),
|
489 | root: index.paths.targetRoot
|
490 | };
|
491 | }
|
492 |
|
493 | exports.createBackendConfig = createBackendConfig;
|
494 | exports.createConfig = createConfig;
|
495 | exports.resolveBaseUrl = resolveBaseUrl;
|
496 | exports.resolveBundlingPaths = resolveBundlingPaths;
|
497 |
|