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