@meteorjs/rspack 1.1.0-beta.22 → 1.1.0-beta.30
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/index.d.ts +0 -6
- package/lib/ignore.js +1 -1
- package/lib/meteorRspackHelpers.js +7 -14
- package/lib/test.js +23 -4
- package/package.json +1 -1
- package/plugins/MeteorRspackOutputPlugin.js +36 -0
- package/rspack.config.js +317 -238
- package/lib/meteorRspackConfigHelpers.js +0 -121
package/index.d.ts
CHANGED
|
@@ -75,12 +75,6 @@ type MeteorEnv = Record<string, any> & {
|
|
|
75
75
|
disablePlugins: (
|
|
76
76
|
matchers: string | RegExp | ((plugin: any, index: number) => boolean) | Array<string | RegExp | ((plugin: any, index: number) => boolean)>
|
|
77
77
|
) => Record<string, any>;
|
|
78
|
-
/**
|
|
79
|
-
* Omit `Meteor.isDevelopment` and `Meteor.isProduction` from the DefinePlugin so
|
|
80
|
-
* the bundle is not tied to a specific Meteor environment (portable / isomorphic builds).
|
|
81
|
-
* @returns A config fragment with `meteor.enablePortableBuild: true`
|
|
82
|
-
*/
|
|
83
|
-
enablePortableBuild: () => Record<string, any>;
|
|
84
78
|
}
|
|
85
79
|
|
|
86
80
|
export type ConfigFactory = (
|
package/lib/ignore.js
CHANGED
|
@@ -117,7 +117,7 @@ function createIgnoreRegex(globPatterns) {
|
|
|
117
117
|
|
|
118
118
|
// For absolute paths, we don't want to force the pattern to match from the beginning
|
|
119
119
|
// but we still want to ensure it matches to the end of the path segment
|
|
120
|
-
regexPattern = '(?:^|/)' + regexPattern
|
|
120
|
+
regexPattern = '(?:^|/)' + regexPattern;
|
|
121
121
|
|
|
122
122
|
return regexPattern;
|
|
123
123
|
}).filter(pattern => pattern !== null);
|
|
@@ -152,19 +152,6 @@ function extendSwcConfig(swcConfig) {
|
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
/**
|
|
156
|
-
* Signal that `Meteor.isDevelopment` and `Meteor.isProduction` should be omitted
|
|
157
|
-
* from DefinePlugin, making the bundle portable across Meteor environments.
|
|
158
|
-
* Usage: return Meteor.enablePortableBuild() in your rspack.config.js
|
|
159
|
-
*
|
|
160
|
-
* @returns {Record<string, object>} config fragment with `meteor.enablePortableBuild: true`
|
|
161
|
-
*/
|
|
162
|
-
function enablePortableBuild() {
|
|
163
|
-
return prepareMeteorRspackConfig({
|
|
164
|
-
"meteor.enablePortableBuild": true,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
155
|
/**
|
|
169
156
|
* Remove plugins from a Rspack config by name, RegExp, predicate, or array of them.
|
|
170
157
|
* When using a function predicate, it receives both the plugin and its index in the plugins array.
|
|
@@ -215,6 +202,12 @@ function disablePlugins(config, matchers) {
|
|
|
215
202
|
return config;
|
|
216
203
|
}
|
|
217
204
|
|
|
205
|
+
function outputMeteorRspack(data) {
|
|
206
|
+
const jsonString = JSON.stringify(data);
|
|
207
|
+
const output = `[Meteor-Rspack]${jsonString}[/Meteor-Rspack]`;
|
|
208
|
+
console.log(output);
|
|
209
|
+
}
|
|
210
|
+
|
|
218
211
|
module.exports = {
|
|
219
212
|
compileWithMeteor,
|
|
220
213
|
compileWithRspack,
|
|
@@ -223,5 +216,5 @@ module.exports = {
|
|
|
223
216
|
extendSwcConfig,
|
|
224
217
|
makeWebNodeBuiltinsAlias,
|
|
225
218
|
disablePlugins,
|
|
226
|
-
|
|
219
|
+
outputMeteorRspack,
|
|
227
220
|
};
|
package/lib/test.js
CHANGED
|
@@ -9,6 +9,7 @@ const { createIgnoreRegex, createIgnoreGlobConfig } = require("./ignore.js");
|
|
|
9
9
|
* @param {string} options.projectDir - The project directory
|
|
10
10
|
* @param {string} options.buildContext - The build context
|
|
11
11
|
* @param {string[]} options.ignoreEntries - Array of ignore patterns
|
|
12
|
+
* @param {string[]} options.meteorIgnoreEntries - Array of meteor ignore patterns
|
|
12
13
|
* @param {string} options.extraEntry - Extra entry to load
|
|
13
14
|
* @returns {string} The path to the generated file
|
|
14
15
|
*/
|
|
@@ -17,6 +18,7 @@ const generateEagerTestFile = ({
|
|
|
17
18
|
projectDir,
|
|
18
19
|
buildContext,
|
|
19
20
|
ignoreEntries: inIgnoreEntries = [],
|
|
21
|
+
meteorIgnoreEntries: inMeteorIgnoreEntries = [],
|
|
20
22
|
prefix: inPrefix = '',
|
|
21
23
|
extraEntry,
|
|
22
24
|
globalImportPath,
|
|
@@ -40,6 +42,11 @@ const generateEagerTestFile = ({
|
|
|
40
42
|
const excludeFoldersRegex = createIgnoreRegex(
|
|
41
43
|
createIgnoreGlobConfig(ignoreEntries)
|
|
42
44
|
);
|
|
45
|
+
console.log("inMeteorIgnoreEntries", inMeteorIgnoreEntries);
|
|
46
|
+
// Create regex from meteor ignore entries
|
|
47
|
+
const excludeMeteorIgnoreRegex = inMeteorIgnoreEntries.length > 0
|
|
48
|
+
? createIgnoreRegex(createIgnoreGlobConfig(inMeteorIgnoreEntries))
|
|
49
|
+
: null;
|
|
43
50
|
|
|
44
51
|
const prefix = (inPrefix && `${inPrefix}-`) || "";
|
|
45
52
|
const filename = isAppTest
|
|
@@ -51,15 +58,27 @@ const generateEagerTestFile = ({
|
|
|
51
58
|
: "/\\.(?:test|spec)s?\\.[^.]+$/";
|
|
52
59
|
|
|
53
60
|
const content = `${
|
|
54
|
-
globalImportPath ? `import '${globalImportPath}';\n\n` :
|
|
55
|
-
}{
|
|
56
|
-
|
|
61
|
+
globalImportPath ? `import '${globalImportPath}';\n\n` : ""
|
|
62
|
+
}${
|
|
63
|
+
excludeMeteorIgnoreRegex
|
|
64
|
+
? `const MeteorIgnoreRegex = ${excludeMeteorIgnoreRegex.toString()};`
|
|
65
|
+
: ""
|
|
66
|
+
}
|
|
67
|
+
{
|
|
68
|
+
const ctx = import.meta.webpackContext('${projectDir}', {
|
|
57
69
|
recursive: true,
|
|
58
70
|
regExp: ${regExp},
|
|
59
71
|
exclude: ${excludeFoldersRegex.toString()},
|
|
60
72
|
mode: 'eager',
|
|
61
73
|
});
|
|
62
|
-
ctx.keys().
|
|
74
|
+
ctx.keys().filter((k) => {
|
|
75
|
+
${
|
|
76
|
+
excludeMeteorIgnoreRegex
|
|
77
|
+
? `// Only exclude based on *relative* path segments.
|
|
78
|
+
return !MeteorIgnoreRegex.test(k);`
|
|
79
|
+
: "return true;"
|
|
80
|
+
}
|
|
81
|
+
}).forEach(ctx);
|
|
63
82
|
${
|
|
64
83
|
extraEntry
|
|
65
84
|
? `const extra = import.meta.webpackContext('${path.dirname(
|
package/package.json
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// MeteorRspackOutputPlugin.js
|
|
2
|
+
//
|
|
3
|
+
// This plugin outputs a JSON stringified with a tag delimiter each time
|
|
4
|
+
// a new Rspack compilation happens. The JSON content is configurable
|
|
5
|
+
// via plugin instantiation options.
|
|
6
|
+
|
|
7
|
+
const { outputMeteorRspack } = require('../lib/meteorRspackHelpers');
|
|
8
|
+
|
|
9
|
+
class MeteorRspackOutputPlugin {
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
this.pluginName = 'MeteorRspackOutputPlugin';
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.compilationCount = 0;
|
|
14
|
+
// The data to be output as JSON, can be a static object or a function
|
|
15
|
+
this.getData =
|
|
16
|
+
typeof options.getData === 'function'
|
|
17
|
+
? options.getData
|
|
18
|
+
: () => options.data || {};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
apply(compiler) {
|
|
22
|
+
// Hook into the 'done' event which fires after each compilation completes
|
|
23
|
+
compiler.hooks.done.tap(this.pluginName, stats => {
|
|
24
|
+
this.compilationCount++;
|
|
25
|
+
const data = {
|
|
26
|
+
...(this.getData(stats, {
|
|
27
|
+
compilationCount: this.compilationCount,
|
|
28
|
+
isRebuild: this.compilationCount > 1,
|
|
29
|
+
}) || {}),
|
|
30
|
+
};
|
|
31
|
+
outputMeteorRspack(data);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = { MeteorRspackOutputPlugin };
|
package/rspack.config.js
CHANGED
|
@@ -10,8 +10,10 @@ 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");
|
|
16
|
+
const { mergeMeteorRspackFragments } = require("./lib/meteorRspackConfigFactory.js");
|
|
15
17
|
const {
|
|
16
18
|
compileWithMeteor,
|
|
17
19
|
compileWithRspack,
|
|
@@ -20,9 +22,8 @@ const {
|
|
|
20
22
|
extendSwcConfig,
|
|
21
23
|
makeWebNodeBuiltinsAlias,
|
|
22
24
|
disablePlugins,
|
|
23
|
-
|
|
25
|
+
outputMeteorRspack,
|
|
24
26
|
} = require('./lib/meteorRspackHelpers.js');
|
|
25
|
-
const { loadUserAndOverrideConfig } = require('./lib/meteorRspackConfigHelpers.js');
|
|
26
27
|
const { prepareMeteorRspackConfig } = require("./lib/meteorRspackConfigFactory");
|
|
27
28
|
|
|
28
29
|
// Safe require that doesn't throw if the module isn't found
|
|
@@ -41,7 +42,11 @@ function safeRequire(moduleName) {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
// Persistent filesystem cache strategy
|
|
44
|
-
function createCacheStrategy(
|
|
45
|
+
function createCacheStrategy(
|
|
46
|
+
mode,
|
|
47
|
+
side,
|
|
48
|
+
{ projectConfigPath, configPath, buildContext } = {},
|
|
49
|
+
) {
|
|
45
50
|
// Check for configuration files
|
|
46
51
|
const tsconfigPath = path.join(process.cwd(), 'tsconfig.json');
|
|
47
52
|
const hasTsconfig = fs.existsSync(tsconfigPath);
|
|
@@ -82,7 +87,9 @@ function createCacheStrategy(mode, side, { projectConfigPath, configPath } = {})
|
|
|
82
87
|
type: "persistent",
|
|
83
88
|
storage: {
|
|
84
89
|
type: "filesystem",
|
|
85
|
-
directory: `node_modules/.cache/rspack${
|
|
90
|
+
directory: `node_modules/.cache/rspack${
|
|
91
|
+
(buildContext && `-${buildContext}`) || ''
|
|
92
|
+
}${(side && `/${side}`) || ''}`,
|
|
86
93
|
},
|
|
87
94
|
...(buildDependencies.length > 0 && {
|
|
88
95
|
buildDependencies: buildDependencies,
|
|
@@ -205,29 +212,15 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
205
212
|
const Meteor = { ...inMeteor };
|
|
206
213
|
// Convert string boolean values to actual booleans
|
|
207
214
|
for (const key in Meteor) {
|
|
208
|
-
if (Meteor[key] ===
|
|
215
|
+
if (Meteor[key] === 'true' || Meteor[key] === true) {
|
|
209
216
|
Meteor[key] = true;
|
|
210
|
-
} else if (Meteor[key] ===
|
|
217
|
+
} else if (Meteor[key] === 'false' || Meteor[key] === false) {
|
|
211
218
|
Meteor[key] = false;
|
|
212
219
|
}
|
|
213
220
|
}
|
|
214
221
|
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
const isNative = !!Meteor.isNative;
|
|
218
|
-
const devServerPort = Meteor.devServerPort || 8080;
|
|
219
|
-
|
|
220
|
-
const projectDir = process.cwd();
|
|
221
|
-
const projectConfigPath =
|
|
222
|
-
Meteor.projectConfigPath || path.resolve(projectDir, "rspack.config.js");
|
|
223
|
-
|
|
224
|
-
// Compute build paths before loading user config (needed by Meteor helpers below)
|
|
225
|
-
const buildContext = Meteor.buildContext || "_build";
|
|
226
|
-
const outputPath = Meteor.outputPath;
|
|
227
|
-
const outputDir = path.dirname(Meteor.outputPath || "");
|
|
228
|
-
Meteor.buildOutputDir = path.resolve(projectDir, buildContext, outputDir);
|
|
229
|
-
|
|
230
|
-
// Meteor flags derived purely from input; independent of loaded user/override configs
|
|
222
|
+
const isProd = !!Meteor.isProduction || argv.mode === 'production';
|
|
223
|
+
const isDev = !!Meteor.isDevelopment || !isProd;
|
|
231
224
|
const isTest = !!Meteor.isTest;
|
|
232
225
|
const isClient = !!Meteor.isClient;
|
|
233
226
|
const isServer = !!Meteor.isServer;
|
|
@@ -237,6 +230,17 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
237
230
|
const isTestModule = !!Meteor.isTestModule;
|
|
238
231
|
const isTestEager = !!Meteor.isTestEager;
|
|
239
232
|
const isTestFullApp = !!Meteor.isTestFullApp;
|
|
233
|
+
const isTestLike = !!Meteor.isTestLike;
|
|
234
|
+
const swcExternalHelpers = !!Meteor.swcExternalHelpers;
|
|
235
|
+
const isNative = !!Meteor.isNative;
|
|
236
|
+
const isProfile = !!Meteor.isProfile;
|
|
237
|
+
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
|
+
const configPath = Meteor.configPath;
|
|
242
|
+
const testEntry = Meteor.testEntry;
|
|
243
|
+
|
|
240
244
|
const isTypescriptEnabled = Meteor.isTypescriptEnabled || false;
|
|
241
245
|
const isJsxEnabled =
|
|
242
246
|
Meteor.isJsxEnabled || (!isTypescriptEnabled && isReactEnabled) || false;
|
|
@@ -244,65 +248,70 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
244
248
|
Meteor.isTsxEnabled || (isTypescriptEnabled && isReactEnabled) || false;
|
|
245
249
|
const isBundleVisualizerEnabled = Meteor.isBundleVisualizerEnabled || false;
|
|
246
250
|
const isAngularEnabled = Meteor.isAngularEnabled || false;
|
|
247
|
-
const enableSwcExternalHelpers = !isServer && swcExternalHelpers;
|
|
248
251
|
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
252
|
+
// Determine entry points
|
|
253
|
+
const entryPath = Meteor.entryPath;
|
|
254
|
+
|
|
255
|
+
// Determine output points
|
|
256
|
+
const outputPath = Meteor.outputPath;
|
|
257
|
+
const outputDir = path.dirname(Meteor.outputPath || '');
|
|
258
|
+
|
|
259
|
+
const outputFilename = Meteor.outputFilename;
|
|
260
|
+
|
|
261
|
+
// Determine run point
|
|
262
|
+
const runPath = Meteor.runPath;
|
|
263
|
+
|
|
264
|
+
// Determine banner
|
|
265
|
+
const bannerOutput = JSON.parse(Meteor.bannerOutput || process.env.RSPACK_BANNER || '""');
|
|
259
266
|
|
|
260
|
-
//
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
?
|
|
267
|
-
:
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
{
|
|
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;
|
|
291
|
+
|
|
292
|
+
const cacheStrategy = createCacheStrategy(
|
|
293
|
+
mode,
|
|
294
|
+
(Meteor.isClient && 'client') || 'server',
|
|
295
|
+
{ projectConfigPath, configPath, buildContext }
|
|
276
296
|
);
|
|
277
|
-
let swcConfigRule = createSwcConfig({
|
|
278
|
-
isTypescriptEnabled,
|
|
279
|
-
isReactEnabled,
|
|
280
|
-
isJsxEnabled,
|
|
281
|
-
isTsxEnabled,
|
|
282
|
-
externalHelpers: enableSwcExternalHelpers,
|
|
283
|
-
isDevEnvironment: isRun && initialIsDev && !isTest && !isNative,
|
|
284
|
-
isClient,
|
|
285
|
-
isAngularEnabled,
|
|
286
|
-
});
|
|
287
|
-
Meteor.swcConfigOptions = swcConfigRule.options;
|
|
288
297
|
|
|
289
298
|
// Expose Meteor's helpers to expand Rspack configs
|
|
290
|
-
Meteor.compileWithMeteor =
|
|
299
|
+
Meteor.compileWithMeteor = deps => compileWithMeteor(deps);
|
|
291
300
|
Meteor.compileWithRspack = (deps, options = {}) =>
|
|
292
301
|
compileWithRspack(deps, {
|
|
293
302
|
options: mergeSplitOverlap(Meteor.swcConfigOptions, options),
|
|
294
303
|
});
|
|
295
|
-
Meteor.setCache =
|
|
296
|
-
setCache(
|
|
304
|
+
Meteor.setCache = enabled =>
|
|
305
|
+
setCache(
|
|
306
|
+
!!enabled,
|
|
307
|
+
enabled === 'memory' ? undefined : cacheStrategy
|
|
308
|
+
);
|
|
297
309
|
Meteor.splitVendorChunk = () => splitVendorChunk();
|
|
298
|
-
Meteor.extendSwcConfig = (customSwcConfig) =>
|
|
299
|
-
extendSwcConfig(customSwcConfig);
|
|
310
|
+
Meteor.extendSwcConfig = (customSwcConfig) => extendSwcConfig(customSwcConfig);
|
|
300
311
|
Meteor.extendConfig = (...configs) => mergeSplitOverlap(...configs);
|
|
301
|
-
Meteor.disablePlugins =
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
});
|
|
305
|
-
Meteor.enablePortableBuild = () => enablePortableBuild();
|
|
312
|
+
Meteor.disablePlugins = matchers => prepareMeteorRspackConfig({
|
|
313
|
+
disablePlugins: matchers,
|
|
314
|
+
});
|
|
306
315
|
|
|
307
316
|
// Add HtmlRspackPlugin function to Meteor
|
|
308
317
|
Meteor.HtmlRspackPlugin = (options = {}) => {
|
|
@@ -326,57 +335,6 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
326
335
|
});
|
|
327
336
|
};
|
|
328
337
|
|
|
329
|
-
// First pass: resolve user/override configs early so mode overrides (e.g. "production")
|
|
330
|
-
// are available before computing isProd/isDev and the rest of the build flags.
|
|
331
|
-
// Skipped for Angular since it manages its own mode via the second pass.
|
|
332
|
-
let { nextUserConfig, nextOverrideConfig } = isAngularEnabled
|
|
333
|
-
? {}
|
|
334
|
-
: await loadUserAndOverrideConfig(projectConfigPath, Meteor, argv);
|
|
335
|
-
|
|
336
|
-
// Determine the final mode with loaded configs
|
|
337
|
-
const currentMode = getModeFromConfig(nextUserConfig, nextOverrideConfig);
|
|
338
|
-
const isProd = currentMode
|
|
339
|
-
? currentMode === "production"
|
|
340
|
-
: !!Meteor.isProduction;
|
|
341
|
-
const isDev = currentMode
|
|
342
|
-
? currentMode === "development"
|
|
343
|
-
: !!Meteor.isDevelopment || !isProd;
|
|
344
|
-
const mode = isProd ? "production" : "development";
|
|
345
|
-
const isPortableBuild = !!(
|
|
346
|
-
nextUserConfig?.["meteor.enablePortableBuild"] ||
|
|
347
|
-
nextOverrideConfig?.["meteor.enablePortableBuild"]
|
|
348
|
-
);
|
|
349
|
-
const configPath = Meteor.configPath;
|
|
350
|
-
const testEntry = Meteor.testEntry;
|
|
351
|
-
|
|
352
|
-
// Determine entry points
|
|
353
|
-
const entryPath = Meteor.entryPath || "";
|
|
354
|
-
|
|
355
|
-
// Determine output points
|
|
356
|
-
const outputFilename = Meteor.outputFilename;
|
|
357
|
-
|
|
358
|
-
// Determine context for bundles and assets
|
|
359
|
-
const assetsContext = Meteor.assetsContext || "build-assets";
|
|
360
|
-
const chunksContext = Meteor.chunksContext || "build-chunks";
|
|
361
|
-
|
|
362
|
-
cacheStrategy = createCacheStrategy(
|
|
363
|
-
mode,
|
|
364
|
-
(Meteor.isClient && "client") || "server",
|
|
365
|
-
{ projectConfigPath, configPath }
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
// Determine run point
|
|
369
|
-
const runPath = Meteor.runPath || "";
|
|
370
|
-
|
|
371
|
-
// Determine banner
|
|
372
|
-
const bannerOutput = JSON.parse(
|
|
373
|
-
Meteor.bannerOutput || process.env.RSPACK_BANNER || '""'
|
|
374
|
-
);
|
|
375
|
-
|
|
376
|
-
// Determine output directories
|
|
377
|
-
const clientOutputDir = path.resolve(projectDir, "public");
|
|
378
|
-
const serverOutputDir = path.resolve(projectDir, "private");
|
|
379
|
-
|
|
380
338
|
// Get Meteor ignore entries
|
|
381
339
|
const meteorIgnoreEntries = getMeteorIgnoreEntries(projectDir);
|
|
382
340
|
|
|
@@ -392,17 +350,21 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
392
350
|
// Set default watch options
|
|
393
351
|
const watchOptions = {
|
|
394
352
|
ignored: [
|
|
395
|
-
...createIgnoreGlobConfig([
|
|
353
|
+
...createIgnoreGlobConfig([
|
|
354
|
+
...meteorIgnoreEntries,
|
|
355
|
+
...additionalEntries,
|
|
356
|
+
]),
|
|
396
357
|
],
|
|
397
358
|
};
|
|
398
359
|
|
|
399
360
|
if (Meteor.isDebug || Meteor.isVerbose) {
|
|
400
|
-
console.log(
|
|
401
|
-
console.log(
|
|
361
|
+
console.log('[i] Rspack mode:', mode);
|
|
362
|
+
console.log('[i] Meteor flags:', Meteor);
|
|
402
363
|
}
|
|
403
364
|
|
|
365
|
+
const enableSwcExternalHelpers = !isServer && swcExternalHelpers;
|
|
404
366
|
const isDevEnvironment = isRun && isDev && !isTest && !isNative;
|
|
405
|
-
swcConfigRule = createSwcConfig({
|
|
367
|
+
const swcConfigRule = createSwcConfig({
|
|
406
368
|
isTypescriptEnabled,
|
|
407
369
|
isReactEnabled,
|
|
408
370
|
isJsxEnabled,
|
|
@@ -412,6 +374,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
412
374
|
isClient,
|
|
413
375
|
isAngularEnabled,
|
|
414
376
|
});
|
|
377
|
+
// Expose swc config to use in custom configs
|
|
415
378
|
Meteor.swcConfigOptions = swcConfigRule.options;
|
|
416
379
|
|
|
417
380
|
const externals = [
|
|
@@ -420,34 +383,34 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
420
383
|
...(isServer ? [/^bcrypt$/] : []),
|
|
421
384
|
];
|
|
422
385
|
const alias = {
|
|
423
|
-
|
|
386
|
+
'/': path.resolve(process.cwd()),
|
|
424
387
|
};
|
|
425
388
|
const fallback = {
|
|
426
389
|
...(isClient && makeWebNodeBuiltinsAlias()),
|
|
427
390
|
};
|
|
428
391
|
const extensions = [
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
392
|
+
'.ts',
|
|
393
|
+
'.tsx',
|
|
394
|
+
'.mts',
|
|
395
|
+
'.cts',
|
|
396
|
+
'.js',
|
|
397
|
+
'.jsx',
|
|
398
|
+
'.mjs',
|
|
399
|
+
'.cjs',
|
|
400
|
+
'.json',
|
|
401
|
+
'.wasm',
|
|
439
402
|
];
|
|
440
403
|
const extraRules = [];
|
|
441
404
|
|
|
442
405
|
const reactRefreshModule = isReactEnabled
|
|
443
|
-
? safeRequire(
|
|
406
|
+
? safeRequire('@rspack/plugin-react-refresh')
|
|
444
407
|
: null;
|
|
445
408
|
|
|
446
409
|
const requireExternalsPlugin = new RequireExternalsPlugin({
|
|
447
410
|
filePath: path.join(buildContext, runPath),
|
|
448
411
|
...(Meteor.isBlazeEnabled && {
|
|
449
412
|
externals: /\.html$/,
|
|
450
|
-
isEagerImport:
|
|
413
|
+
isEagerImport: module => module.endsWith('.html'),
|
|
451
414
|
...(isProd && {
|
|
452
415
|
lastImports: [`./${outputFilename}`],
|
|
453
416
|
}),
|
|
@@ -457,26 +420,25 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
457
420
|
|
|
458
421
|
// Handle assets
|
|
459
422
|
const assetExternalsPlugin = new AssetExternalsPlugin();
|
|
460
|
-
const assetModuleFilename =
|
|
423
|
+
const assetModuleFilename = _fileInfo => {
|
|
461
424
|
const filename = _fileInfo.filename;
|
|
462
|
-
const isPublic = filename.startsWith(
|
|
425
|
+
const isPublic = filename.startsWith('/') || filename.startsWith('public');
|
|
463
426
|
if (isPublic) return `[name][ext][query]`;
|
|
464
427
|
return `${assetsContext}/[hash][ext][query]`;
|
|
465
428
|
};
|
|
466
429
|
|
|
467
430
|
const rsdoctorModule = isBundleVisualizerEnabled
|
|
468
|
-
? safeRequire(
|
|
431
|
+
? safeRequire('@rsdoctor/rspack-plugin')
|
|
469
432
|
: null;
|
|
470
|
-
const doctorPluginConfig =
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
: [];
|
|
433
|
+
const doctorPluginConfig = isRun && isBundleVisualizerEnabled && rsdoctorModule?.RsdoctorRspackPlugin
|
|
434
|
+
? [
|
|
435
|
+
new rsdoctorModule.RsdoctorRspackPlugin({
|
|
436
|
+
port: isClient
|
|
437
|
+
? (parseInt(Meteor.rsdoctorClientPort || '8888', 10))
|
|
438
|
+
: (parseInt(Meteor.rsdoctorServerPort || '8889', 10)),
|
|
439
|
+
}),
|
|
440
|
+
]
|
|
441
|
+
: [];
|
|
480
442
|
const bannerPluginConfig = !isBuild
|
|
481
443
|
? [
|
|
482
444
|
new BannerPlugin({
|
|
@@ -487,6 +449,10 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
487
449
|
: [];
|
|
488
450
|
// Not supported in Meteor yet (Rspack 1.7+ is enabled by default)
|
|
489
451
|
const lazyCompilationConfig = { lazyCompilation: false };
|
|
452
|
+
const shouldLogVerbose = isProfile || isVerbose;
|
|
453
|
+
const loggingConfig = shouldLogVerbose
|
|
454
|
+
? {}
|
|
455
|
+
: { stats: "errors-warnings", infrastructureLogging: { level: "warn" } };
|
|
490
456
|
|
|
491
457
|
const clientEntry =
|
|
492
458
|
isClient && isTest && isTestEager && isTestFullApp
|
|
@@ -494,7 +460,8 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
494
460
|
isAppTest: true,
|
|
495
461
|
projectDir,
|
|
496
462
|
buildContext,
|
|
497
|
-
ignoreEntries: [
|
|
463
|
+
ignoreEntries: ["**/server/**"],
|
|
464
|
+
meteorIgnoreEntries,
|
|
498
465
|
prefix: "client",
|
|
499
466
|
extraEntry: path.resolve(process.cwd(), Meteor.mainClientEntry),
|
|
500
467
|
globalImportPath: path.resolve(projectDir, buildContext, entryPath),
|
|
@@ -505,18 +472,19 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
505
472
|
isClient: true,
|
|
506
473
|
projectDir,
|
|
507
474
|
buildContext,
|
|
508
|
-
ignoreEntries: [
|
|
475
|
+
ignoreEntries: ["**/server/**"],
|
|
476
|
+
meteorIgnoreEntries,
|
|
509
477
|
prefix: "client",
|
|
510
478
|
globalImportPath: path.resolve(projectDir, buildContext, entryPath),
|
|
511
479
|
})
|
|
512
480
|
: isClient && isTest && testEntry
|
|
513
481
|
? path.resolve(process.cwd(), testEntry)
|
|
514
482
|
: path.resolve(process.cwd(), buildContext, entryPath);
|
|
515
|
-
const clientNameConfig = `[${(isTest &&
|
|
483
|
+
const clientNameConfig = `[${(isTest && 'test-') || ''}client-rspack]`;
|
|
516
484
|
// Base client config
|
|
517
485
|
let clientConfig = {
|
|
518
486
|
name: clientNameConfig,
|
|
519
|
-
target:
|
|
487
|
+
target: 'web',
|
|
520
488
|
mode,
|
|
521
489
|
entry: clientEntry,
|
|
522
490
|
output: {
|
|
@@ -525,7 +493,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
525
493
|
const chunkName = _module.chunk?.name;
|
|
526
494
|
const isMainChunk = !chunkName || chunkName === "main";
|
|
527
495
|
const chunkSuffix = `${chunksContext}/[id]${
|
|
528
|
-
isProd ?
|
|
496
|
+
isProd ? '.[chunkhash]' : ''
|
|
529
497
|
}.js`;
|
|
530
498
|
if (isDevEnvironment) {
|
|
531
499
|
if (isMainChunk) return outputFilename;
|
|
@@ -534,21 +502,21 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
534
502
|
if (isMainChunk) return `../${buildContext}/${outputPath}`;
|
|
535
503
|
return chunkSuffix;
|
|
536
504
|
},
|
|
537
|
-
libraryTarget:
|
|
538
|
-
publicPath:
|
|
539
|
-
chunkFilename: `${chunksContext}/[id]${isProd ?
|
|
505
|
+
libraryTarget: 'commonjs2',
|
|
506
|
+
publicPath: '/',
|
|
507
|
+
chunkFilename: `${chunksContext}/[id]${isProd ? '.[chunkhash]' : ''}.js`,
|
|
540
508
|
assetModuleFilename,
|
|
541
509
|
cssFilename: `${chunksContext}/[name]${
|
|
542
|
-
isProd ?
|
|
510
|
+
isProd ? '.[contenthash]' : ''
|
|
543
511
|
}.css`,
|
|
544
512
|
cssChunkFilename: `${chunksContext}/[id]${
|
|
545
|
-
isProd ?
|
|
513
|
+
isProd ? '.[contenthash]' : ''
|
|
546
514
|
}.css`,
|
|
547
515
|
...(isProd && { clean: { keep: keepOutsideBuild() } }),
|
|
548
516
|
},
|
|
549
517
|
optimization: {
|
|
550
518
|
usedExports: true,
|
|
551
|
-
splitChunks: { chunks:
|
|
519
|
+
splitChunks: { chunks: 'async' },
|
|
552
520
|
},
|
|
553
521
|
module: {
|
|
554
522
|
rules: [
|
|
@@ -557,7 +525,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
557
525
|
? [
|
|
558
526
|
{
|
|
559
527
|
test: /\.html$/i,
|
|
560
|
-
loader:
|
|
528
|
+
loader: 'ignore-loader',
|
|
561
529
|
},
|
|
562
530
|
]
|
|
563
531
|
: []),
|
|
@@ -575,43 +543,46 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
575
543
|
assetExternalsPlugin,
|
|
576
544
|
].filter(Boolean),
|
|
577
545
|
new DefinePlugin({
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
"Meteor.isProduction": JSON.stringify(isProd),
|
|
585
|
-
}),
|
|
546
|
+
'Meteor.isClient': JSON.stringify(true),
|
|
547
|
+
'Meteor.isServer': JSON.stringify(false),
|
|
548
|
+
'Meteor.isTest': JSON.stringify(isTestLike && !isTestFullApp),
|
|
549
|
+
'Meteor.isAppTest': JSON.stringify(isTestLike && isTestFullApp),
|
|
550
|
+
'Meteor.isDevelopment': JSON.stringify(isDev),
|
|
551
|
+
'Meteor.isProduction': JSON.stringify(isProd),
|
|
586
552
|
}),
|
|
587
553
|
...bannerPluginConfig,
|
|
588
554
|
Meteor.HtmlRspackPlugin(),
|
|
589
555
|
...doctorPluginConfig,
|
|
590
556
|
new NormalModuleReplacementPlugin(/^node:(.*)$/, (res) => {
|
|
591
|
-
res.request = res.request.replace(/^node:/,
|
|
557
|
+
res.request = res.request.replace(/^node:/, '');
|
|
592
558
|
}),
|
|
593
559
|
],
|
|
594
560
|
watchOptions,
|
|
595
|
-
devtool:
|
|
596
|
-
isDevEnvironment || isNative || isTest
|
|
597
|
-
? "source-map"
|
|
598
|
-
: "hidden-source-map",
|
|
561
|
+
devtool: isDevEnvironment || isNative || isTest ? 'source-map' : 'hidden-source-map',
|
|
599
562
|
...(isDevEnvironment && {
|
|
600
563
|
devServer: {
|
|
601
564
|
...createRemoteDevServerConfig(),
|
|
602
|
-
static: { directory: clientOutputDir, publicPath:
|
|
565
|
+
static: { directory: clientOutputDir, publicPath: '/__rspack__/' },
|
|
603
566
|
hot: true,
|
|
604
567
|
liveReload: true,
|
|
605
568
|
...(Meteor.isBlazeEnabled && { hot: false }),
|
|
606
|
-
port: devServerPort,
|
|
569
|
+
port: Meteor.devServerPort || 8080,
|
|
607
570
|
devMiddleware: {
|
|
608
|
-
writeToDisk:
|
|
609
|
-
/\.(html)$/.test(filePath) && !filePath.includes(
|
|
571
|
+
writeToDisk: filePath =>
|
|
572
|
+
/\.(html)$/.test(filePath) && !filePath.includes('.hot-update.'),
|
|
573
|
+
},
|
|
574
|
+
onListening(devServer) {
|
|
575
|
+
if (!devServer) return;
|
|
576
|
+
const { host, port } = devServer.options;
|
|
577
|
+
const protocol = devServer.options.server?.type === "https" ? "https" : "http";
|
|
578
|
+
const devServerUrl = `${protocol}://${host || "localhost"}:${port}`;
|
|
579
|
+
outputMeteorRspack({ devServerUrl });
|
|
610
580
|
},
|
|
611
581
|
},
|
|
612
582
|
}),
|
|
613
583
|
...merge(cacheStrategy, { experiments: { css: true } }),
|
|
614
584
|
...lazyCompilationConfig,
|
|
585
|
+
...loggingConfig,
|
|
615
586
|
};
|
|
616
587
|
|
|
617
588
|
const serverEntry =
|
|
@@ -620,7 +591,8 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
620
591
|
isAppTest: true,
|
|
621
592
|
projectDir,
|
|
622
593
|
buildContext,
|
|
623
|
-
ignoreEntries: [
|
|
594
|
+
ignoreEntries: ["**/client/**"],
|
|
595
|
+
meteorIgnoreEntries,
|
|
624
596
|
prefix: "server",
|
|
625
597
|
globalImportPath: path.resolve(projectDir, buildContext, entryPath),
|
|
626
598
|
})
|
|
@@ -629,25 +601,26 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
629
601
|
isAppTest: false,
|
|
630
602
|
projectDir,
|
|
631
603
|
buildContext,
|
|
632
|
-
ignoreEntries: [
|
|
604
|
+
ignoreEntries: ["**/client/**"],
|
|
605
|
+
meteorIgnoreEntries,
|
|
633
606
|
prefix: "server",
|
|
634
607
|
globalImportPath: path.resolve(projectDir, buildContext, entryPath),
|
|
635
608
|
})
|
|
636
609
|
: isServer && isTest && testEntry
|
|
637
610
|
? path.resolve(process.cwd(), testEntry)
|
|
638
611
|
: path.resolve(projectDir, buildContext, entryPath);
|
|
639
|
-
const serverNameConfig = `[${(isTest &&
|
|
612
|
+
const serverNameConfig = `[${(isTest && 'test-') || ''}server-rspack]`;
|
|
640
613
|
// Base server config
|
|
641
614
|
let serverConfig = {
|
|
642
615
|
name: serverNameConfig,
|
|
643
|
-
target:
|
|
616
|
+
target: 'node',
|
|
644
617
|
mode,
|
|
645
618
|
entry: serverEntry,
|
|
646
619
|
output: {
|
|
647
620
|
path: serverOutputDir,
|
|
648
621
|
filename: () => `../${buildContext}/${outputPath}`,
|
|
649
|
-
libraryTarget:
|
|
650
|
-
chunkFilename: `${chunksContext}/[id]${isProd ?
|
|
622
|
+
libraryTarget: 'commonjs2',
|
|
623
|
+
chunkFilename: `${chunksContext}/[id]${isProd ? '.[chunkhash]' : ''}.js`,
|
|
651
624
|
assetModuleFilename,
|
|
652
625
|
...(isProd && { clean: { keep: keepOutsideBuild() } }),
|
|
653
626
|
},
|
|
@@ -661,15 +634,15 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
661
634
|
parser: {
|
|
662
635
|
javascript: {
|
|
663
636
|
// Dynamic imports on the server are treated as bundled in the same chunk
|
|
664
|
-
dynamicImportMode:
|
|
637
|
+
dynamicImportMode: 'eager',
|
|
665
638
|
},
|
|
666
639
|
},
|
|
667
640
|
},
|
|
668
641
|
resolve: {
|
|
669
642
|
extensions,
|
|
670
643
|
alias,
|
|
671
|
-
modules: [
|
|
672
|
-
conditionNames: [
|
|
644
|
+
modules: ['node_modules', path.resolve(projectDir)],
|
|
645
|
+
conditionNames: ['import', 'require', 'node', 'default'],
|
|
673
646
|
},
|
|
674
647
|
externals,
|
|
675
648
|
externalsPresets: { node: true },
|
|
@@ -677,22 +650,18 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
677
650
|
new DefinePlugin(
|
|
678
651
|
isTest && (isTestModule || isTestEager)
|
|
679
652
|
? {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
"Meteor.isDevelopment": JSON.stringify(isDev),
|
|
684
|
-
}),
|
|
653
|
+
'Meteor.isTest': JSON.stringify(isTest && !isTestFullApp),
|
|
654
|
+
'Meteor.isAppTest': JSON.stringify(isTest && isTestFullApp),
|
|
655
|
+
'Meteor.isDevelopment': JSON.stringify(isDev),
|
|
685
656
|
}
|
|
686
657
|
: {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
}),
|
|
695
|
-
}
|
|
658
|
+
'Meteor.isClient': JSON.stringify(false),
|
|
659
|
+
'Meteor.isServer': JSON.stringify(true),
|
|
660
|
+
'Meteor.isTest': JSON.stringify(isTestLike && !isTestFullApp),
|
|
661
|
+
'Meteor.isAppTest': JSON.stringify(isTestLike && isTestFullApp),
|
|
662
|
+
'Meteor.isDevelopment': JSON.stringify(isDev),
|
|
663
|
+
'Meteor.isProduction': JSON.stringify(isProd),
|
|
664
|
+
},
|
|
696
665
|
),
|
|
697
666
|
...bannerPluginConfig,
|
|
698
667
|
requireExternalsPlugin,
|
|
@@ -700,20 +669,111 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
700
669
|
...doctorPluginConfig,
|
|
701
670
|
],
|
|
702
671
|
watchOptions,
|
|
703
|
-
devtool:
|
|
704
|
-
isDevEnvironment || isNative || isTest
|
|
705
|
-
? "source-map"
|
|
706
|
-
: "hidden-source-map",
|
|
672
|
+
devtool: isDevEnvironment || isNative || isTest ? 'source-map' : 'hidden-source-map',
|
|
707
673
|
...((isDevEnvironment || (isTest && !isTestEager) || isNative) &&
|
|
708
674
|
cacheStrategy),
|
|
709
675
|
...lazyCompilationConfig,
|
|
676
|
+
...loggingConfig,
|
|
710
677
|
};
|
|
711
678
|
|
|
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
|
+
|
|
712
772
|
// Establish Angular overrides to ensure proper integration
|
|
713
773
|
const angularExpandConfig = isAngularEnabled
|
|
714
774
|
? {
|
|
715
775
|
mode: isProd ? "production" : "development",
|
|
716
|
-
devServer: { port: devServerPort },
|
|
776
|
+
devServer: { port: Meteor.devServerPort },
|
|
717
777
|
stats: { preset: "normal" },
|
|
718
778
|
infrastructureLogging: { level: "info" },
|
|
719
779
|
...(isProd && isClient && { output: { module: false } }),
|
|
@@ -740,26 +800,35 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
740
800
|
}
|
|
741
801
|
: {};
|
|
742
802
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
({ nextUserConfig, nextOverrideConfig } = await loadUserAndOverrideConfig(
|
|
748
|
-
projectConfigPath,
|
|
749
|
-
Meteor,
|
|
750
|
-
argv
|
|
751
|
-
));
|
|
752
|
-
}
|
|
753
|
-
let config = isClient ? clientConfig : serverConfig;
|
|
754
|
-
if (nextUserConfig) {
|
|
755
|
-
config = mergeSplitOverlap(config, nextUserConfig);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
config = mergeSplitOverlap(config, angularExpandConfig);
|
|
803
|
+
let config = mergeSplitOverlap(
|
|
804
|
+
isClient ? clientConfig : serverConfig,
|
|
805
|
+
angularExpandConfig
|
|
806
|
+
);
|
|
759
807
|
config = mergeSplitOverlap(config, testClientExpandConfig);
|
|
760
808
|
|
|
761
|
-
|
|
762
|
-
|
|
809
|
+
// Check for override config file (extra file to override everything)
|
|
810
|
+
if (projectConfigPath) {
|
|
811
|
+
const configDir = path.dirname(projectConfigPath);
|
|
812
|
+
const configFileName = path.basename(projectConfigPath);
|
|
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
|
+
}
|
|
831
|
+
}
|
|
763
832
|
}
|
|
764
833
|
|
|
765
834
|
const shouldDisablePlugins = config?.disablePlugins != null;
|
|
@@ -768,23 +837,33 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
768
837
|
delete config.disablePlugins;
|
|
769
838
|
}
|
|
770
839
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
console.log("Config:", inspect(config, { depth: null, colors: true }));
|
|
775
|
-
// }
|
|
840
|
+
if (Meteor.isDebug || Meteor.isVerbose) {
|
|
841
|
+
console.log('Config:', inspect(config, { depth: null, colors: true }));
|
|
842
|
+
}
|
|
776
843
|
|
|
777
844
|
// Check if lazyCompilation is enabled and warn the user
|
|
778
|
-
if (
|
|
779
|
-
config.lazyCompilation === true ||
|
|
780
|
-
typeof config.lazyCompilation === "object"
|
|
781
|
-
) {
|
|
845
|
+
if (config.lazyCompilation === true || typeof config.lazyCompilation === 'object') {
|
|
782
846
|
console.warn(
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
847
|
+
'\n⚠️ Warning: lazyCompilation may not work correctly in the current Meteor-Rspack integration.\n' +
|
|
848
|
+
' This feature will be evaluated for support in future Meteor versions.\n' +
|
|
849
|
+
' If you encounter any issues, please disable it in your rspack config.\n',
|
|
786
850
|
);
|
|
787
851
|
}
|
|
788
852
|
|
|
853
|
+
// Add MeteorRspackOutputPlugin as the last plugin to output compilation info
|
|
854
|
+
const meteorRspackOutputPlugin = new MeteorRspackOutputPlugin({
|
|
855
|
+
getData: (stats, { isRebuild, compilationCount }) => ({
|
|
856
|
+
name: config.name,
|
|
857
|
+
mode: config.mode,
|
|
858
|
+
hasErrors: stats.hasErrors(),
|
|
859
|
+
hasWarnings: stats.hasWarnings(),
|
|
860
|
+
timestamp: Date.now(),
|
|
861
|
+
statsOverrided,
|
|
862
|
+
compilationCount,
|
|
863
|
+
isRebuild,
|
|
864
|
+
}),
|
|
865
|
+
});
|
|
866
|
+
config.plugins = [meteorRspackOutputPlugin, ...(config.plugins || [])];
|
|
867
|
+
|
|
789
868
|
return [config];
|
|
790
869
|
}
|
|
@@ -1,121 +0,0 @@
|
|
|
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
|
-
};
|