@meteorjs/rspack 0.0.59 → 0.0.61
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 +26 -1
- package/lib/meteorRspackConfigFactory.js +28 -25
- package/lib/meteorRspackHelpers.js +52 -1
- package/package.json +1 -1
- package/rspack.config.js +69 -7
package/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
defineConfig as _rspackDefineConfig,
|
|
6
6
|
Configuration as _RspackConfig,
|
|
7
7
|
} from '@rspack/cli';
|
|
8
|
-
import { HtmlRspackPluginOptions } from '@rspack/core';
|
|
8
|
+
import { HtmlRspackPluginOptions, RuleSetConditions } from '@rspack/core';
|
|
9
9
|
|
|
10
10
|
export interface MeteorRspackConfig extends _RspackConfig {
|
|
11
11
|
meteor?: {
|
|
@@ -31,6 +31,31 @@ type MeteorEnv = Record<string, any> & {
|
|
|
31
31
|
* @returns An instance of HtmlRspackPlugin
|
|
32
32
|
*/
|
|
33
33
|
HtmlRspackPlugin: (options?: HtmlRspackPluginOptions) => HtmlRspackPlugin;
|
|
34
|
+
/**
|
|
35
|
+
* Wrap externals for Meteor runtime.
|
|
36
|
+
* @param deps - Package names or module IDs
|
|
37
|
+
* @returns A config object with externals configuration
|
|
38
|
+
*/
|
|
39
|
+
compileWithMeteor: (deps: RuleSetConditions) => Record<string, object>;
|
|
40
|
+
/**
|
|
41
|
+
* Add SWC transpilation rules limited to specific deps (monorepo-friendly).
|
|
42
|
+
* @param deps - Package names to include in SWC loader
|
|
43
|
+
* @param options - Optional configuration options
|
|
44
|
+
* @returns A config object with module rules configuration
|
|
45
|
+
*/
|
|
46
|
+
compileWithRspack: (deps: RuleSetConditions) => Record<string, object>;
|
|
47
|
+
/**
|
|
48
|
+
* Enable or disable Rspack cache config.
|
|
49
|
+
* @param enabled - Whether to enable caching
|
|
50
|
+
* @param cacheConfig - Optional cache configuration
|
|
51
|
+
* @returns A config object with cache configuration
|
|
52
|
+
*/
|
|
53
|
+
setCache: (enabled: boolean | 'memory') => Record<string, object>;
|
|
54
|
+
/**
|
|
55
|
+
* Enable Rspack split vendor chunk.
|
|
56
|
+
* @returns A config object with optimization configuration
|
|
57
|
+
*/
|
|
58
|
+
splitVendorChunk: () => Record<string, object>;
|
|
34
59
|
}
|
|
35
60
|
|
|
36
61
|
export type ConfigFactory = (
|
|
@@ -42,11 +42,17 @@ function prepareMeteorRspackConfig(customConfig, opts = {}) {
|
|
|
42
42
|
* Merge all `{prefix}<n>` fragments into `config` using `mergeSplitOverlap`,
|
|
43
43
|
* then remove those temporary keys. Mutates `config`.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
45
|
+
* Position-aware merge:
|
|
46
|
+
* Walk the config in insertion order and fold:
|
|
47
|
+
* - for a fragment key: out = mergeSplitOverlap(out, fragment)
|
|
48
|
+
* - for a normal key: out = mergeSplitOverlap(out, { [key]: value })
|
|
49
|
+
*
|
|
50
|
+
* Result: fragments behave like spreads at their exact position;
|
|
51
|
+
* later inline keys override earlier ones (including fragments).
|
|
46
52
|
*
|
|
47
53
|
* @param {object} config
|
|
48
54
|
* @param {{ prefix?: string }} [opts]
|
|
49
|
-
* @returns {object}
|
|
55
|
+
* @returns {object} same (mutated) config
|
|
50
56
|
*/
|
|
51
57
|
function mergeMeteorRspackFragments(config, opts = {}) {
|
|
52
58
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
@@ -54,39 +60,36 @@ function mergeMeteorRspackFragments(config, opts = {}) {
|
|
|
54
60
|
}
|
|
55
61
|
const prefix = opts.prefix || DEFAULT_PREFIX;
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
.map((k) => [k, parseInt(k.slice(prefix.length), 10)])
|
|
61
|
-
.sort((a, b) => a[1] - b[1])
|
|
62
|
-
.map(([k]) => k);
|
|
63
|
+
let out = {};
|
|
64
|
+
for (const key of Object.keys(config)) {
|
|
65
|
+
const val = config[key];
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
const isFragment =
|
|
68
|
+
typeof key === "string" &&
|
|
69
|
+
key.startsWith(prefix) &&
|
|
70
|
+
/^\d+$/.test(key.slice(prefix.length));
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
if (isFragment) {
|
|
73
|
+
if (!val || typeof val !== "object" || Array.isArray(val)) {
|
|
74
|
+
throw new Error(`Fragment "${key}" must be a plain object`);
|
|
75
|
+
}
|
|
76
|
+
out = mergeSplitOverlap(out, val);
|
|
77
|
+
} else {
|
|
78
|
+
out = mergeSplitOverlap(out, { [key]: val });
|
|
71
79
|
}
|
|
72
|
-
const merged = mergeSplitOverlap(config, fragment);
|
|
73
|
-
|
|
74
|
-
// Keep object identity: replace contents of `config` with `merged`
|
|
75
|
-
replaceObject(config, merged);
|
|
76
80
|
}
|
|
77
81
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
// keep object identity; fragments disappear because `out` doesn't include them
|
|
83
|
+
replaceObject(config, out);
|
|
81
84
|
return config;
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
function replaceObject(target, source) {
|
|
85
|
-
for (const
|
|
86
|
-
if (!(
|
|
88
|
+
for (const k of Object.keys(target)) {
|
|
89
|
+
if (!(k in source)) delete target[k];
|
|
87
90
|
}
|
|
88
|
-
for (const
|
|
89
|
-
target[
|
|
91
|
+
for (const k of Object.keys(source)) {
|
|
92
|
+
target[k] = source[k];
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
|
|
@@ -54,6 +54,30 @@ function compileWithRspack(deps, { options = {} } = {}) {
|
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Enable or disable Rspack cache config
|
|
59
|
+
* Usage: setCache(false)
|
|
60
|
+
*
|
|
61
|
+
* @param {boolean} enabled
|
|
62
|
+
* @param {Record<string, object>} cacheConfig
|
|
63
|
+
* @returns {Record<string, object>} `{ meteorRspackConfigX: { cache: {} } }`
|
|
64
|
+
*/
|
|
65
|
+
function setCache(
|
|
66
|
+
enabled,
|
|
67
|
+
cacheConfig = { cache: true, experiments: { cache: true } }
|
|
68
|
+
) {
|
|
69
|
+
return prepareMeteorRspackConfig(
|
|
70
|
+
enabled
|
|
71
|
+
? cacheConfig
|
|
72
|
+
: {
|
|
73
|
+
cache: false, // disable cache
|
|
74
|
+
experiments: {
|
|
75
|
+
cache: false, // disable persistent cache (experimental flag)
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
57
81
|
/**
|
|
58
82
|
* Build an alias map that disables ALL Node core modules in a web build.
|
|
59
83
|
* - Includes both 'fs' and 'node:fs' keys
|
|
@@ -65,7 +89,7 @@ function makeWebNodeBuiltinsAlias(extras = []) {
|
|
|
65
89
|
|
|
66
90
|
const names = new Set();
|
|
67
91
|
for (const m of core) {
|
|
68
|
-
names.add(m);
|
|
92
|
+
names.add(m); // e.g. 'fs'
|
|
69
93
|
names.add(`node:${m}`); // e.g. 'node:fs'
|
|
70
94
|
}
|
|
71
95
|
for (const x of extras) names.add(x);
|
|
@@ -74,8 +98,35 @@ function makeWebNodeBuiltinsAlias(extras = []) {
|
|
|
74
98
|
return Object.fromEntries([...names].map((m) => [m, false]));
|
|
75
99
|
}
|
|
76
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Enable Rspack split vendor chunk config
|
|
103
|
+
* Usage: splitVendorChunk()
|
|
104
|
+
*
|
|
105
|
+
* @returns {Record<string, object>} `{ meteorRspackConfigX: { optimization: { ... } } }`
|
|
106
|
+
*/
|
|
107
|
+
function splitVendorChunk() {
|
|
108
|
+
return prepareMeteorRspackConfig({
|
|
109
|
+
optimization: {
|
|
110
|
+
splitChunks: {
|
|
111
|
+
chunks: "all", // split both sync and async imports
|
|
112
|
+
cacheGroups: {
|
|
113
|
+
vendor: {
|
|
114
|
+
test: /[\\/]node_modules[\\/]/,
|
|
115
|
+
name: "vendor",
|
|
116
|
+
enforce: true,
|
|
117
|
+
priority: 10,
|
|
118
|
+
chunks: "all",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
77
126
|
module.exports = {
|
|
78
127
|
compileWithMeteor,
|
|
79
128
|
compileWithRspack,
|
|
129
|
+
setCache,
|
|
130
|
+
splitVendorChunk,
|
|
80
131
|
makeWebNodeBuiltinsAlias,
|
|
81
132
|
};
|
package/package.json
CHANGED
package/rspack.config.js
CHANGED
|
@@ -14,6 +14,8 @@ const { mergeMeteorRspackFragments } = require("./lib/meteorRspackConfigFactory.
|
|
|
14
14
|
const {
|
|
15
15
|
compileWithMeteor,
|
|
16
16
|
compileWithRspack,
|
|
17
|
+
setCache,
|
|
18
|
+
splitVendorChunk,
|
|
17
19
|
makeWebNodeBuiltinsAlias,
|
|
18
20
|
} = require('./lib/meteorRspackHelpers.js');
|
|
19
21
|
|
|
@@ -137,6 +139,43 @@ function createSwcConfig({
|
|
|
137
139
|
};
|
|
138
140
|
}
|
|
139
141
|
|
|
142
|
+
function createRemoteDevServerConfig() {
|
|
143
|
+
const rootUrl = process.env.ROOT_URL;
|
|
144
|
+
let hostname;
|
|
145
|
+
let protocol;
|
|
146
|
+
let port;
|
|
147
|
+
|
|
148
|
+
if (rootUrl) {
|
|
149
|
+
try {
|
|
150
|
+
const url = new URL(rootUrl);
|
|
151
|
+
// Detect if it's remote (not localhost or 127.x)
|
|
152
|
+
const isLocal =
|
|
153
|
+
url.hostname.includes('localhost') ||
|
|
154
|
+
url.hostname.startsWith('127.') ||
|
|
155
|
+
url.hostname.endsWith('.local');
|
|
156
|
+
if (!isLocal) {
|
|
157
|
+
hostname = url.hostname;
|
|
158
|
+
protocol = url.protocol === 'https:' ? 'wss' : 'ws';
|
|
159
|
+
port = url.port ? Number(url.port) : (url.protocol === 'https:' ? 443 : 80);
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
client: {
|
|
163
|
+
webSocketURL: {
|
|
164
|
+
hostname,
|
|
165
|
+
port,
|
|
166
|
+
protocol,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
} catch (err) {
|
|
172
|
+
console.warn(`Invalid ROOT_URL "${rootUrl}", falling back to localhost`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// If local doesn't provide any extra config
|
|
177
|
+
return {};
|
|
178
|
+
}
|
|
140
179
|
|
|
141
180
|
// Keep files outside of build folders
|
|
142
181
|
function keepOutsideBuild() {
|
|
@@ -218,12 +257,24 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
218
257
|
const buildOutputDir = path.resolve(projectDir, buildContext, outputDir);
|
|
219
258
|
Meteor.buildOutputDir = buildOutputDir;
|
|
220
259
|
|
|
260
|
+
const cacheStrategy = createCacheStrategy(
|
|
261
|
+
mode,
|
|
262
|
+
(Meteor.isClient && 'client') || 'server',
|
|
263
|
+
{ projectConfigPath, configPath }
|
|
264
|
+
);
|
|
265
|
+
|
|
221
266
|
// Expose Meteor's helpers to expand Rspack configs
|
|
222
267
|
Meteor.compileWithMeteor = deps => compileWithMeteor(deps);
|
|
223
268
|
Meteor.compileWithRspack = deps =>
|
|
224
269
|
compileWithRspack(deps, {
|
|
225
270
|
options: Meteor.swcConfigOptions,
|
|
226
271
|
});
|
|
272
|
+
Meteor.setCache = enabled =>
|
|
273
|
+
setCache(
|
|
274
|
+
!!enabled,
|
|
275
|
+
enabled === 'memory' ? undefined : cacheStrategy
|
|
276
|
+
);
|
|
277
|
+
Meteor.splitVendorChunk = () => splitVendorChunk();
|
|
227
278
|
|
|
228
279
|
// Add HtmlRspackPlugin function to Meteor
|
|
229
280
|
Meteor.HtmlRspackPlugin = (options = {}) => {
|
|
@@ -432,6 +483,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
432
483
|
devtool: isDevEnvironment || isNative || isTest ? 'source-map' : 'hidden-source-map',
|
|
433
484
|
...(isDevEnvironment && {
|
|
434
485
|
devServer: {
|
|
486
|
+
...createRemoteDevServerConfig(),
|
|
435
487
|
static: { directory: clientOutputDir, publicPath: '/__rspack__/' },
|
|
436
488
|
hot: true,
|
|
437
489
|
liveReload: true,
|
|
@@ -443,7 +495,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
443
495
|
},
|
|
444
496
|
},
|
|
445
497
|
}),
|
|
446
|
-
...merge(
|
|
498
|
+
...merge(cacheStrategy, { experiments: { css: true } })
|
|
447
499
|
};
|
|
448
500
|
|
|
449
501
|
|
|
@@ -526,7 +578,7 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
526
578
|
watchOptions,
|
|
527
579
|
devtool: isDevEnvironment || isNative || isTest ? 'source-map' : 'hidden-source-map',
|
|
528
580
|
...((isDevEnvironment || (isTest && !isTestEager) || isNative) &&
|
|
529
|
-
|
|
581
|
+
cacheStrategy),
|
|
530
582
|
};
|
|
531
583
|
|
|
532
584
|
// Load and apply project-level overrides for the selected build
|
|
@@ -561,10 +613,15 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
561
613
|
throw error;
|
|
562
614
|
}
|
|
563
615
|
|
|
564
|
-
const
|
|
616
|
+
const rawUserConfig =
|
|
565
617
|
typeof projectConfig === 'function'
|
|
566
618
|
? projectConfig(Meteor, argv)
|
|
567
619
|
: projectConfig;
|
|
620
|
+
const resolvedUserConfig = await Promise.resolve(rawUserConfig);
|
|
621
|
+
const userConfig =
|
|
622
|
+
resolvedUserConfig && '0' in resolvedUserConfig
|
|
623
|
+
? resolvedUserConfig[0]
|
|
624
|
+
: resolvedUserConfig;
|
|
568
625
|
|
|
569
626
|
const omitPaths = [
|
|
570
627
|
"name",
|
|
@@ -583,22 +640,27 @@ module.exports = async function (inMeteor = {}, argv = {}) {
|
|
|
583
640
|
);
|
|
584
641
|
};
|
|
585
642
|
|
|
643
|
+
let nextUserConfig = cleanOmittedPaths(userConfig, {
|
|
644
|
+
omitPaths,
|
|
645
|
+
warningFn,
|
|
646
|
+
});
|
|
647
|
+
nextUserConfig = mergeMeteorRspackFragments(nextUserConfig);
|
|
648
|
+
|
|
586
649
|
if (Meteor.isClient) {
|
|
587
650
|
clientConfig = mergeSplitOverlap(
|
|
588
651
|
clientConfig,
|
|
589
|
-
|
|
652
|
+
nextUserConfig
|
|
590
653
|
);
|
|
591
654
|
}
|
|
592
655
|
if (Meteor.isServer) {
|
|
593
656
|
serverConfig = mergeSplitOverlap(
|
|
594
657
|
serverConfig,
|
|
595
|
-
|
|
658
|
+
nextUserConfig
|
|
596
659
|
);
|
|
597
660
|
}
|
|
598
661
|
}
|
|
599
662
|
|
|
600
|
-
const
|
|
601
|
-
const config = mergeMeteorRspackFragments(sideConfig);
|
|
663
|
+
const config = isClient ? clientConfig : serverConfig;
|
|
602
664
|
|
|
603
665
|
if (Meteor.isDebug || Meteor.isVerbose) {
|
|
604
666
|
console.log('Config:', inspect(config, { depth: null, colors: true }));
|