@corespeed/webpack 0.0.0 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,690 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ var process$1 = require('node:process');
4
+ var dotenv = require('dotenv');
5
+ var node_module = require('node:module');
6
+ var readBrowserslist = require('browserslist');
7
+ var getPortPlease = require('get-port-please');
8
+ var cleanWebpackPlugin = require('clean-webpack-plugin');
9
+ var ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
10
+ var webpack = require('webpack');
11
+ var CopyWebpackPlugin = require('copy-webpack-plugin');
12
+ var HtmlWebpackPlugin = require('html-webpack-plugin');
13
+ var webpackBundleAnalyzer = require('webpack-bundle-analyzer');
14
+ var WebpackBarProgressPlugin = require('webpackbar');
15
+ var appendArrayInPlace = require('foxts/append-array-in-place');
16
+ var MiniCssExtractPlugin = require('mini-css-extract-plugin');
17
+ var TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
18
+ var isCI = require('is-ci');
19
+ var prompts = require('@clack/prompts');
20
+ var installPkg = require('@antfu/install-pkg');
21
+ var castArray = require('foxts/cast-array');
22
+ var LightningCSS = require('lightningcss');
23
+ var reactCompilerWebpack = require('react-compiler-webpack');
24
+ var TerserPlugin = require('terser-webpack-plugin');
25
+ var lightningcssLoader = require('lightningcss-loader');
26
+ var path = require('node:path');
27
+
28
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
29
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
30
+
31
+ var process__default = /*#__PURE__*/_interopDefault(process$1);
32
+ var readBrowserslist__default = /*#__PURE__*/_interopDefault(readBrowserslist);
33
+ var ReactRefreshPlugin__default = /*#__PURE__*/_interopDefault(ReactRefreshPlugin);
34
+ var CopyWebpackPlugin__default = /*#__PURE__*/_interopDefault(CopyWebpackPlugin);
35
+ var HtmlWebpackPlugin__default = /*#__PURE__*/_interopDefault(HtmlWebpackPlugin);
36
+ var WebpackBarProgressPlugin__default = /*#__PURE__*/_interopDefault(WebpackBarProgressPlugin);
37
+ var MiniCssExtractPlugin__default = /*#__PURE__*/_interopDefault(MiniCssExtractPlugin);
38
+ var TsconfigPathsPlugin__default = /*#__PURE__*/_interopDefault(TsconfigPathsPlugin);
39
+ var isCI__default = /*#__PURE__*/_interopDefault(isCI);
40
+ var LightningCSS__default = /*#__PURE__*/_interopDefault(LightningCSS);
41
+ var TerserPlugin__default = /*#__PURE__*/_interopDefault(TerserPlugin);
42
+ var path__default = /*#__PURE__*/_interopDefault(path);
43
+
44
+ function getSupportedBrowsers(browserlists, dir, isDevelopment) {
45
+ if (browserlists) {
46
+ return readBrowserslist__default.default(browserlists);
47
+ }
48
+ try {
49
+ return readBrowserslist.loadConfig({
50
+ path: dir,
51
+ env: isDevelopment ? 'development' : 'production'
52
+ });
53
+ } catch {}
54
+ }
55
+
56
+ function getSwcOptions(isDevelopment, useTypeScript, supportedBrowsers, coreJsVersion) {
57
+ return {
58
+ jsc: {
59
+ parser: useTypeScript ? {
60
+ syntax: 'typescript',
61
+ tsx: true
62
+ } : {
63
+ syntax: 'ecmascript',
64
+ jsx: true,
65
+ importAttributes: true
66
+ },
67
+ externalHelpers: true,
68
+ loose: false,
69
+ transform: {
70
+ react: {
71
+ runtime: 'automatic',
72
+ refresh: isDevelopment,
73
+ development: isDevelopment
74
+ },
75
+ optimizer: {
76
+ simplify: true,
77
+ globals: {
78
+ // typeofs: {
79
+ // window: 'object'
80
+ // },
81
+ envs: {
82
+ NODE_ENV: isDevelopment ? '"development"' : '"production"'
83
+ }
84
+ }
85
+ }
86
+ }
87
+ },
88
+ env: {
89
+ // swc-loader don't read browserslist config file, manually specify targets
90
+ targets: supportedBrowsers?.length ? supportedBrowsers : 'defaults, chrome > 70, edge >= 79, firefox esr, safari >= 11, not dead, not ie > 0, not ie_mob > 0, not OperaMini all',
91
+ mode: 'usage',
92
+ loose: false,
93
+ coreJs: coreJsVersion,
94
+ shippedProposals: false
95
+ }
96
+ };
97
+ }
98
+
99
+ const output = ({ output }, { jsFilename, cssFilename, assetFilename })=>(config)=>{
100
+ const { path: outputPath, base = '/', library, crossOriginLoading } = output;
101
+ config.output ??= {};
102
+ config.output.asyncChunks = true;
103
+ config.output.crossOriginLoading ??= crossOriginLoading;
104
+ config.output.hashFunction = 'xxhash64';
105
+ config.output.hashDigestLength = 16;
106
+ config.output.publicPath ??= base;
107
+ config.output.path ??= outputPath;
108
+ config.output.library ??= library;
109
+ config.output.filename ??= jsFilename;
110
+ config.output.chunkFilename ??= jsFilename;
111
+ config.output.cssFilename ??= cssFilename;
112
+ config.output.cssChunkFilename ??= cssFilename;
113
+ config.output.assetModuleFilename ??= assetFilename;
114
+ config.output.hotUpdateChunkFilename = 'webpack/[id].[fullhash].hot-update.js';
115
+ config.output.hotUpdateMainFilename = 'webpack/[fullhash].[runtime].hot-update.json';
116
+ return config;
117
+ };
118
+
119
+ const base = ({ development: isDevelopment, entry, webpackExperimentalBuiltinCssSupport })=>(config)=>{
120
+ config.mode ??= isDevelopment ? 'development' : 'production';
121
+ config.entry ??= entry;
122
+ config.experiments ??= {};
123
+ config.experiments.css ??= webpackExperimentalBuiltinCssSupport;
124
+ config.experiments.cacheUnaffected ??= true;
125
+ return config;
126
+ };
127
+
128
+ const sourcemap = ({ development: isDevelopment, sourcemap })=>(config)=>{
129
+ const { development: sourceMapDevelopment = 'eval-source-map', production: sourceMapProduction = 'hidden-source-map' } = sourcemap;
130
+ config.devtool ??= isDevelopment ? sourceMapDevelopment : sourceMapProduction;
131
+ return config;
132
+ };
133
+
134
+ const devserver = ({ devServerPort, spa, publicDir })=>async (config)=>{
135
+ const { fallbackPort: port = process.env.PORT ? Number(process.env.PORT || 3000) : 3000, portRange = [
136
+ 3000,
137
+ 3100
138
+ ], ports = [] } = devServerPort;
139
+ const finalPort = await getPortPlease.getPort({
140
+ port,
141
+ ports,
142
+ portRange
143
+ });
144
+ config.devServer ??= {};
145
+ config.devServer.port ??= finalPort;
146
+ config.devServer.hot ??= true;
147
+ config.devServer.historyApiFallback ??= spa;
148
+ config.devServer.static ??= {};
149
+ if (typeof config.devServer.static === 'object' && !Array.isArray(config.devServer.static)) {
150
+ config.devServer.static.directory ??= publicDir;
151
+ }
152
+ // in any case being a string, array, boolean, we do not override it
153
+ config.devServer.client ??= {};
154
+ if (typeof config.devServer.client === 'object') {
155
+ config.devServer.client.overlay ??= {};
156
+ if (typeof config.devServer.client.overlay === 'object') {
157
+ config.devServer.client.overlay.errors ??= true;
158
+ config.devServer.client.overlay.warnings ??= false;
159
+ }
160
+ }
161
+ return config;
162
+ };
163
+
164
+ const plugins = ({ development: isDevelopment, htmlTemplatePath, analyze, webpackExperimentalBuiltinCssSupport, plugins: customPlugins }, { cssFilename })=>(config)=>{
165
+ config.plugins ??= [];
166
+ if (!isDevelopment) {
167
+ config.plugins.push(new cleanWebpackPlugin.CleanWebpackPlugin(), new WebpackBarProgressPlugin__default.default());
168
+ }
169
+ if (isDevelopment) {
170
+ config.plugins.push(new ReactRefreshPlugin__default.default());
171
+ }
172
+ if (!webpackExperimentalBuiltinCssSupport) {
173
+ config.plugins.push(new MiniCssExtractPlugin__default.default({
174
+ filename: cssFilename
175
+ }));
176
+ }
177
+ // env inline
178
+ const publicEnv = Object.entries(process.env).reduce((acc, [key, value])=>{
179
+ if (key.startsWith('PUBLIC_') || key.startsWith('NEXT_PUBLIC_')) {
180
+ acc[`process.env.${key}`] = JSON.stringify(value);
181
+ }
182
+ return acc;
183
+ }, {});
184
+ config.plugins.push(new webpack.DefinePlugin({
185
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || (isDevelopment ? 'development' : 'production')),
186
+ 'import.meta.env.DEV': isDevelopment.toString(),
187
+ 'import.meta.env.PROD': (!isDevelopment).toString(),
188
+ 'typeof window': JSON.stringify('object'),
189
+ 'process.env': JSON.stringify(publicEnv),
190
+ ...publicEnv
191
+ }), new CopyWebpackPlugin__default.default({
192
+ patterns: [
193
+ {
194
+ from: 'public',
195
+ to: '.',
196
+ // globOptions: {
197
+ // ignore: ['**/index.html']
198
+ // },
199
+ noErrorOnMissing: true
200
+ }
201
+ ]
202
+ }));
203
+ if (htmlTemplatePath) {
204
+ config.plugins.push(new HtmlWebpackPlugin__default.default({
205
+ template: htmlTemplatePath
206
+ }));
207
+ }
208
+ if (analyze) {
209
+ config.plugins.push(new webpackBundleAnalyzer.BundleAnalyzerPlugin(typeof analyze === 'object' ? analyze : {
210
+ analyzerMode: 'static'
211
+ }));
212
+ }
213
+ appendArrayInPlace.appendArrayInPlace(config.plugins, customPlugins);
214
+ return config;
215
+ };
216
+
217
+ async function ensurePackage(packages, cwd, dev) {
218
+ const globalRequire = node_module.createRequire(cwd);
219
+ const missingPackages = new Set();
220
+ for (const packageName of castArray.castArray(packages)){
221
+ try {
222
+ globalRequire.resolve(packageName, {
223
+ paths: [
224
+ cwd
225
+ ]
226
+ });
227
+ } catch (e) {
228
+ if (typeof e === 'object' && e && 'code' in e && e.code === 'MODULE_NOT_FOUND') {
229
+ missingPackages.add(packageName);
230
+ }
231
+ }
232
+ }
233
+ if (missingPackages.size === 0) {
234
+ return;
235
+ }
236
+ if (isCI__default.default) {
237
+ throw new Error(`Missing required packages: ${[
238
+ ...missingPackages
239
+ ].join(', ')}. Please ensure all required packages are installed.`);
240
+ }
241
+ const result = await prompts.confirm({
242
+ message: ` The following packages are required but not installed: ${[
243
+ ...missingPackages
244
+ ].join(', ')}. Do you want to install them now?`,
245
+ initialValue: true
246
+ });
247
+ if (result) {
248
+ await installPkg.installPackage([
249
+ ...missingPackages
250
+ ], {
251
+ dev
252
+ });
253
+ }
254
+ }
255
+
256
+ const resolve = ({ cwd, lodashTreeShaking })=>async (config)=>{
257
+ config.resolve ??= {};
258
+ const extensions = [
259
+ '.ts',
260
+ '.tsx',
261
+ '.jsx',
262
+ '.mjs',
263
+ '.cjs',
264
+ '.js',
265
+ '.json'
266
+ ];
267
+ config.resolve.extensions = extensions;
268
+ config.resolve.cache = true;
269
+ config.resolve.unsafeCache = false;
270
+ config.resolve.conditionNames = [
271
+ 'import',
272
+ 'module',
273
+ 'require',
274
+ 'default'
275
+ ];
276
+ config.resolve.plugins ??= [];
277
+ config.resolve.plugins.push(new TsconfigPathsPlugin__default.default({
278
+ // tsconfig-paths-webpack-plugin can't access `resolve.extensions`
279
+ // have to provide again
280
+ extensions
281
+ }));
282
+ const globalRequire = node_module.createRequire(cwd);
283
+ if (lodashTreeShaking) {
284
+ await ensurePackage('lodash-es', cwd, true);
285
+ config.resolve.alias ??= {};
286
+ if (!Array.isArray(config.resolve.alias)) {
287
+ config.resolve.alias.lodash = 'lodash-es';
288
+ }
289
+ config.resolve.fallback ??= {};
290
+ if (!Array.isArray(config.resolve.fallback)) {
291
+ config.resolve.fallback['lodash-es/fp'] = globalRequire.resolve('lodash/fp');
292
+ }
293
+ }
294
+ return config;
295
+ };
296
+
297
+ const external = ({ externals })=>(config)=>{
298
+ const finalExternals = [];
299
+ if (config.externals) {
300
+ if (Array.isArray(config.externals)) {
301
+ appendArrayInPlace.appendArrayInPlace(finalExternals, config.externals);
302
+ } else {
303
+ finalExternals.push(config.externals);
304
+ }
305
+ }
306
+ finalExternals.push(externals);
307
+ config.externals = finalExternals;
308
+ return config;
309
+ };
310
+
311
+ const regexLikeCss = /\.(css|scss|sass)$/;
312
+ const $require = typeof globalThis.require === 'function' ? globalThis.require : node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
313
+ const loaders = ({ cwd, postcss, svgr, reactCompiler, webpackExperimentalBuiltinCssSupport, browserlists }, { swcTypeScriptOptions, swcJavaScriptOptions, supportedBrowsers })=>async (config)=>{
314
+ await ensurePackage([
315
+ 'core-js',
316
+ '@swc/helpers'
317
+ ], cwd, false);
318
+ const blocks = [];
319
+ config.module ??= {};
320
+ config.module.rules ??= [];
321
+ // Automatically transform references to files (i.e. url()) into URLs
322
+ loader({
323
+ oneOf: [
324
+ {
325
+ // This should only be applied to CSS files
326
+ issuer: regexLikeCss,
327
+ // Exclude extensions that webpack handles by default
328
+ exclude: [
329
+ /\.(js|mjs|jsx|ts|tsx)$/,
330
+ /\.html$/,
331
+ /\.json$/,
332
+ /\.webpack\[[^\]]+]$/
333
+ ],
334
+ // `asset/resource` always emits a URL reference, where `asset`
335
+ // might inline the asset as a data URI
336
+ type: 'asset/resource'
337
+ }
338
+ ]
339
+ });
340
+ // CSS
341
+ if (postcss) {
342
+ await ensurePackage([
343
+ 'postcss',
344
+ 'postcss-loader'
345
+ ], cwd, true);
346
+ }
347
+ const globalRequire = node_module.createRequire(cwd);
348
+ if (!webpackExperimentalBuiltinCssSupport || postcss) {
349
+ loader({
350
+ test: /\.css$/,
351
+ use: [
352
+ !webpackExperimentalBuiltinCssSupport && {
353
+ loader: MiniCssExtractPlugin.loader
354
+ },
355
+ !webpackExperimentalBuiltinCssSupport && {
356
+ loader: $require.resolve('css-loader')
357
+ },
358
+ {
359
+ loader: $require.resolve('lightningcss-loader'),
360
+ options: {
361
+ implementation: LightningCSS__default.default,
362
+ // lightningcss-loader will read targets and parsed via browserlists
363
+ // https://github.com/fz6m/lightningcss-loader/blob/7f3601abea4479deb31db713610c5a09e8a5d576/src/loader.ts#L44
364
+ // https://github.com/fz6m/lightningcss-loader/blob/7f3601abea4479deb31db713610c5a09e8a5d576/src/minify.ts#L111
365
+ // https://github.com/fz6m/lightningcss-loader/blob/7f3601abea4479deb31db713610c5a09e8a5d576/src/utils.ts#L39
366
+ targets: browserlists ?? supportedBrowsers
367
+ }
368
+ },
369
+ postcss && globalRequire.resolve('postcss-loader')
370
+ ]
371
+ });
372
+ }
373
+ // SVGR
374
+ if (svgr) {
375
+ await ensurePackage('@svgr/webpack', cwd, true);
376
+ loader({
377
+ test: /\.svg$/i,
378
+ type: 'asset',
379
+ resourceQuery: /url/ // *.svg?url
380
+ });
381
+ loader({
382
+ test: /\.svg$/i,
383
+ issuer: /\.[jt]sx?$/,
384
+ resourceQuery: {
385
+ not: [
386
+ /url/
387
+ ]
388
+ },
389
+ use: [
390
+ {
391
+ loader: $require.resolve('swc-loader'),
392
+ options: swcTypeScriptOptions
393
+ },
394
+ {
395
+ loader: globalRequire.resolve('@svgr/webpack'),
396
+ options: {
397
+ babel: false
398
+ }
399
+ }
400
+ ]
401
+ });
402
+ }
403
+ // Assets
404
+ loader({
405
+ oneOf: [
406
+ {
407
+ test: /\.(woff|woff2|eot|ttf|otf)$/i,
408
+ type: 'asset/resource'
409
+ },
410
+ {
411
+ test: /assets\//,
412
+ type: 'asset/resource',
413
+ generator: {
414
+ filename: '_assets/[hash][ext][query]'
415
+ }
416
+ }
417
+ ]
418
+ });
419
+ // TypeScript/JavaScript
420
+ if (reactCompiler) {
421
+ await ensurePackage('babel-plugin-react-compiler', cwd, true);
422
+ }
423
+ loader({
424
+ test: /\.[cm]?tsx?$/,
425
+ exclude: [
426
+ /node_modules/
427
+ ],
428
+ use: [
429
+ {
430
+ loader: $require.resolve('swc-loader'),
431
+ options: swcTypeScriptOptions
432
+ },
433
+ reactCompiler && {
434
+ loader: reactCompilerWebpack.reactCompilerLoader,
435
+ options: reactCompilerWebpack.defineReactCompilerLoaderOption(typeof reactCompiler === 'object' ? reactCompiler : {})
436
+ }
437
+ ]
438
+ });
439
+ loader({
440
+ test: /\.[cm]?jsx?$/,
441
+ exclude: [
442
+ /node_modules/
443
+ ],
444
+ use: [
445
+ {
446
+ loader: $require.resolve('swc-loader'),
447
+ options: swcJavaScriptOptions
448
+ },
449
+ reactCompiler && {
450
+ loader: reactCompilerWebpack.reactCompilerLoader,
451
+ options: reactCompilerWebpack.defineReactCompilerLoaderOption(typeof reactCompiler === 'object' ? reactCompiler : {})
452
+ }
453
+ ]
454
+ });
455
+ return blocks.reduce(async (cfg, next)=>next(await cfg), config);
456
+ function loader(rule) {
457
+ blocks.push((config)=>{
458
+ if (rule.oneOf) {
459
+ const existing = config.module.rules.find((arrayRule)=>arrayRule && typeof arrayRule === 'object' && arrayRule.oneOf);
460
+ if (existing && typeof existing === 'object') {
461
+ existing.oneOf.push(...rule.oneOf);
462
+ return config;
463
+ }
464
+ }
465
+ config.module.rules.push(rule);
466
+ return config;
467
+ });
468
+ }
469
+ // function unshiftLoader(
470
+ // rule: WebpackRuleSetRule
471
+ // ) {
472
+ // blocks.push((config: WebpackConfiguration) => {
473
+ // if (rule.oneOf) {
474
+ // const existing = config.module!.rules!.find(
475
+ // (arrayRule) => arrayRule && typeof arrayRule === 'object' && arrayRule.oneOf
476
+ // );
477
+ // if (existing && typeof existing === 'object') {
478
+ // existing.oneOf?.unshift(...rule.oneOf);
479
+ // return config;
480
+ // }
481
+ // }
482
+ // config.module!.rules!.unshift(rule);
483
+ // return config;
484
+ // });
485
+ // };
486
+ };
487
+
488
+ const optimization = ({ development: isDevelopment, browserlists }, { supportedBrowsers })=>(config)=>{
489
+ config.optimization ??= {};
490
+ config.optimization.emitOnErrors = !isDevelopment;
491
+ config.optimization.checkWasmTypes = false;
492
+ config.optimization.nodeEnv = false; // we manually bring our own DefinePlugin
493
+ config.optimization.minimizer ??= [];
494
+ config.optimization.minimizer.push(new TerserPlugin__default.default({
495
+ minify: TerserPlugin__default.default.swcMinify,
496
+ terserOptions: {
497
+ compress: {
498
+ ecma: 2018,
499
+ comparisons: false,
500
+ inline: 2 // https://github.com/vercel/next.js/issues/7178#issuecomment-493048965
501
+ },
502
+ mangle: {
503
+ safari10: true
504
+ },
505
+ format: {
506
+ // use ecma 2015+ to enable minify like shorthand object
507
+ ecma: 2018,
508
+ safari10: true,
509
+ comments: false,
510
+ // Fixes usage of Emoji and certain Regex
511
+ ascii_only: true
512
+ }
513
+ }
514
+ }), new lightningcssLoader.LightningCssMinifyPlugin({
515
+ implementation: LightningCSS__default.default,
516
+ // lightningcss-loader will read targets and parsed via browserlists
517
+ // https://github.com/fz6m/lightningcss-loader/blob/7f3601abea4479deb31db713610c5a09e8a5d576/src/loader.ts#L44
518
+ // https://github.com/fz6m/lightningcss-loader/blob/7f3601abea4479deb31db713610c5a09e8a5d576/src/minify.ts#L111
519
+ // https://github.com/fz6m/lightningcss-loader/blob/7f3601abea4479deb31db713610c5a09e8a5d576/src/utils.ts#L39
520
+ targets: browserlists ?? supportedBrowsers
521
+ }));
522
+ return config;
523
+ };
524
+
525
+ function getTopLevelFrameworkPaths(frameworkPackages, dir) {
526
+ const globalRequire = node_module.createRequire(dir);
527
+ // Only top-level packages are included, e.g. nested copies like
528
+ // 'node_modules/meow/node_modules/react' are not included.
529
+ const topLevelFrameworkPaths = [];
530
+ const visitedFrameworkPackages = new Set();
531
+ // Adds package-paths of dependencies recursively
532
+ const addPackagePath = (packageName, relativeToPath)=>{
533
+ try {
534
+ if (visitedFrameworkPackages.has(packageName)) return;
535
+ visitedFrameworkPackages.add(packageName);
536
+ const packageJsonPath = globalRequire.resolve(`${packageName}/package.json`, {
537
+ paths: [
538
+ relativeToPath
539
+ ]
540
+ });
541
+ // Include a trailing slash so that a `.startsWith(packagePath)` check avoids false positives
542
+ // when one package name starts with the full name of a different package.
543
+ // For example:
544
+ // "node_modules/react-slider".startsWith("node_modules/react") // true
545
+ // "node_modules/react-slider".startsWith("node_modules/react/") // false
546
+ const directory = path__default.default.join(packageJsonPath, '../');
547
+ // Returning from the function in case the directory has already been added and traversed
548
+ if (topLevelFrameworkPaths.includes(directory)) return;
549
+ topLevelFrameworkPaths.push(directory);
550
+ const dependencies = globalRequire(packageJsonPath).dependencies || {};
551
+ for (const name of Object.keys(dependencies)){
552
+ addPackagePath(name, directory);
553
+ }
554
+ } catch {
555
+ // don't error on failing to resolve framework packages
556
+ }
557
+ };
558
+ for (const packageName of frameworkPackages){
559
+ addPackagePath(packageName, dir);
560
+ }
561
+ return topLevelFrameworkPaths;
562
+ }
563
+
564
+ const splitChunks = ({ cwd, topLevelFrameworkPackages })=>(config)=>{
565
+ config.optimization ??= {};
566
+ if (config.optimization.runtimeChunk === 'single') {
567
+ config.optimization.runtimeChunk = {
568
+ name: 'webpack'
569
+ };
570
+ } else {
571
+ config.optimization.runtimeChunk ??= {
572
+ name: 'webpack'
573
+ };
574
+ }
575
+ config.optimization.splitChunks ||= {};
576
+ config.optimization.splitChunks.maxInitialRequests = 25;
577
+ config.optimization.splitChunks.minSize = 20000;
578
+ config.optimization.splitChunks.cacheGroups ??= {};
579
+ const topLevelFrameworkPaths = getTopLevelFrameworkPaths(topLevelFrameworkPackages, cwd);
580
+ config.optimization.splitChunks.cacheGroups.framework ||= {
581
+ chunks: 'all',
582
+ name: 'framework',
583
+ test (module) {
584
+ const resource = module.nameForCondition();
585
+ return resource ? topLevelFrameworkPaths.some((pkgPath)=>resource.startsWith(pkgPath)) : false;
586
+ },
587
+ priority: 40,
588
+ enforce: true
589
+ };
590
+ return config;
591
+ };
592
+
593
+ /**
594
+ * Usage:
595
+ *
596
+ * ```js
597
+ * // webpack.config.js
598
+ * const { createWebpck } = require('@corespeed/webpack');
599
+ * const path = require('node:path');
600
+ *
601
+ * module.exports = createWebpack({
602
+ * // your options here
603
+ * }, {
604
+ * // your custom webpack config here
605
+ * });
606
+ * ```
607
+ */ async function createWebpack(options, customWebpackOptions = {}) {
608
+ const ctx = {
609
+ output: {},
610
+ spa: true,
611
+ publicDir: './public',
612
+ development: process__default.default.env.NODE_ENV === 'development',
613
+ // entry,
614
+ htmlTemplatePath: './src/index.html',
615
+ sourcemap: {},
616
+ devServerPort: {},
617
+ externals: {},
618
+ webpackExperimentalBuiltinCssSupport: false,
619
+ postcss: false,
620
+ svgr: false,
621
+ topLevelFrameworkPackages: [
622
+ 'react',
623
+ 'react-dom',
624
+ 'wouter',
625
+ 'react-router',
626
+ 'react-router-dom'
627
+ ],
628
+ reactCompiler: false,
629
+ analyze: process__default.default.env.ANALYZE === 'true',
630
+ plugins: [],
631
+ dotenv: {},
632
+ lodashTreeShaking: false,
633
+ ...options
634
+ };
635
+ // dotenv
636
+ if (ctx.dotenv) {
637
+ if (typeof ctx.dotenv === 'boolean') {
638
+ dotenv.configDotenv();
639
+ } else {
640
+ dotenv.configDotenv(ctx.dotenv);
641
+ }
642
+ }
643
+ // Output
644
+ const { filenameContainChunkName: outputChunkFileFormatContainChunkName = false, filenamePrefix: _outputFilenamePrefix = '/_assets/static/' } = ctx.output;
645
+ const prodOnlyChunkName = outputChunkFileFormatContainChunkName ? '[name].' : '';
646
+ const outputFilenamePrefix = ensureFilenamePrefix(_outputFilenamePrefix);
647
+ // MiniCssExtractPlugin do not read output.cssFilename
648
+ // https://github.com/webpack/mini-css-extract-plugin/issues/1041
649
+ // So we need to pass cssFilename to both output.cssFilename and new MiniCssExtractPlugin({ filename: ... })
650
+ // So we calculate them ahead here and pass via block context
651
+ const jsFilename = outputFilenamePrefix + 'js/' + (ctx.development ? '[name].js' : prodOnlyChunkName + '[contenthash].js');
652
+ const cssFilename = outputFilenamePrefix + 'css/' + (ctx.development ? '[name].css' : prodOnlyChunkName + '[contenthash].css');
653
+ const assetFilename = outputFilenamePrefix + 'assets/' + (ctx.development ? '[name].[hash][ext][query]' : prodOnlyChunkName + '[hash][ext][query]');
654
+ // Misc
655
+ const supportedBrowsers = getSupportedBrowsers(ctx.browserlists, ctx.cwd, ctx.development);
656
+ supportedBrowsers ? LightningCSS.browserslistToTargets(supportedBrowsers) : undefined;
657
+ const globalRequire = node_module.createRequire(ctx.cwd);
658
+ const coreJsVersion = globalRequire('core-js/package.json').version;
659
+ const blockCtx = {
660
+ swcJavaScriptOptions: getSwcOptions(ctx.development, false, supportedBrowsers, coreJsVersion),
661
+ swcTypeScriptOptions: getSwcOptions(ctx.development, true, supportedBrowsers, coreJsVersion),
662
+ supportedBrowsers,
663
+ jsFilename,
664
+ cssFilename,
665
+ assetFilename
666
+ };
667
+ return [
668
+ base(ctx),
669
+ external(ctx),
670
+ output(ctx, blockCtx),
671
+ sourcemap(ctx),
672
+ devserver(ctx),
673
+ loaders(ctx, blockCtx),
674
+ plugins(ctx, blockCtx),
675
+ optimization(ctx, blockCtx),
676
+ splitChunks(ctx),
677
+ resolve(ctx)
678
+ ].reduce(async (config, next)=>next(await config), customWebpackOptions);
679
+ }
680
+ function ensureFilenamePrefix(path) {
681
+ if (path.startsWith('/')) {
682
+ path = path.slice(1);
683
+ }
684
+ if (!path.endsWith('/')) {
685
+ path = path + '/';
686
+ }
687
+ return path;
688
+ }
689
+
690
+ exports.createWebpack = createWebpack;