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