@lynx-js/external-bundle-rsbuild-plugin 0.3.0 → 0.4.1
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/CHANGELOG.md +21 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.js +53 -25
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @lynx-js/external-bundle-rsbuild-plugin
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Ship the refresh runtime in the shared external bundle so it is loaded once instead of per card. ([#3009](https://github.com/lynx-family/lynx-stack/pull/3009))
|
|
8
|
+
|
|
9
|
+
`@lynx-js/react/refresh` was missing from both the `react-umd` entry and the `reactlynx` externals preset, so every card bundled its own copy. Each copy overwrites `options.debounceRendering` on the _shared_ ReactLynx runtime with a closure that defers through that card's own `Promise`. The last card loaded wins, and once it is destroyed its microtask queue stops draining — the lost flush leaves Preact's scheduling counter set, so no card in the shared context ever re-renders again.
|
|
10
|
+
|
|
11
|
+
Only the development bundle carries it; the production bundle is unchanged in size.
|
|
12
|
+
|
|
13
|
+
## 0.4.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- The `reactlynx` externals preset accepts `{ async: true }`, mounting ReactLynx as an awaited promise so async runtimes can load it via `fetchBundle().then` (the sync array form reads `React.memo` etc. off a pending promise and gets `undefined`). Externals presets resolve per environment (`environmentName` is available in the preset context): `lynx` / `lynx-*` environments use `react.lynx.bundle`, other environments (e.g. `web`) use the web-encoded `@lynx-js/react-umd/{dev,prod}-web` `react.web.bundle` — `async` only controls the mount form. ([#2934](https://github.com/lynx-family/lynx-stack/pull/2934))
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [[`34318ea`](https://github.com/lynx-family/lynx-stack/commit/34318ea3432b6484a383707458ed9c4ee19e2097)]:
|
|
22
|
+
- @lynx-js/externals-loading-webpack-plugin@0.2.1
|
|
23
|
+
|
|
3
24
|
## 0.3.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -28,6 +28,19 @@ export interface ReactLynxExternalsPresetOptions {
|
|
|
28
28
|
* @defaultValue `'@lynx-js/react-umd'`
|
|
29
29
|
*/
|
|
30
30
|
reactUmdPackageName?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Load the ReactLynx runtime bundle asynchronously, for the web target.
|
|
33
|
+
*
|
|
34
|
+
* The web runtime (`@lynx-js/web-core`) can only fetch external bundles
|
|
35
|
+
* asynchronously (`fetchBundle().then`), so ReactLynx must be mounted as a
|
|
36
|
+
* promise that consuming modules await before reading a subpath (otherwise
|
|
37
|
+
* `React.memo` etc. are read off a pending promise and are `undefined`).
|
|
38
|
+
* Enabling this also resolves the web-encoded `@lynx-js/react-umd/{dev,prod}-web`
|
|
39
|
+
* bundle and defaults `bundlePath` to `react.web.bundle`.
|
|
40
|
+
*
|
|
41
|
+
* @defaultValue `false`
|
|
42
|
+
*/
|
|
43
|
+
async?: boolean;
|
|
31
44
|
/**
|
|
32
45
|
* Override the runtime bundle URL directly.
|
|
33
46
|
*
|
|
@@ -65,6 +78,16 @@ export interface ExternalsPresetContext {
|
|
|
65
78
|
* The current Rsbuild project root path.
|
|
66
79
|
*/
|
|
67
80
|
rootPath: string;
|
|
81
|
+
/**
|
|
82
|
+
* The Rsbuild environment being resolved (e.g. `'lynx'`, `'web'`).
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
*
|
|
86
|
+
* Presets use this to pick environment-specific artifacts — for example the
|
|
87
|
+
* built-in `reactlynx` preset resolves the web-encoded `react.web.bundle`
|
|
88
|
+
* for the `web` environment and `react.lynx.bundle` otherwise.
|
|
89
|
+
*/
|
|
90
|
+
environmentName?: string;
|
|
68
91
|
}
|
|
69
92
|
/**
|
|
70
93
|
* Definition for a named externals preset.
|
package/lib/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { ExternalsLoadingPlugin } from '@lynx-js/externals-loading-webpack-plugi
|
|
|
13
13
|
const require = createRequire(import.meta.url);
|
|
14
14
|
const DEFAULT_REACT_UMD_PACKAGE_NAME = '@lynx-js/react-umd';
|
|
15
15
|
const REACT_LYNX_BUNDLE_FILE_NAME = 'react.lynx.bundle';
|
|
16
|
+
const REACT_LYNX_WEB_BUNDLE_FILE_NAME = 'react.web.bundle';
|
|
16
17
|
const reactLynxExternalTemplate = {
|
|
17
18
|
'react': {
|
|
18
19
|
libraryName: ['ReactLynx', 'React'],
|
|
@@ -86,6 +87,12 @@ const reactLynxExternalTemplate = {
|
|
|
86
87
|
mainThread: { sectionPath: 'ReactLynx__main-thread' },
|
|
87
88
|
async: false,
|
|
88
89
|
},
|
|
90
|
+
'@lynx-js/react/refresh': {
|
|
91
|
+
libraryName: ['ReactLynx', 'ReactRefresh'],
|
|
92
|
+
background: { sectionPath: 'ReactLynx' },
|
|
93
|
+
mainThread: { sectionPath: 'ReactLynx__main-thread' },
|
|
94
|
+
async: false,
|
|
95
|
+
},
|
|
89
96
|
preact: {
|
|
90
97
|
libraryName: ['ReactLynx', 'Preact'],
|
|
91
98
|
background: { sectionPath: 'ReactLynx' },
|
|
@@ -125,28 +132,39 @@ export function normalizeBundlePath(bundlePath) {
|
|
|
125
132
|
function createBuiltInExternalsPresetDefinitions() {
|
|
126
133
|
return {
|
|
127
134
|
reactlynx: {
|
|
128
|
-
resolveExternals(value) {
|
|
129
|
-
return createReactLynxExternals(normalizeReactLynxPreset(value));
|
|
135
|
+
resolveExternals(value, context) {
|
|
136
|
+
return createReactLynxExternals(normalizeReactLynxPreset(value), isWebEnvironment(context));
|
|
130
137
|
},
|
|
131
138
|
resolveManagedAssets(value, context) {
|
|
132
139
|
const preset = normalizeReactLynxPreset(value);
|
|
133
140
|
if (!preset || preset.url) {
|
|
134
141
|
return new Map();
|
|
135
142
|
}
|
|
143
|
+
const isWeb = isWebEnvironment(context);
|
|
136
144
|
return new Map([
|
|
137
145
|
[
|
|
138
|
-
getDefaultReactLynxBundlePath(preset),
|
|
139
|
-
getReactLynxBundlePath(context.rootPath, preset.reactUmdPackageName ?? DEFAULT_REACT_UMD_PACKAGE_NAME),
|
|
146
|
+
getDefaultReactLynxBundlePath(preset, isWeb),
|
|
147
|
+
getReactLynxBundlePath(context.rootPath, preset.reactUmdPackageName ?? DEFAULT_REACT_UMD_PACKAGE_NAME, isWeb),
|
|
140
148
|
],
|
|
141
149
|
]);
|
|
142
150
|
},
|
|
143
151
|
},
|
|
144
152
|
};
|
|
145
153
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
// The bundle encoding follows the target environment: `lynx` / `lynx-*`
|
|
155
|
+
// environments decode `tasm` bundles (mirroring rspeedy's `isLynx`
|
|
156
|
+
// convention), every other environment (e.g. `web`) decodes web-encoded
|
|
157
|
+
// bundles. `async` only controls how the external is mounted.
|
|
158
|
+
function isWebEnvironment(context) {
|
|
159
|
+
const name = context.environmentName;
|
|
160
|
+
if (name === undefined) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return name !== 'lynx' && !name.startsWith('lynx-');
|
|
164
|
+
}
|
|
165
|
+
function getReactLynxBundlePath(rootPath, reactUmdPackageName, isWeb) {
|
|
166
|
+
const variant = process.env['NODE_ENV'] === 'production' ? 'prod' : 'dev';
|
|
167
|
+
const reactUmdExport = `${reactUmdPackageName}/${variant}${isWeb ? '-web' : ''}`;
|
|
150
168
|
try {
|
|
151
169
|
return require.resolve(reactUmdExport, { paths: [rootPath] });
|
|
152
170
|
}
|
|
@@ -238,14 +256,15 @@ function resolvePresetExternals(externalsPresets, presetDefinitions, context) {
|
|
|
238
256
|
}
|
|
239
257
|
return { externals, managedAssets };
|
|
240
258
|
}
|
|
241
|
-
function createReactLynxExternals(preset) {
|
|
259
|
+
function createReactLynxExternals(preset, isWeb) {
|
|
242
260
|
const bundleReference = preset?.url
|
|
243
261
|
? { url: preset.url }
|
|
244
|
-
: { bundlePath: getDefaultReactLynxBundlePath(preset) };
|
|
262
|
+
: { bundlePath: getDefaultReactLynxBundlePath(preset, isWeb) };
|
|
245
263
|
return Object.fromEntries(Object.entries(reactLynxExternalTemplate).map(([request, external]) => [
|
|
246
264
|
request,
|
|
247
265
|
{
|
|
248
266
|
...external,
|
|
267
|
+
...(preset?.async === undefined ? {} : { async: preset.async }),
|
|
249
268
|
...bundleReference,
|
|
250
269
|
},
|
|
251
270
|
]));
|
|
@@ -278,8 +297,13 @@ class EmitManagedBundleAssetsPlugin {
|
|
|
278
297
|
});
|
|
279
298
|
}
|
|
280
299
|
}
|
|
281
|
-
function getDefaultReactLynxBundlePath(preset) {
|
|
282
|
-
|
|
300
|
+
function getDefaultReactLynxBundlePath(preset, isWeb) {
|
|
301
|
+
if (preset?.bundlePath) {
|
|
302
|
+
return normalizeBundlePath(preset.bundlePath);
|
|
303
|
+
}
|
|
304
|
+
return isWeb
|
|
305
|
+
? REACT_LYNX_WEB_BUNDLE_FILE_NAME
|
|
306
|
+
: REACT_LYNX_BUNDLE_FILE_NAME;
|
|
283
307
|
}
|
|
284
308
|
function joinUrlPath(base, bundlePath) {
|
|
285
309
|
const normalizedBase = base ?? '/';
|
|
@@ -312,13 +336,6 @@ function getManagedBundleAssets(options, presetManagedAssets, api) {
|
|
|
312
336
|
}
|
|
313
337
|
return assets;
|
|
314
338
|
}
|
|
315
|
-
function getLocalBundleAssets(options, presetManagedAssets, api, serverBase) {
|
|
316
|
-
const assets = new Map();
|
|
317
|
-
for (const [bundlePath, sourcePath] of getManagedBundleAssets(options, presetManagedAssets, api)) {
|
|
318
|
-
assets.set(joinUrlPath(serverBase, bundlePath), sourcePath);
|
|
319
|
-
}
|
|
320
|
-
return assets;
|
|
321
|
-
}
|
|
322
339
|
function resolvePluginExternals(externals) {
|
|
323
340
|
if (!externals) {
|
|
324
341
|
return {};
|
|
@@ -386,12 +403,16 @@ export function pluginExternalBundle(options) {
|
|
|
386
403
|
name: 'lynx:external-bundle',
|
|
387
404
|
setup(api) {
|
|
388
405
|
const presetDefinitions = resolvePresetDefinitions(options.externalsPresetDefinitions);
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
406
|
+
// Presets resolve per environment (in `modifyRspackConfig`, where the
|
|
407
|
+
// environment name is known); this map collects every environment's
|
|
408
|
+
// local bundle assets for the dev-server middleware, which reads it at
|
|
409
|
+
// request time.
|
|
410
|
+
const localBundleAssets = new Map();
|
|
411
|
+
let serverBase;
|
|
392
412
|
api.modifyRsbuildConfig((config, { mergeRsbuildConfig }) => {
|
|
393
|
-
|
|
394
|
-
if (
|
|
413
|
+
serverBase = config.server?.base;
|
|
414
|
+
if (options.externals === undefined
|
|
415
|
+
&& options.externalsPresets === undefined) {
|
|
395
416
|
return config;
|
|
396
417
|
}
|
|
397
418
|
return mergeRsbuildConfig(config, {
|
|
@@ -423,17 +444,24 @@ export function pluginExternalBundle(options) {
|
|
|
423
444
|
},
|
|
424
445
|
});
|
|
425
446
|
});
|
|
426
|
-
api.modifyRspackConfig((config) => {
|
|
447
|
+
api.modifyRspackConfig((config, { environment }) => {
|
|
427
448
|
const LAYERS = api.useExposed(Symbol.for('LAYERS'));
|
|
428
449
|
if (!LAYERS) {
|
|
429
450
|
throw new Error('external-bundle-rsbuild-plugin requires exposed `LAYERS`. Please install a DSL plugin, for example `pluginReactLynx` for ReactLynx.');
|
|
430
451
|
}
|
|
452
|
+
const presetResolution = resolvePresetExternals(options.externalsPresets, presetDefinitions, {
|
|
453
|
+
rootPath: api.context.rootPath,
|
|
454
|
+
environmentName: environment.name,
|
|
455
|
+
});
|
|
431
456
|
const explicitExternals = resolvePluginExternals(options.externals);
|
|
432
457
|
const externals = {
|
|
433
458
|
...presetResolution.externals,
|
|
434
459
|
...explicitExternals,
|
|
435
460
|
};
|
|
436
461
|
const managedBundleAssets = getManagedBundleAssets(options, presetResolution.managedAssets, api);
|
|
462
|
+
for (const [bundlePath, sourcePath] of managedBundleAssets) {
|
|
463
|
+
localBundleAssets.set(joinUrlPath(serverBase, bundlePath), sourcePath);
|
|
464
|
+
}
|
|
437
465
|
config.plugins = config.plugins || [];
|
|
438
466
|
if (managedBundleAssets.size > 0) {
|
|
439
467
|
config.plugins.push(new EmitManagedBundleAssetsPlugin(managedBundleAssets));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynx-js/external-bundle-rsbuild-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "An rsbuild plugin for loading lynx external bundles.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rsbuild",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"README.md"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@lynx-js/externals-loading-webpack-plugin": "0.2.
|
|
37
|
+
"@lynx-js/externals-loading-webpack-plugin": "0.2.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@microsoft/api-extractor": "7.58.
|
|
41
|
-
"@rsbuild/core": "2.
|
|
42
|
-
"@lynx-js/react-umd": "0.
|
|
40
|
+
"@microsoft/api-extractor": "7.58.12",
|
|
41
|
+
"@rsbuild/core": "2.1.7",
|
|
42
|
+
"@lynx-js/react-umd": "0.123.1"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=18"
|