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