UNPKG

16.5 kBJavaScriptView Raw
1'use strict';
2
3var fs = require('fs-extra');
4var path = require('path');
5var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
6var HtmlWebpackPlugin = require('html-webpack-plugin');
7var ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
8var runScriptWebpackPlugin = require('run-script-webpack-plugin');
9var webpack = require('webpack');
10var nodeExternals = require('webpack-node-externals');
11var cliCommon = require('@backstage/cli-common');
12var getPackages = require('@manypkg/get-packages');
13var MiniCssExtractPlugin = require('mini-css-extract-plugin');
14var svgrTemplate = require('./svgrTemplate-550efce6.cjs.js');
15var index = require('./index-09611511.cjs.js');
16var run = require('./run-a95417b1.cjs.js');
17var ESLintPlugin = require('eslint-webpack-plugin');
18var pickBy = require('lodash/pickBy');
19
20function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
21
22var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
23var ForkTsCheckerWebpackPlugin__default = /*#__PURE__*/_interopDefaultLegacy(ForkTsCheckerWebpackPlugin);
24var HtmlWebpackPlugin__default = /*#__PURE__*/_interopDefaultLegacy(HtmlWebpackPlugin);
25var ModuleScopePlugin__default = /*#__PURE__*/_interopDefaultLegacy(ModuleScopePlugin);
26var webpack__default = /*#__PURE__*/_interopDefaultLegacy(webpack);
27var nodeExternals__default = /*#__PURE__*/_interopDefaultLegacy(nodeExternals);
28var MiniCssExtractPlugin__default = /*#__PURE__*/_interopDefaultLegacy(MiniCssExtractPlugin);
29var ESLintPlugin__default = /*#__PURE__*/_interopDefaultLegacy(ESLintPlugin);
30var pickBy__default = /*#__PURE__*/_interopDefaultLegacy(pickBy);
31
32const { ESBuildMinifyPlugin } = require("esbuild-loader");
33const 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
77const 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
197class 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
224function 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}
232async 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}
255async 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}
350async 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}
436function 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
453function 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
493exports.createBackendConfig = createBackendConfig;
494exports.createConfig = createConfig;
495exports.resolveBaseUrl = resolveBaseUrl;
496exports.resolveBundlingPaths = resolveBundlingPaths;
497//# sourceMappingURL=paths-5887046a.cjs.js.map