@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 +689 -0
- package/dist/index.d.ts +228 -0
- package/dist/index.mjs +675 -0
- package/package.json +84 -8
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;
|