@corespeed/webpack 0.0.0 → 0.1.0-beta.1

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