@meteorjs/rspack 1.1.0-beta.3 → 1.1.0-beta.31
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/.claude/settings.local.json +10 -0
- package/README.md +141 -0
- package/index.d.ts +18 -1
- package/lib/ignore.js +1 -1
- package/lib/meteorRspackConfigHelpers.js +121 -0
- package/lib/meteorRspackHelpers.js +54 -3
- package/lib/swc.js +36 -6
- package/lib/test.js +23 -16
- package/package.json +1 -1
- package/plugins/MeteorRspackOutputPlugin.js +36 -0
- package/plugins/RequireExtenalsPlugin.js +10 -4
- package/rspack.config.js +294 -257
- package/scripts/bump-version.js +89 -0
- package/scripts/publish-beta.sh +4 -0
package/rspack.config.js
CHANGED
|
@@ -10,18 +10,22 @@ const { getMeteorAppSwcConfig } = require('./lib/swc.js');
|
|
|
10
10
|
const HtmlRspackPlugin = require('./plugins/HtmlRspackPlugin.js');
|
|
11
11
|
const { RequireExternalsPlugin } = require('./plugins/RequireExtenalsPlugin.js');
|
|
12
12
|
const { AssetExternalsPlugin } = require('./plugins/AssetExternalsPlugin.js');
|
|
13
|
+
const { MeteorRspackOutputPlugin } = require('./plugins/MeteorRspackOutputPlugin.js');
|
|
13
14
|
const { generateEagerTestFile } = require("./lib/test.js");
|
|
14
15
|
const { getMeteorIgnoreEntries, createIgnoreGlobConfig } = require("./lib/ignore");
|
|
15
|
-
const { mergeMeteorRspackFragments } = require("./lib/meteorRspackConfigFactory.js");
|
|
16
16
|
const {
|
|
17
17
|
compileWithMeteor,
|
|
18
18
|
compileWithRspack,
|
|
19
19
|
setCache,
|
|
20
20
|
splitVendorChunk,
|
|
21
21
|
extendSwcConfig,
|
|
22
|
+
replaceSwcConfig,
|
|
22
23
|
makeWebNodeBuiltinsAlias,
|
|
23
24
|
disablePlugins,
|
|
25
|
+
outputMeteorRspack,
|
|
26
|
+
enablePortableBuild,
|
|
24
27
|
} = require('./lib/meteorRspackHelpers.js');
|
|
28
|
+
const { loadUserAndOverrideConfig } = require('./lib/meteorRspackConfigHelpers.js');
|
|
25
29
|
const { prepareMeteorRspackConfig } = require("./lib/meteorRspackConfigFactory");
|
|
26
30
|
|
|
27
31
|
// Safe require that doesn't throw if the module isn't found
|
|
@@ -40,7 +44,11 @@ function safeRequire(moduleName) {
|
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
// Persistent filesystem cache strategy
|
|
43
|
-
function createCacheStrategy(
|
|
47
|
+
function createCacheStrategy(
|
|
48
|
+
mode,
|
|
49
|
+
side,
|
|
50
|
+
{ projectConfigPath, configPath, buildContext } = {},
|
|
51
|
+
) {
|
|
44
52
|
// Check for configuration files
|
|
45
53
|
const tsconfigPath = path.join(process.cwd(), 'tsconfig.json');
|
|
46
54
|
const hasTsconfig = fs.existsSync(tsconfigPath);
|
|
@@ -52,6 +60,8 @@ function createCacheStrategy(mode, side, { projectConfigPath, configPath } = {})
|
|
|
52
60
|
const hasSwcrcConfig = fs.existsSync(swcrcPath);
|
|
53
61
|
const swcJsPath = path.join(process.cwd(), 'swc.config.js');
|
|
54
62
|
const hasSwcJsConfig = fs.existsSync(swcJsPath);
|
|
63
|
+
const swcTsPath = path.join(process.cwd(), 'swc.config.ts');
|
|
64
|
+
const hasSwcTsConfig = fs.existsSync(swcTsPath);
|
|
55
65
|
const postcssConfigPath = path.join(process.cwd(), 'postcss.config.js');
|
|
56
66
|
const hasPostcssConfig = fs.existsSync(postcssConfigPath);
|
|
57
67
|
const packageLockPath = path.join(process.cwd(), 'package-lock.json');
|
|
@@ -68,6 +78,7 @@ function createCacheStrategy(mode, side, { projectConfigPath, configPath } = {})
|
|
|
68
78
|
...(hasBabelJsConfig ? [babelJsConfig] : []),
|
|
69
79
|
...(hasSwcrcConfig ? [swcrcPath] : []),
|
|
70
80
|
...(hasSwcJsConfig ? [swcJsPath] : []),
|
|
81
|
+
...(hasSwcTsConfig ? [swcTsPath] : []),
|
|
71
82
|
...(hasPostcssConfig ? [postcssConfigPath] : []),
|
|
72
83
|
...(hasPackageLock ? [packageLockPath] : []),
|
|
73
84
|
...(hasYarnLock ? [yarnLockPath] : []),
|
|
@@ -81,7 +92,9 @@ function createCacheStrategy(mode, side, { projectConfigPath, configPath } = {})
|
|
|
81
92
|
type: "persistent",
|
|
82
93
|
storage: {
|
|
83
94
|
type: "filesystem",
|
|
84
|
-
directory: `node_modules/.cache/rspack
|
|
95
|
+
directory: `node_modules/.cache/rspack/${
|
|
96
|
+
[buildContext, side].filter(Boolean).join('-') || 'default'
|
|
97
|
+
}`,
|
|
85
98
|
},
|
|
86
99
|
...(buildDependencies.length > 0 && {
|
|
87
100
|
buildDependencies: buildDependencies,
|
|
@@ -204,15 +217,45 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
204
217
|
const Meteor = { ...inMeteor };
|
|
205
218
|
// Convert string boolean values to actual booleans
|
|
206
219
|
for (const key in Meteor) {
|
|
207
|
-
if (Meteor[key] ===
|
|
220
|
+
if (Meteor[key] === "true" || Meteor[key] === true) {
|
|
208
221
|
Meteor[key] = true;
|
|
209
|
-
} else if (Meteor[key] ===
|
|
222
|
+
} else if (Meteor[key] === "false" || Meteor[key] === false) {
|
|
210
223
|
Meteor[key] = false;
|
|
211
224
|
}
|
|
212
225
|
}
|
|
213
226
|
|
|
214
|
-
const
|
|
215
|
-
const
|
|
227
|
+
const isTestLike = !!Meteor.isTestLike;
|
|
228
|
+
const swcExternalHelpers = !!Meteor.swcExternalHelpers;
|
|
229
|
+
const isNative = !!Meteor.isNative;
|
|
230
|
+
const devServerPort = Meteor.devServerPort || 8080;
|
|
231
|
+
|
|
232
|
+
const projectDir = process.cwd();
|
|
233
|
+
const projectConfigPath =
|
|
234
|
+
Meteor.projectConfigPath || path.resolve(projectDir, "rspack.config.js");
|
|
235
|
+
|
|
236
|
+
// Determine context for bundles and assets
|
|
237
|
+
const meteorLocalDirName = process.env.METEOR_LOCAL_DIR
|
|
238
|
+
? path.basename(process.env.METEOR_LOCAL_DIR.replace(/\\/g, "/"))
|
|
239
|
+
: "";
|
|
240
|
+
const buildContext =
|
|
241
|
+
Meteor.buildContext ||
|
|
242
|
+
process.env.RSPACK_BUILD_CONTEXT ||
|
|
243
|
+
`_build${(meteorLocalDirName && `-${meteorLocalDirName}`) || ""}`;
|
|
244
|
+
const assetsContext =
|
|
245
|
+
Meteor.assetsContext ||
|
|
246
|
+
process.env.RSPACK_ASSETS_CONTEXT ||
|
|
247
|
+
`build-assets${(meteorLocalDirName && `-${meteorLocalDirName}`) || ""}`;
|
|
248
|
+
const chunksContext =
|
|
249
|
+
Meteor.chunksContext ||
|
|
250
|
+
process.env.RSPACK_CHUNKS_CONTEXT ||
|
|
251
|
+
`build-chunks${(meteorLocalDirName && `-${meteorLocalDirName}`) || ""}`;
|
|
252
|
+
|
|
253
|
+
// Compute build paths before loading user config (needed by Meteor helpers below)
|
|
254
|
+
const outputPath = Meteor.outputPath;
|
|
255
|
+
const outputDir = path.dirname(Meteor.outputPath || "");
|
|
256
|
+
Meteor.buildOutputDir = path.resolve(projectDir, buildContext, outputDir);
|
|
257
|
+
|
|
258
|
+
// Meteor flags derived purely from input; independent of loaded user/override configs
|
|
216
259
|
const isTest = !!Meteor.isTest;
|
|
217
260
|
const isClient = !!Meteor.isClient;
|
|
218
261
|
const isServer = !!Meteor.isServer;
|
|
@@ -222,12 +265,8 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
222
265
|
const isTestModule = !!Meteor.isTestModule;
|
|
223
266
|
const isTestEager = !!Meteor.isTestEager;
|
|
224
267
|
const isTestFullApp = !!Meteor.isTestFullApp;
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
const isNative = !!Meteor.isNative;
|
|
228
|
-
const mode = isProd ? 'production' : 'development';
|
|
229
|
-
const projectDir = process.cwd();
|
|
230
|
-
const projectConfigPath = Meteor.projectConfigPath || path.resolve(projectDir, 'rspack.config.js');
|
|
268
|
+
const isProfile = !!Meteor.isProfile;
|
|
269
|
+
const isVerbose = !!Meteor.isVerbose;
|
|
231
270
|
const configPath = Meteor.configPath;
|
|
232
271
|
const testEntry = Meteor.testEntry;
|
|
233
272
|
|
|
@@ -238,58 +277,69 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
238
277
|
Meteor.isTsxEnabled || (isTypescriptEnabled && isReactEnabled) || false;
|
|
239
278
|
const isBundleVisualizerEnabled = Meteor.isBundleVisualizerEnabled || false;
|
|
240
279
|
const isAngularEnabled = Meteor.isAngularEnabled || false;
|
|
280
|
+
const enableSwcExternalHelpers = !isServer && swcExternalHelpers;
|
|
241
281
|
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const runPath = Meteor.runPath;
|
|
253
|
-
|
|
254
|
-
// Determine banner
|
|
255
|
-
const bannerOutput = JSON.parse(Meteor.bannerOutput || process.env.RSPACK_BANNER || '""');
|
|
256
|
-
|
|
257
|
-
// Determine output directories
|
|
258
|
-
const clientOutputDir = path.resolve(projectDir, 'public');
|
|
259
|
-
const serverOutputDir = path.resolve(projectDir, 'private');
|
|
260
|
-
|
|
261
|
-
// Determine context for bundles and assets
|
|
262
|
-
const buildContext = Meteor.buildContext || '_build';
|
|
263
|
-
const assetsContext = Meteor.assetsContext || 'build-assets';
|
|
264
|
-
const chunksContext = Meteor.chunksContext || 'build-chunks';
|
|
265
|
-
|
|
266
|
-
// Determine build output and pass to Meteor
|
|
267
|
-
const buildOutputDir = path.resolve(projectDir, buildContext, outputDir);
|
|
268
|
-
Meteor.buildOutputDir = buildOutputDir;
|
|
282
|
+
// Defined here so it can be called both before and after the first config load;
|
|
283
|
+
// without loaded configs it falls through to argv/Meteor flags.
|
|
284
|
+
const getModeFromConfig = (userConfig, overrideConfig) => {
|
|
285
|
+
if (overrideConfig?.mode) return overrideConfig.mode;
|
|
286
|
+
if (userConfig?.mode) return userConfig.mode;
|
|
287
|
+
if (argv.mode) return argv.mode;
|
|
288
|
+
if (Meteor.isProduction) return "production";
|
|
289
|
+
if (Meteor.isDevelopment) return "development";
|
|
290
|
+
return null;
|
|
291
|
+
};
|
|
269
292
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
293
|
+
// Initial mode before user/override configs are loaded
|
|
294
|
+
const initialCurrentMode = getModeFromConfig();
|
|
295
|
+
const initialIsProd = initialCurrentMode
|
|
296
|
+
? initialCurrentMode === "production"
|
|
297
|
+
: !!Meteor.isProduction;
|
|
298
|
+
const initialIsDev = initialCurrentMode
|
|
299
|
+
? initialCurrentMode === "development"
|
|
300
|
+
: !!Meteor.isDevelopment || !initialIsProd;
|
|
301
|
+
const initialMode = initialIsProd ? "production" : "development";
|
|
302
|
+
|
|
303
|
+
// Initialized with pre-load values so helpers work during the first config load;
|
|
304
|
+
// reassigned after load once mode is fully resolved.
|
|
305
|
+
let cacheStrategy = createCacheStrategy(
|
|
306
|
+
initialMode,
|
|
307
|
+
(Meteor.isClient && "client") || "server",
|
|
308
|
+
{ projectConfigPath, configPath, buildContext }
|
|
274
309
|
);
|
|
310
|
+
let swcConfigRule = createSwcConfig({
|
|
311
|
+
isTypescriptEnabled,
|
|
312
|
+
isReactEnabled,
|
|
313
|
+
isJsxEnabled,
|
|
314
|
+
isTsxEnabled,
|
|
315
|
+
externalHelpers: enableSwcExternalHelpers,
|
|
316
|
+
isDevEnvironment: isRun && initialIsDev && !isTest && !isNative,
|
|
317
|
+
isClient,
|
|
318
|
+
isAngularEnabled,
|
|
319
|
+
});
|
|
320
|
+
Meteor.swcConfigOptions = swcConfigRule.options;
|
|
275
321
|
|
|
276
322
|
// Expose Meteor's helpers to expand Rspack configs
|
|
277
|
-
Meteor.compileWithMeteor = deps => compileWithMeteor(deps);
|
|
323
|
+
Meteor.compileWithMeteor = (deps) => compileWithMeteor(deps);
|
|
278
324
|
Meteor.compileWithRspack = (deps, options = {}) =>
|
|
279
325
|
compileWithRspack(deps, {
|
|
280
326
|
options: mergeSplitOverlap(Meteor.swcConfigOptions, options),
|
|
281
327
|
});
|
|
282
|
-
Meteor.setCache = enabled =>
|
|
283
|
-
setCache(
|
|
284
|
-
!!enabled,
|
|
285
|
-
enabled === 'memory' ? undefined : cacheStrategy
|
|
286
|
-
);
|
|
328
|
+
Meteor.setCache = (enabled) =>
|
|
329
|
+
setCache(!!enabled, enabled === "memory" ? undefined : cacheStrategy);
|
|
287
330
|
Meteor.splitVendorChunk = () => splitVendorChunk();
|
|
288
|
-
Meteor.extendSwcConfig = (customSwcConfig) =>
|
|
331
|
+
Meteor.extendSwcConfig = (customSwcConfig) =>
|
|
332
|
+
extendSwcConfig(
|
|
333
|
+
mergeSplitOverlap(Meteor.swcConfigOptions, customSwcConfig)
|
|
334
|
+
);
|
|
335
|
+
Meteor.replaceSwcConfig = (customSwcConfig) =>
|
|
336
|
+
replaceSwcConfig(customSwcConfig);
|
|
289
337
|
Meteor.extendConfig = (...configs) => mergeSplitOverlap(...configs);
|
|
290
|
-
Meteor.disablePlugins = matchers =>
|
|
291
|
-
|
|
292
|
-
|
|
338
|
+
Meteor.disablePlugins = (matchers) =>
|
|
339
|
+
prepareMeteorRspackConfig({
|
|
340
|
+
disablePlugins: matchers,
|
|
341
|
+
});
|
|
342
|
+
Meteor.enablePortableBuild = () => enablePortableBuild();
|
|
293
343
|
|
|
294
344
|
// Add HtmlRspackPlugin function to Meteor
|
|
295
345
|
Meteor.HtmlRspackPlugin = (options = {}) => {
|
|
@@ -313,6 +363,51 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
313
363
|
});
|
|
314
364
|
};
|
|
315
365
|
|
|
366
|
+
// First pass: resolve user/override configs early so mode overrides (e.g. "production")
|
|
367
|
+
// are available before computing isProd/isDev and the rest of the build flags.
|
|
368
|
+
// Skipped for Angular since it manages its own mode via the second pass.
|
|
369
|
+
let { nextUserConfig, nextOverrideConfig } = isAngularEnabled
|
|
370
|
+
? {}
|
|
371
|
+
: await loadUserAndOverrideConfig(projectConfigPath, Meteor, argv);
|
|
372
|
+
|
|
373
|
+
// Determine the final mode with loaded configs
|
|
374
|
+
const currentMode = getModeFromConfig(nextUserConfig, nextOverrideConfig);
|
|
375
|
+
const isProd = currentMode
|
|
376
|
+
? currentMode === "production"
|
|
377
|
+
: !!Meteor.isProduction;
|
|
378
|
+
const isDev = currentMode
|
|
379
|
+
? currentMode === "development"
|
|
380
|
+
: !!Meteor.isDevelopment || !isProd;
|
|
381
|
+
const mode = isProd ? "production" : "development";
|
|
382
|
+
const isPortableBuild = !!(
|
|
383
|
+
nextUserConfig?.["meteor.enablePortableBuild"] ||
|
|
384
|
+
nextOverrideConfig?.["meteor.enablePortableBuild"]
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
// Determine entry points
|
|
388
|
+
const entryPath = Meteor.entryPath || "";
|
|
389
|
+
|
|
390
|
+
// Determine output points
|
|
391
|
+
const outputFilename = Meteor.outputFilename;
|
|
392
|
+
|
|
393
|
+
cacheStrategy = createCacheStrategy(
|
|
394
|
+
mode,
|
|
395
|
+
(Meteor.isClient && "client") || "server",
|
|
396
|
+
{ projectConfigPath, configPath }
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
// Determine run point
|
|
400
|
+
const runPath = Meteor.runPath || "";
|
|
401
|
+
|
|
402
|
+
// Determine banner
|
|
403
|
+
const bannerOutput = JSON.parse(
|
|
404
|
+
Meteor.bannerOutput || process.env.RSPACK_BANNER || '""'
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
// Determine output directories
|
|
408
|
+
const clientOutputDir = path.resolve(projectDir, "public");
|
|
409
|
+
const serverOutputDir = path.resolve(projectDir, "private");
|
|
410
|
+
|
|
316
411
|
// Get Meteor ignore entries
|
|
317
412
|
const meteorIgnoreEntries = getMeteorIgnoreEntries(projectDir);
|
|
318
413
|
|
|
@@ -328,21 +423,17 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
328
423
|
// Set default watch options
|
|
329
424
|
const watchOptions = {
|
|
330
425
|
ignored: [
|
|
331
|
-
...createIgnoreGlobConfig([
|
|
332
|
-
...meteorIgnoreEntries,
|
|
333
|
-
...additionalEntries,
|
|
334
|
-
]),
|
|
426
|
+
...createIgnoreGlobConfig([...meteorIgnoreEntries, ...additionalEntries]),
|
|
335
427
|
],
|
|
336
428
|
};
|
|
337
429
|
|
|
338
430
|
if (Meteor.isDebug || Meteor.isVerbose) {
|
|
339
|
-
console.log(
|
|
340
|
-
console.log(
|
|
431
|
+
console.log("[i] Rspack mode:", mode);
|
|
432
|
+
console.log("[i] Meteor flags:", Meteor);
|
|
341
433
|
}
|
|
342
434
|
|
|
343
|
-
const enableSwcExternalHelpers = !isServer && swcExternalHelpers;
|
|
344
435
|
const isDevEnvironment = isRun && isDev && !isTest && !isNative;
|
|
345
|
-
|
|
436
|
+
swcConfigRule = createSwcConfig({
|
|
346
437
|
isTypescriptEnabled,
|
|
347
438
|
isReactEnabled,
|
|
348
439
|
isJsxEnabled,
|
|
@@ -352,7 +443,6 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
352
443
|
isClient,
|
|
353
444
|
isAngularEnabled,
|
|
354
445
|
});
|
|
355
|
-
// Expose swc config to use in custom configs
|
|
356
446
|
Meteor.swcConfigOptions = swcConfigRule.options;
|
|
357
447
|
|
|
358
448
|
const externals = [
|
|
@@ -361,34 +451,34 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
361
451
|
...(isServer ? [/^bcrypt$/] : []),
|
|
362
452
|
];
|
|
363
453
|
const alias = {
|
|
364
|
-
|
|
454
|
+
"/": path.resolve(process.cwd()),
|
|
365
455
|
};
|
|
366
456
|
const fallback = {
|
|
367
457
|
...(isClient && makeWebNodeBuiltinsAlias()),
|
|
368
458
|
};
|
|
369
459
|
const extensions = [
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
460
|
+
".ts",
|
|
461
|
+
".tsx",
|
|
462
|
+
".mts",
|
|
463
|
+
".cts",
|
|
464
|
+
".js",
|
|
465
|
+
".jsx",
|
|
466
|
+
".mjs",
|
|
467
|
+
".cjs",
|
|
468
|
+
".json",
|
|
469
|
+
".wasm",
|
|
380
470
|
];
|
|
381
471
|
const extraRules = [];
|
|
382
472
|
|
|
383
473
|
const reactRefreshModule = isReactEnabled
|
|
384
|
-
? safeRequire(
|
|
474
|
+
? safeRequire("@rspack/plugin-react-refresh")
|
|
385
475
|
: null;
|
|
386
476
|
|
|
387
477
|
const requireExternalsPlugin = new RequireExternalsPlugin({
|
|
388
478
|
filePath: path.join(buildContext, runPath),
|
|
389
479
|
...(Meteor.isBlazeEnabled && {
|
|
390
480
|
externals: /\.html$/,
|
|
391
|
-
isEagerImport: module => module.endsWith(
|
|
481
|
+
isEagerImport: (module) => module.endsWith(".html"),
|
|
392
482
|
...(isProd && {
|
|
393
483
|
lastImports: [`./${outputFilename}`],
|
|
394
484
|
}),
|
|
@@ -398,25 +488,26 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
398
488
|
|
|
399
489
|
// Handle assets
|
|
400
490
|
const assetExternalsPlugin = new AssetExternalsPlugin();
|
|
401
|
-
const assetModuleFilename = _fileInfo => {
|
|
491
|
+
const assetModuleFilename = (_fileInfo) => {
|
|
402
492
|
const filename = _fileInfo.filename;
|
|
403
|
-
const isPublic = filename.startsWith(
|
|
493
|
+
const isPublic = filename.startsWith("/") || filename.startsWith("public");
|
|
404
494
|
if (isPublic) return `[name][ext][query]`;
|
|
405
495
|
return `${assetsContext}/[hash][ext][query]`;
|
|
406
496
|
};
|
|
407
497
|
|
|
408
498
|
const rsdoctorModule = isBundleVisualizerEnabled
|
|
409
|
-
? safeRequire(
|
|
499
|
+
? safeRequire("@rsdoctor/rspack-plugin")
|
|
410
500
|
: null;
|
|
411
|
-
const doctorPluginConfig =
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
501
|
+
const doctorPluginConfig =
|
|
502
|
+
isRun && isBundleVisualizerEnabled && rsdoctorModule?.RsdoctorRspackPlugin
|
|
503
|
+
? [
|
|
504
|
+
new rsdoctorModule.RsdoctorRspackPlugin({
|
|
505
|
+
port: isClient
|
|
506
|
+
? parseInt(Meteor.rsdoctorClientPort || "8888", 10)
|
|
507
|
+
: parseInt(Meteor.rsdoctorServerPort || "8889", 10),
|
|
508
|
+
}),
|
|
509
|
+
]
|
|
510
|
+
: [];
|
|
420
511
|
const bannerPluginConfig = !isBuild
|
|
421
512
|
? [
|
|
422
513
|
new BannerPlugin({
|
|
@@ -427,6 +518,10 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
427
518
|
: [];
|
|
428
519
|
// Not supported in Meteor yet (Rspack 1.7+ is enabled by default)
|
|
429
520
|
const lazyCompilationConfig = { lazyCompilation: false };
|
|
521
|
+
const shouldLogVerbose = isProfile || isVerbose;
|
|
522
|
+
const loggingConfig = shouldLogVerbose
|
|
523
|
+
? {}
|
|
524
|
+
: { stats: "errors-warnings", infrastructureLogging: { level: "warn" } };
|
|
430
525
|
|
|
431
526
|
const clientEntry =
|
|
432
527
|
isClient && isTest && isTestEager && isTestFullApp
|
|
@@ -454,16 +549,11 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
454
549
|
: isClient && isTest && testEntry
|
|
455
550
|
? path.resolve(process.cwd(), testEntry)
|
|
456
551
|
: path.resolve(process.cwd(), buildContext, entryPath);
|
|
457
|
-
|
|
458
|
-
"--> (rspack.config.js-Line: 431)\n clientEntry: ",
|
|
459
|
-
clientEntry,
|
|
460
|
-
entryPath
|
|
461
|
-
);
|
|
462
|
-
const clientNameConfig = `[${(isTest && 'test-') || ''}client-rspack]`;
|
|
552
|
+
const clientNameConfig = `[${(isTest && "test-") || ""}client-rspack]`;
|
|
463
553
|
// Base client config
|
|
464
554
|
let clientConfig = {
|
|
465
555
|
name: clientNameConfig,
|
|
466
|
-
target:
|
|
556
|
+
target: "web",
|
|
467
557
|
mode,
|
|
468
558
|
entry: clientEntry,
|
|
469
559
|
output: {
|
|
@@ -472,7 +562,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
472
562
|
const chunkName = _module.chunk?.name;
|
|
473
563
|
const isMainChunk = !chunkName || chunkName === "main";
|
|
474
564
|
const chunkSuffix = `${chunksContext}/[id]${
|
|
475
|
-
isProd ?
|
|
565
|
+
isProd ? ".[chunkhash]" : ""
|
|
476
566
|
}.js`;
|
|
477
567
|
if (isDevEnvironment) {
|
|
478
568
|
if (isMainChunk) return outputFilename;
|
|
@@ -481,21 +571,21 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
481
571
|
if (isMainChunk) return `../${buildContext}/${outputPath}`;
|
|
482
572
|
return chunkSuffix;
|
|
483
573
|
},
|
|
484
|
-
libraryTarget:
|
|
485
|
-
publicPath:
|
|
486
|
-
chunkFilename: `${chunksContext}/[id]${isProd ?
|
|
574
|
+
libraryTarget: "commonjs2",
|
|
575
|
+
publicPath: "/",
|
|
576
|
+
chunkFilename: `${chunksContext}/[id]${isProd ? ".[chunkhash]" : ""}.js`,
|
|
487
577
|
assetModuleFilename,
|
|
488
578
|
cssFilename: `${chunksContext}/[name]${
|
|
489
|
-
isProd ?
|
|
579
|
+
isProd ? ".[contenthash]" : ""
|
|
490
580
|
}.css`,
|
|
491
581
|
cssChunkFilename: `${chunksContext}/[id]${
|
|
492
|
-
isProd ?
|
|
582
|
+
isProd ? ".[contenthash]" : ""
|
|
493
583
|
}.css`,
|
|
494
584
|
...(isProd && { clean: { keep: keepOutsideBuild() } }),
|
|
495
585
|
},
|
|
496
586
|
optimization: {
|
|
497
587
|
usedExports: true,
|
|
498
|
-
splitChunks: { chunks:
|
|
588
|
+
splitChunks: { chunks: "async" },
|
|
499
589
|
},
|
|
500
590
|
module: {
|
|
501
591
|
rules: [
|
|
@@ -504,7 +594,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
504
594
|
? [
|
|
505
595
|
{
|
|
506
596
|
test: /\.html$/i,
|
|
507
|
-
loader:
|
|
597
|
+
loader: "ignore-loader",
|
|
508
598
|
},
|
|
509
599
|
]
|
|
510
600
|
: []),
|
|
@@ -522,38 +612,52 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
522
612
|
assetExternalsPlugin,
|
|
523
613
|
].filter(Boolean),
|
|
524
614
|
new DefinePlugin({
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
615
|
+
"Meteor.isClient": JSON.stringify(true),
|
|
616
|
+
"Meteor.isServer": JSON.stringify(false),
|
|
617
|
+
"Meteor.isTest": JSON.stringify(isTestLike && !isTestFullApp),
|
|
618
|
+
"Meteor.isAppTest": JSON.stringify(isTestLike && isTestFullApp),
|
|
619
|
+
...(!isPortableBuild && {
|
|
620
|
+
"Meteor.isDevelopment": JSON.stringify(isDev),
|
|
621
|
+
"Meteor.isProduction": JSON.stringify(isProd),
|
|
622
|
+
}),
|
|
531
623
|
}),
|
|
532
624
|
...bannerPluginConfig,
|
|
533
625
|
Meteor.HtmlRspackPlugin(),
|
|
534
626
|
...doctorPluginConfig,
|
|
535
627
|
new NormalModuleReplacementPlugin(/^node:(.*)$/, (res) => {
|
|
536
|
-
res.request = res.request.replace(/^node:/,
|
|
628
|
+
res.request = res.request.replace(/^node:/, "");
|
|
537
629
|
}),
|
|
538
630
|
],
|
|
539
631
|
watchOptions,
|
|
540
|
-
devtool:
|
|
632
|
+
devtool:
|
|
633
|
+
isDevEnvironment || isNative || isTest
|
|
634
|
+
? "source-map"
|
|
635
|
+
: "hidden-source-map",
|
|
541
636
|
...(isDevEnvironment && {
|
|
542
637
|
devServer: {
|
|
543
638
|
...createRemoteDevServerConfig(),
|
|
544
|
-
static: { directory: clientOutputDir, publicPath:
|
|
639
|
+
static: { directory: clientOutputDir, publicPath: "/__rspack__/" },
|
|
545
640
|
hot: true,
|
|
546
641
|
liveReload: true,
|
|
547
642
|
...(Meteor.isBlazeEnabled && { hot: false }),
|
|
548
|
-
port:
|
|
643
|
+
port: devServerPort,
|
|
549
644
|
devMiddleware: {
|
|
550
|
-
writeToDisk: filePath =>
|
|
551
|
-
/\.(html)$/.test(filePath) && !filePath.includes(
|
|
645
|
+
writeToDisk: (filePath) =>
|
|
646
|
+
/\.(html)$/.test(filePath) && !filePath.includes(".hot-update."),
|
|
647
|
+
},
|
|
648
|
+
onListening(devServer) {
|
|
649
|
+
if (!devServer) return;
|
|
650
|
+
const { host, port } = devServer.options;
|
|
651
|
+
const protocol =
|
|
652
|
+
devServer.options.server?.type === "https" ? "https" : "http";
|
|
653
|
+
const devServerUrl = `${protocol}://${host || "localhost"}:${port}`;
|
|
654
|
+
outputMeteorRspack({ devServerUrl });
|
|
552
655
|
},
|
|
553
656
|
},
|
|
554
657
|
}),
|
|
555
658
|
...merge(cacheStrategy, { experiments: { css: true } }),
|
|
556
659
|
...lazyCompilationConfig,
|
|
660
|
+
...loggingConfig,
|
|
557
661
|
};
|
|
558
662
|
|
|
559
663
|
const serverEntry =
|
|
@@ -580,23 +684,18 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
580
684
|
: isServer && isTest && testEntry
|
|
581
685
|
? path.resolve(process.cwd(), testEntry)
|
|
582
686
|
: path.resolve(projectDir, buildContext, entryPath);
|
|
583
|
-
const serverNameConfig = `[${(isTest &&
|
|
584
|
-
console.log(
|
|
585
|
-
"--> (rspack.config.js-Line: 576)\n serverEntry: ",
|
|
586
|
-
serverEntry,
|
|
587
|
-
entryPath
|
|
588
|
-
);
|
|
687
|
+
const serverNameConfig = `[${(isTest && "test-") || ""}server-rspack]`;
|
|
589
688
|
// Base server config
|
|
590
689
|
let serverConfig = {
|
|
591
690
|
name: serverNameConfig,
|
|
592
|
-
target:
|
|
691
|
+
target: "node",
|
|
593
692
|
mode,
|
|
594
693
|
entry: serverEntry,
|
|
595
694
|
output: {
|
|
596
695
|
path: serverOutputDir,
|
|
597
696
|
filename: () => `../${buildContext}/${outputPath}`,
|
|
598
|
-
libraryTarget:
|
|
599
|
-
chunkFilename: `${chunksContext}/[id]${isProd ?
|
|
697
|
+
libraryTarget: "commonjs2",
|
|
698
|
+
chunkFilename: `${chunksContext}/[id]${isProd ? ".[chunkhash]" : ""}.js`,
|
|
600
699
|
assetModuleFilename,
|
|
601
700
|
...(isProd && { clean: { keep: keepOutsideBuild() } }),
|
|
602
701
|
},
|
|
@@ -610,15 +709,15 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
610
709
|
parser: {
|
|
611
710
|
javascript: {
|
|
612
711
|
// Dynamic imports on the server are treated as bundled in the same chunk
|
|
613
|
-
dynamicImportMode:
|
|
712
|
+
dynamicImportMode: "eager",
|
|
614
713
|
},
|
|
615
714
|
},
|
|
616
715
|
},
|
|
617
716
|
resolve: {
|
|
618
717
|
extensions,
|
|
619
718
|
alias,
|
|
620
|
-
modules: [
|
|
621
|
-
conditionNames: [
|
|
719
|
+
modules: ["node_modules", path.resolve(projectDir)],
|
|
720
|
+
conditionNames: ["import", "require", "node", "default"],
|
|
622
721
|
},
|
|
623
722
|
externals,
|
|
624
723
|
externalsPresets: { node: true },
|
|
@@ -626,18 +725,22 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
626
725
|
new DefinePlugin(
|
|
627
726
|
isTest && (isTestModule || isTestEager)
|
|
628
727
|
? {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
728
|
+
"Meteor.isTest": JSON.stringify(isTest && !isTestFullApp),
|
|
729
|
+
"Meteor.isAppTest": JSON.stringify(isTest && isTestFullApp),
|
|
730
|
+
...(!isPortableBuild && {
|
|
731
|
+
"Meteor.isDevelopment": JSON.stringify(isDev),
|
|
732
|
+
}),
|
|
632
733
|
}
|
|
633
734
|
: {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
735
|
+
"Meteor.isClient": JSON.stringify(false),
|
|
736
|
+
"Meteor.isServer": JSON.stringify(true),
|
|
737
|
+
"Meteor.isTest": JSON.stringify(isTestLike && !isTestFullApp),
|
|
738
|
+
"Meteor.isAppTest": JSON.stringify(isTestLike && isTestFullApp),
|
|
739
|
+
...(!isPortableBuild && {
|
|
740
|
+
"Meteor.isDevelopment": JSON.stringify(isDev),
|
|
741
|
+
"Meteor.isProduction": JSON.stringify(isProd),
|
|
742
|
+
}),
|
|
743
|
+
}
|
|
641
744
|
),
|
|
642
745
|
...bannerPluginConfig,
|
|
643
746
|
requireExternalsPlugin,
|
|
@@ -645,104 +748,21 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
645
748
|
...doctorPluginConfig,
|
|
646
749
|
],
|
|
647
750
|
watchOptions,
|
|
648
|
-
devtool:
|
|
751
|
+
devtool:
|
|
752
|
+
isDevEnvironment || isNative || isTest
|
|
753
|
+
? "source-map"
|
|
754
|
+
: "hidden-source-map",
|
|
649
755
|
...((isDevEnvironment || (isTest && !isTestEager) || isNative) &&
|
|
650
756
|
cacheStrategy),
|
|
651
757
|
...lazyCompilationConfig,
|
|
758
|
+
...loggingConfig,
|
|
652
759
|
};
|
|
653
760
|
|
|
654
|
-
// Helper function to load and process config files
|
|
655
|
-
async function loadAndProcessConfig(configPath, configType, Meteor, argv, isAngularEnabled) {
|
|
656
|
-
try {
|
|
657
|
-
// Load the config file
|
|
658
|
-
let config;
|
|
659
|
-
if (path.extname(configPath) === '.mjs') {
|
|
660
|
-
// For ESM modules, we need to use dynamic import
|
|
661
|
-
const fileUrl = `file://${configPath}`;
|
|
662
|
-
const module = await import(fileUrl);
|
|
663
|
-
config = module.default || module;
|
|
664
|
-
} else {
|
|
665
|
-
// For CommonJS modules, we can use require
|
|
666
|
-
config = require(configPath)?.default || require(configPath);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
// Process the config
|
|
670
|
-
const rawConfig = typeof config === 'function' ? config(Meteor, argv) : config;
|
|
671
|
-
const resolvedConfig = await Promise.resolve(rawConfig);
|
|
672
|
-
const userConfig = resolvedConfig && '0' in resolvedConfig ? resolvedConfig[0] : resolvedConfig;
|
|
673
|
-
|
|
674
|
-
// Define omitted paths and warning function
|
|
675
|
-
const omitPaths = [
|
|
676
|
-
"name",
|
|
677
|
-
"target",
|
|
678
|
-
"entry",
|
|
679
|
-
"output.path",
|
|
680
|
-
"output.filename",
|
|
681
|
-
...(Meteor.isServer ? ["optimization.splitChunks", "optimization.runtimeChunk"] : []),
|
|
682
|
-
].filter(Boolean);
|
|
683
|
-
|
|
684
|
-
const warningFn = path => {
|
|
685
|
-
if (isAngularEnabled) return;
|
|
686
|
-
console.warn(
|
|
687
|
-
`[${configType}] Ignored custom "${path}" — reserved for Meteor-Rspack integration.`,
|
|
688
|
-
);
|
|
689
|
-
};
|
|
690
|
-
|
|
691
|
-
// Clean omitted paths and merge Meteor Rspack fragments
|
|
692
|
-
let nextConfig = cleanOmittedPaths(userConfig, {
|
|
693
|
-
omitPaths,
|
|
694
|
-
warningFn,
|
|
695
|
-
});
|
|
696
|
-
nextConfig = mergeMeteorRspackFragments(nextConfig);
|
|
697
|
-
|
|
698
|
-
return nextConfig;
|
|
699
|
-
} catch (error) {
|
|
700
|
-
console.error(`Error loading ${configType} from ${configPath}:`, error);
|
|
701
|
-
if (configType === 'rspack.config.js') {
|
|
702
|
-
throw error; // Only rethrow for project config
|
|
703
|
-
}
|
|
704
|
-
return null;
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// Load and apply project-level overrides for the selected build
|
|
709
|
-
// Check if we're in a Meteor package directory by looking at the path
|
|
710
|
-
const isMeteorPackageConfig = projectDir.includes('/packages/rspack');
|
|
711
|
-
if (fs.existsSync(projectConfigPath) && !isMeteorPackageConfig) {
|
|
712
|
-
// Check if there's a .mjs or .cjs version of the config file
|
|
713
|
-
const mjsConfigPath = projectConfigPath.replace(/\.js$/, '.mjs');
|
|
714
|
-
const cjsConfigPath = projectConfigPath.replace(/\.js$/, '.cjs');
|
|
715
|
-
|
|
716
|
-
let projectConfigPathToUse = projectConfigPath;
|
|
717
|
-
if (fs.existsSync(mjsConfigPath)) {
|
|
718
|
-
projectConfigPathToUse = mjsConfigPath;
|
|
719
|
-
} else if (fs.existsSync(cjsConfigPath)) {
|
|
720
|
-
projectConfigPathToUse = cjsConfigPath;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const nextUserConfig = await loadAndProcessConfig(
|
|
724
|
-
projectConfigPathToUse,
|
|
725
|
-
'rspack.config.js',
|
|
726
|
-
Meteor,
|
|
727
|
-
argv,
|
|
728
|
-
isAngularEnabled
|
|
729
|
-
);
|
|
730
|
-
|
|
731
|
-
if (nextUserConfig) {
|
|
732
|
-
if (Meteor.isClient) {
|
|
733
|
-
clientConfig = mergeSplitOverlap(clientConfig, nextUserConfig);
|
|
734
|
-
}
|
|
735
|
-
if (Meteor.isServer) {
|
|
736
|
-
serverConfig = mergeSplitOverlap(serverConfig, nextUserConfig);
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
|
|
741
761
|
// Establish Angular overrides to ensure proper integration
|
|
742
762
|
const angularExpandConfig = isAngularEnabled
|
|
743
763
|
? {
|
|
744
764
|
mode: isProd ? "production" : "development",
|
|
745
|
-
devServer: { port:
|
|
765
|
+
devServer: { port: devServerPort },
|
|
746
766
|
stats: { preset: "normal" },
|
|
747
767
|
infrastructureLogging: { level: "info" },
|
|
748
768
|
...(isProd && isClient && { output: { module: false } }),
|
|
@@ -769,34 +789,31 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
769
789
|
}
|
|
770
790
|
: {};
|
|
771
791
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
792
|
+
// Second pass: re-run only when a mode override was detected, so the user config
|
|
793
|
+
// can depend on fully-computed Meteor flags and helpers (swcConfigOptions, buildOutputDir, etc.).
|
|
794
|
+
if (nextUserConfig?.mode || nextOverrideConfig?.mode || isAngularEnabled) {
|
|
795
|
+
({ nextUserConfig, nextOverrideConfig } = await loadUserAndOverrideConfig(
|
|
796
|
+
projectConfigPath,
|
|
797
|
+
Meteor,
|
|
798
|
+
argv
|
|
799
|
+
));
|
|
800
|
+
}
|
|
801
|
+
let statsOverrided = false;
|
|
802
|
+
let config = isClient ? clientConfig : serverConfig;
|
|
803
|
+
if (nextUserConfig) {
|
|
804
|
+
config = mergeSplitOverlap(config, nextUserConfig);
|
|
805
|
+
if (nextUserConfig.stats != null) {
|
|
806
|
+
statsOverrided = true;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
config = mergeSplitOverlap(config, angularExpandConfig);
|
|
776
811
|
config = mergeSplitOverlap(config, testClientExpandConfig);
|
|
777
812
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
const configExt = path.extname(configFileName);
|
|
783
|
-
const configNameWithoutExt = configFileName.replace(configExt, '');
|
|
784
|
-
const configNameFull = `${configNameWithoutExt}.override${configExt}`;
|
|
785
|
-
const overrideConfigPath = path.join(configDir, configNameFull);
|
|
786
|
-
|
|
787
|
-
if (fs.existsSync(overrideConfigPath)) {
|
|
788
|
-
const nextOverrideConfig = await loadAndProcessConfig(
|
|
789
|
-
overrideConfigPath,
|
|
790
|
-
configNameFull,
|
|
791
|
-
Meteor,
|
|
792
|
-
argv,
|
|
793
|
-
isAngularEnabled
|
|
794
|
-
);
|
|
795
|
-
|
|
796
|
-
if (nextOverrideConfig) {
|
|
797
|
-
// Apply override config as the last step
|
|
798
|
-
config = mergeSplitOverlap(config, nextOverrideConfig);
|
|
799
|
-
}
|
|
813
|
+
if (nextOverrideConfig) {
|
|
814
|
+
config = mergeSplitOverlap(config, nextOverrideConfig);
|
|
815
|
+
if (nextOverrideConfig.stats != null) {
|
|
816
|
+
statsOverrided = true;
|
|
800
817
|
}
|
|
801
818
|
}
|
|
802
819
|
|
|
@@ -806,18 +823,38 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
806
823
|
delete config.disablePlugins;
|
|
807
824
|
}
|
|
808
825
|
|
|
826
|
+
delete config["meteor.enablePortableBuild"];
|
|
827
|
+
|
|
809
828
|
if (Meteor.isDebug || Meteor.isVerbose) {
|
|
810
|
-
|
|
829
|
+
console.log("Config:", inspect(config, { depth: null, colors: true }));
|
|
811
830
|
}
|
|
812
831
|
|
|
813
832
|
// Check if lazyCompilation is enabled and warn the user
|
|
814
|
-
if (
|
|
833
|
+
if (
|
|
834
|
+
config.lazyCompilation === true ||
|
|
835
|
+
typeof config.lazyCompilation === "object"
|
|
836
|
+
) {
|
|
815
837
|
console.warn(
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
838
|
+
"\n⚠️ Warning: lazyCompilation may not work correctly in the current Meteor-Rspack integration.\n" +
|
|
839
|
+
" This feature will be evaluated for support in future Meteor versions.\n" +
|
|
840
|
+
" If you encounter any issues, please disable it in your rspack config.\n"
|
|
819
841
|
);
|
|
820
842
|
}
|
|
821
843
|
|
|
844
|
+
// Add MeteorRspackOutputPlugin as the last plugin to output compilation info
|
|
845
|
+
const meteorRspackOutputPlugin = new MeteorRspackOutputPlugin({
|
|
846
|
+
getData: (stats, { isRebuild, compilationCount }) => ({
|
|
847
|
+
name: config.name,
|
|
848
|
+
mode: config.mode,
|
|
849
|
+
hasErrors: stats.hasErrors(),
|
|
850
|
+
hasWarnings: stats.hasWarnings(),
|
|
851
|
+
timestamp: Date.now(),
|
|
852
|
+
statsOverrided,
|
|
853
|
+
compilationCount,
|
|
854
|
+
isRebuild,
|
|
855
|
+
}),
|
|
856
|
+
});
|
|
857
|
+
config.plugins = [meteorRspackOutputPlugin, ...(config.plugins || [])];
|
|
858
|
+
|
|
822
859
|
return [config];
|
|
823
860
|
}
|