@lynx-js/react-webpack-plugin-canary 0.14.0 → 0.15.0-canary-20261027-749147c8
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 +24 -0
- package/lib/DefinesInjection.js +12 -5
- package/lib/LynxProcessEvalResultRuntimeModule.js +8 -3
- package/lib/MainThreadHMR.d.ts +4 -0
- package/lib/MainThreadHMR.js +206 -0
- package/lib/ReactWebpackPlugin.d.ts +8 -0
- package/lib/ReactWebpackPlugin.js +50 -4
- package/lib/hmr/enabled.d.ts +1 -0
- package/lib/hmr/enabled.js +5 -0
- package/lib/loaders/main-thread.js +7 -0
- package/lib/runtime/hmr-background.d.ts +1 -0
- package/lib/runtime/hmr-background.js +94 -0
- package/lib/runtime/hmr-load.d.ts +1 -0
- package/lib/runtime/hmr-load.js +51 -0
- package/lib/runtime/hmr-main-thread.d.ts +1 -0
- package/lib/runtime/hmr-main-thread.js +76 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @lynx-js/react-webpack-plugin
|
|
2
2
|
|
|
3
|
+
## 0.15.0-canary-20261027063858-749147c82c3e0bb06f1e92567a5afec909baf19b
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Support Main Thread Function HMR in native ReactLynx development builds. Apply main-thread updates through native bundle loading before releasing background Fast Refresh, and refresh worklet owners when their main-thread dependencies change. Reload once if either runtime fails or times out, and preserve runtime version coordination when the development connection reconnects. ([#4179](https://github.com/lynx-family/lynx-stack/pull/4179))
|
|
8
|
+
|
|
9
|
+
Accept ordinary Snapshot component and helper updates at their actual main-thread entry roots, preserving explicit HMR handlers and declines. Keep a stable main-thread registration module so the first background-only worklet added during development is registered before Fast Refresh resumes.
|
|
10
|
+
|
|
11
|
+
Allow up to ten seconds for matching main-thread completion before timeout recovery.
|
|
12
|
+
|
|
13
|
+
Load background HMR updates through the same Native bundle adapter, preserve the SDK runtime wrapper in per-chunk sections, and retain the original background loader on hosts without Native app-scope initialization.
|
|
14
|
+
|
|
15
|
+
Use the build engine's exposed template plugin consistently for React compilation and Native HMR hooks, while retaining the installed template plugin as the default for direct Rspack integrations.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Apply main-thread hot updates to loaded async chunks, keep async definition modules stable when worklets are added or removed, and retain background HMR on hosts without Native bundle loading. Centralize the shared HMR runtime identifiers. ([#4179](https://github.com/lynx-family/lynx-stack/pull/4179))
|
|
20
|
+
|
|
21
|
+
Keep the refresh plugin compatible with the planned `react-webpack-plugin` 0.15 release while preserving its existing peer dependency ranges.
|
|
22
|
+
- Updated dependencies [[`7d498ae`](https://github.com/lynx-family/lynx-stack/commit/7d498aece52a20e77abc19e2a4579333861c11da), [`749147c`](https://github.com/lynx-family/lynx-stack/commit/749147c82c3e0bb06f1e92567a5afec909baf19b), [`18dc25e`](https://github.com/lynx-family/lynx-stack/commit/18dc25ecb7dc0700e63da5c648f8dee702821405), [`4b19a9b`](https://github.com/lynx-family/lynx-stack/commit/4b19a9b356f29f7177dfb423d1b0b3114e248c69)]:
|
|
23
|
+
- @lynx-js/webpack-runtime-globals@0.1.0-canary-20261027063858-749147c82c3e0bb06f1e92567a5afec909baf19b
|
|
24
|
+
- @lynx-js/react@0.129.1-canary-20261027063858-749147c82c3e0bb06f1e92567a5afec909baf19b
|
|
25
|
+
- @lynx-js/template-webpack-plugin@0.16.6-canary-20261027063858-749147c82c3e0bb06f1e92567a5afec909baf19b
|
|
26
|
+
|
|
3
27
|
## 0.14.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/lib/DefinesInjection.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import { DEFINES_FOR_SNAPSHOT_BUILD_INFO, DEFINES_FOR_WORKLET_BUILD_INFO, collectDefines, renderDefinesModule, selectMissingDefines, } from './Defines.js';
|
|
6
|
+
import { MAIN_THREAD_HMR } from './hmr/enabled.js';
|
|
6
7
|
import { LAYERS } from './layer.js';
|
|
7
8
|
import { boundaryKey, definesImportByBoundary, } from './loaders/defines-import-by-boundary.js';
|
|
8
9
|
import { REACT_RUNTIME_REQUIREMENTS_BUILD_INFO, } from './loaders/main-thread.js';
|
|
@@ -77,7 +78,7 @@ export function applyDefinesInjection(compiler, entryPairs, pluginName) {
|
|
|
77
78
|
return module ? [module] : [];
|
|
78
79
|
});
|
|
79
80
|
};
|
|
80
|
-
const processScope = async (backgroundRoots, mainThreadRoots, inheritedPresent, ancestors, request, inject) => {
|
|
81
|
+
const processScope = async (backgroundRoots, mainThreadRoots, inheritedPresent, ancestors, request, inject, keepEmpty = false) => {
|
|
81
82
|
const background = traverse(backgroundRoots);
|
|
82
83
|
const mainThread = traverse(mainThreadRoots);
|
|
83
84
|
const present = {
|
|
@@ -96,9 +97,12 @@ export function applyDefinesInjection(compiler, entryPairs, pluginName) {
|
|
|
96
97
|
if (unmergeable.length > 0) {
|
|
97
98
|
throw new Error(`The main thread lacks the worklet definition(s) ${unmergeable.map(({ id }) => id).join(', ')} and they cannot be merged: they close over shared-runtime imports. Make the owning module reachable from the main thread, or avoid closing over a shared import inside the worklet.`);
|
|
98
99
|
}
|
|
99
|
-
if (missingSnapshot.length > 0 || missingWorklet.length > 0) {
|
|
100
|
+
if (keepEmpty || missingSnapshot.length > 0 || missingWorklet.length > 0) {
|
|
100
101
|
const previousModule = [...compilation.modules].find(module => module.resource === request);
|
|
101
|
-
virtualModules.writeModule(request, renderDefinesModule(missingSnapshot, missingWorklet)
|
|
102
|
+
virtualModules.writeModule(request, renderDefinesModule(missingSnapshot, missingWorklet)
|
|
103
|
+
+ (compiler[MAIN_THREAD_HMR]
|
|
104
|
+
? '\nif (module.hot) module.hot.accept();'
|
|
105
|
+
: ''));
|
|
102
106
|
// Updating the virtual file does not invalidate a module already
|
|
103
107
|
// reused by this compilation. Rebuild it before reusing its imports.
|
|
104
108
|
if (previousModule) {
|
|
@@ -117,7 +121,7 @@ export function applyDefinesInjection(compiler, entryPairs, pluginName) {
|
|
|
117
121
|
await processScope([backgroundBoundary], [mainThreadBoundary], present, new Set([...ancestors, resource]), `${resource}.__lynx-react-defines.js`, async (boundaryRequest) => {
|
|
118
122
|
definesImports.set(boundaryKey(mainThreadBoundary.layer, resource), boundaryRequest);
|
|
119
123
|
await rebuildModule(mainThreadBoundary);
|
|
120
|
-
});
|
|
124
|
+
}, keepEmpty);
|
|
121
125
|
}
|
|
122
126
|
};
|
|
123
127
|
await Promise.all(entryPairs.map(async ({ mainThread, background }) => {
|
|
@@ -133,7 +137,10 @@ export function applyDefinesInjection(compiler, entryPairs, pluginName) {
|
|
|
133
137
|
for (const originalRequest of originalRequests) {
|
|
134
138
|
await addEntry(originalRequest);
|
|
135
139
|
}
|
|
136
|
-
}
|
|
140
|
+
},
|
|
141
|
+
// HMR only reexecutes cached self-accepted modules. Keep the root
|
|
142
|
+
// definition module executed even before its first definition.
|
|
143
|
+
Boolean(compiler[MAIN_THREAD_HMR]));
|
|
137
144
|
}));
|
|
138
145
|
// A background boundary can lose its last definition or disappear
|
|
139
146
|
// entirely while its main-thread module remains cached and reachable.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RuntimeGlobals as LynxRuntimeGlobals } from '@lynx-js/webpack-runtime-globals';
|
|
2
|
+
import { MAIN_THREAD_HMR } from './hmr/enabled.js';
|
|
2
3
|
export function createLynxProcessEvalResultRuntimeModule(webpack) {
|
|
3
4
|
return class LynxProcessEvalResultRuntimeModule extends webpack.RuntimeModule {
|
|
4
5
|
constructor() {
|
|
@@ -18,10 +19,14 @@ globalThis.processEvalResult = (${LynxRuntimeGlobals.lynxProcessEvalResultByHost
|
|
|
18
19
|
if (chunk && chunk.ids && chunk.modules) {
|
|
19
20
|
// We only deal with webpack chunk
|
|
20
21
|
${webpack.RuntimeGlobals.externalInstallChunk}(chunk);
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
${compilation.compiler[MAIN_THREAD_HMR]
|
|
23
|
+
? `var moduleIds = chunk.entryModuleIds || Object.keys(chunk.modules);
|
|
24
|
+
for (var i = 0; i < moduleIds.length; i++) {
|
|
25
|
+
${webpack.RuntimeGlobals.require}(moduleIds[i]);
|
|
26
|
+
}`
|
|
27
|
+
: `for (var moduleId in chunk.modules) {
|
|
23
28
|
${webpack.RuntimeGlobals.require}(moduleId);
|
|
24
|
-
}
|
|
29
|
+
}`}
|
|
25
30
|
return chunk;
|
|
26
31
|
}
|
|
27
32
|
return chunk
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Compiler } from '@rspack/core';
|
|
2
|
+
import type { LynxTemplatePlugin } from '@lynx-js/template-webpack-plugin';
|
|
3
|
+
import type { EntryPair } from './DefinesInjection.js';
|
|
4
|
+
export declare function applyMainThreadHMR(compiler: Compiler, entryPairs: EntryPair[], acceptEntryModules: boolean, templatePlugin: typeof LynxTemplatePlugin): void;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// Copyright 2026 The Lynx Authors. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
import { RuntimeGlobals as LynxRuntimeGlobals } from '@lynx-js/webpack-runtime-globals';
|
|
5
|
+
import { DEFINES_FOR_WORKLET_BUILD_INFO } from './Defines.js';
|
|
6
|
+
import { MAIN_THREAD_HMR } from './hmr/enabled.js';
|
|
7
|
+
import { LAYERS } from './layer.js';
|
|
8
|
+
import backgroundRuntime from './runtime/hmr-background.js';
|
|
9
|
+
import loadRuntime from './runtime/hmr-load.js';
|
|
10
|
+
import mainThreadRuntime from './runtime/hmr-main-thread.js';
|
|
11
|
+
export function applyMainThreadHMR(compiler, entryPairs, acceptEntryModules, templatePlugin) {
|
|
12
|
+
const name = 'ReactMainThreadHMR';
|
|
13
|
+
compiler[MAIN_THREAD_HMR] = true;
|
|
14
|
+
const { RuntimeGlobals, RuntimeModule, Template, sources } = compiler.webpack;
|
|
15
|
+
let previousHash;
|
|
16
|
+
let previousModules = new Map();
|
|
17
|
+
compiler.hooks.thisCompilation.tap(name, compilation => {
|
|
18
|
+
const currentModules = new Map();
|
|
19
|
+
const getFilename = (chunk, manifest, id = chunk.id) => compilation.getPath(manifest
|
|
20
|
+
? compilation.outputOptions.hotUpdateMainFilename
|
|
21
|
+
: compilation.outputOptions.hotUpdateChunkFilename, {
|
|
22
|
+
hash: previousHash,
|
|
23
|
+
chunk: { id: id, name: chunk.name },
|
|
24
|
+
runtime: [...chunk.runtime].sort().join('~'),
|
|
25
|
+
});
|
|
26
|
+
compilation.hooks.additionalTreeRuntimeRequirements.tap(name, (chunk, requirements) => {
|
|
27
|
+
for (const pair of entryPairs) {
|
|
28
|
+
const main = compilation.entrypoints.get(pair.mainThread);
|
|
29
|
+
const background = compilation.entrypoints.get(pair.background);
|
|
30
|
+
const isMain = main?.getRuntimeChunk() === chunk;
|
|
31
|
+
if (!isMain && background?.getRuntimeChunk() !== chunk)
|
|
32
|
+
continue;
|
|
33
|
+
requirements.add(RuntimeGlobals.moduleCache);
|
|
34
|
+
requirements.add(RuntimeGlobals.interceptModuleExecution);
|
|
35
|
+
requirements.add(RuntimeGlobals.getFullHash);
|
|
36
|
+
requirements.add(RuntimeGlobals.publicPath);
|
|
37
|
+
class DualThreadHMRRuntimeModule extends RuntimeModule {
|
|
38
|
+
constructor() {
|
|
39
|
+
super(name, RuntimeModule.STAGE_ATTACH);
|
|
40
|
+
}
|
|
41
|
+
generate() {
|
|
42
|
+
const dependency = compilation.entries.get(pair.mainThread)
|
|
43
|
+
.dependencies[0];
|
|
44
|
+
const module = compilation.moduleGraph.getModule(dependency);
|
|
45
|
+
return [
|
|
46
|
+
Template.getFunctionContent(loadRuntime),
|
|
47
|
+
Template.getFunctionContent(isMain ? mainThreadRuntime : backgroundRuntime),
|
|
48
|
+
].join('\n')
|
|
49
|
+
.replaceAll('$BACKGROUND$', JSON.stringify(!isMain))
|
|
50
|
+
.replaceAll('$RuntimeGlobals_lynxHMR$', LynxRuntimeGlobals.lynxHMR)
|
|
51
|
+
.replaceAll('$RuntimeGlobals_lynxHMRLoad$', LynxRuntimeGlobals.lynxHMRLoad)
|
|
52
|
+
.replaceAll('$ENTRY_MODULES$', JSON.stringify(acceptEntryModules
|
|
53
|
+
? [
|
|
54
|
+
...new Set(compilation.entries.get(pair.mainThread)
|
|
55
|
+
.dependencies.map(dependency => compilation.chunkGraph.getModuleId(compilation.moduleGraph.getModule(dependency)))),
|
|
56
|
+
]
|
|
57
|
+
: []))
|
|
58
|
+
.replaceAll('$METHOD$', JSON.stringify(`__lynxHMR_${pair.mainThread}`))
|
|
59
|
+
.replaceAll('$EVENT$', JSON.stringify(`LynxHMR:${pair.background}`))
|
|
60
|
+
.replaceAll('$HOT_MODULE$', JSON.stringify(compilation.chunkGraph.getModuleId(module)));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
compilation.addRuntimeModule(chunk, new DualThreadHMRRuntimeModule());
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
compilation.hooks.processAssets.tap({
|
|
67
|
+
name,
|
|
68
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
|
|
69
|
+
}, () => {
|
|
70
|
+
const { chunkGraph, moduleGraph } = compilation;
|
|
71
|
+
for (const pair of entryPairs) {
|
|
72
|
+
const main = compilation.entrypoints.get(pair.mainThread);
|
|
73
|
+
const background = compilation.entrypoints.get(pair.background);
|
|
74
|
+
const mainChunk = main.getRuntimeChunk();
|
|
75
|
+
const backgroundChunk = background.getRuntimeChunk();
|
|
76
|
+
const mainModules = new Set([...mainChunk.getAllReferencedChunks()].flatMap(chunk => [...chunkGraph.getChunkModulesIterable(chunk)]));
|
|
77
|
+
const backgroundModules = new Map();
|
|
78
|
+
for (const chunk of backgroundChunk.getAllReferencedChunks()) {
|
|
79
|
+
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
|
80
|
+
const resource = module.resource;
|
|
81
|
+
if (resource && module.layer === LAYERS.BACKGROUND) {
|
|
82
|
+
backgroundModules.set(resource, module);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const changed = [];
|
|
87
|
+
for (const module of mainModules) {
|
|
88
|
+
if (module.layer !== LAYERS.MAIN_THREAD)
|
|
89
|
+
continue;
|
|
90
|
+
const key = `${pair.mainThread}:${module.identifier()}`;
|
|
91
|
+
const hash = chunkGraph.getModuleHash(module, new Set(mainChunk.runtime));
|
|
92
|
+
currentModules.set(key, hash);
|
|
93
|
+
if (previousHash && previousModules.get(key) !== hash) {
|
|
94
|
+
changed.push(module);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Follow actual MTS dependencies to their worklet-owning BTS modules.
|
|
98
|
+
// Replaying their existing factories preserves Fast Refresh's own
|
|
99
|
+
// acceptance boundary; invalidating a self-accepted owner would not.
|
|
100
|
+
const owners = new Set();
|
|
101
|
+
const visited = new Set();
|
|
102
|
+
while (changed.length > 0) {
|
|
103
|
+
const module = changed.pop();
|
|
104
|
+
if (visited.has(module))
|
|
105
|
+
continue;
|
|
106
|
+
visited.add(module);
|
|
107
|
+
const resource = module.resource;
|
|
108
|
+
const owner = resource ? backgroundModules.get(resource) : undefined;
|
|
109
|
+
const defines = owner?.buildInfo?.[DEFINES_FOR_WORKLET_BUILD_INFO];
|
|
110
|
+
if (owner && Array.isArray(defines) && defines.length > 0) {
|
|
111
|
+
owners.add(chunkGraph.getModuleId(owner));
|
|
112
|
+
}
|
|
113
|
+
for (const connection of moduleGraph.getIncomingConnections(module)) {
|
|
114
|
+
if (connection.originModule
|
|
115
|
+
&& mainModules.has(connection.originModule)) {
|
|
116
|
+
changed.push(connection.originModule);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (!previousHash)
|
|
121
|
+
continue;
|
|
122
|
+
const manifestAsset = compilation.getAsset(getFilename(mainChunk, true));
|
|
123
|
+
if (!manifestAsset)
|
|
124
|
+
continue;
|
|
125
|
+
const manifest = JSON.parse(manifestAsset.source.source().toString());
|
|
126
|
+
for (const id of manifest.c) {
|
|
127
|
+
const target = [...compilation.chunks].find(chunk => chunk.id === id);
|
|
128
|
+
const file = getFilename(target, false);
|
|
129
|
+
const asset = compilation.getAsset(file);
|
|
130
|
+
compilation.updateAsset(file, asset.source, {
|
|
131
|
+
...asset.info,
|
|
132
|
+
'lynx:main-thread': true,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (owners.size > 0) {
|
|
136
|
+
const file = getFilename(backgroundChunk, false);
|
|
137
|
+
const asset = compilation.getAsset(file);
|
|
138
|
+
compilation.updateAsset(file, new sources.ConcatSource(asset.source, `\nexports.lynxRefreshModules=${JSON.stringify([...owners])};`));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
const emitted = new Set();
|
|
143
|
+
const hooks = templatePlugin.getLynxTemplatePluginHooks(compilation);
|
|
144
|
+
hooks.beforeEmit.tapPromise(name, async (args) => {
|
|
145
|
+
if (!previousHash)
|
|
146
|
+
return args;
|
|
147
|
+
for (const pair of entryPairs) {
|
|
148
|
+
if (!args.chunkGroups.some(group => group.name === pair.mainThread)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
for (const entry of [pair.mainThread, pair.background]) {
|
|
152
|
+
const isMain = entry === pair.mainThread;
|
|
153
|
+
const chunk = compilation.entrypoints.get(entry).getRuntimeChunk();
|
|
154
|
+
const filename = getFilename(chunk, true);
|
|
155
|
+
const manifest = compilation.getAsset(filename);
|
|
156
|
+
if (!manifest || emitted.has(filename))
|
|
157
|
+
continue;
|
|
158
|
+
emitted.add(filename);
|
|
159
|
+
const manifestSource = manifest.source.source().toString();
|
|
160
|
+
const sections = {
|
|
161
|
+
// BTS loadScript must initialize the same app scope as normal JS
|
|
162
|
+
// chunks. This wrapper also detects hosts predating that support.
|
|
163
|
+
manifest: {
|
|
164
|
+
content: isMain
|
|
165
|
+
? `(${manifestSource})`
|
|
166
|
+
: `({init:function(){return (${manifestSource});}})`,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
const { c: ids } = JSON.parse(manifestSource);
|
|
170
|
+
for (const id of ids) {
|
|
171
|
+
const target = [...compilation.chunks].find(chunk => chunk.id === id);
|
|
172
|
+
const file = getFilename(target, false);
|
|
173
|
+
const source = compilation.getAsset(file).source.source()
|
|
174
|
+
.toString();
|
|
175
|
+
// BTS assets already carry the runtime wrapper and its host scope.
|
|
176
|
+
// MTS chunks expose CommonJS exports without that SDK wrapper.
|
|
177
|
+
sections[file] = {
|
|
178
|
+
content: isMain
|
|
179
|
+
? `(function(){var exports={};${source}\nreturn exports;})()`
|
|
180
|
+
: source,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const encodeOptions = {
|
|
184
|
+
...args.finalEncodeOptions,
|
|
185
|
+
sourceContent: {
|
|
186
|
+
...args.finalEncodeOptions['sourceContent'],
|
|
187
|
+
appType: 'DynamicComponent',
|
|
188
|
+
},
|
|
189
|
+
lepusCode: undefined,
|
|
190
|
+
manifest: {},
|
|
191
|
+
customSections: sections,
|
|
192
|
+
};
|
|
193
|
+
const { buffer } = await hooks.encode.promise({ encodeOptions });
|
|
194
|
+
compilation.emitAsset(filename.replace(/\.json$/, '.bundle'), new sources.RawSource(buffer));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return args;
|
|
198
|
+
});
|
|
199
|
+
compilation.hooks.afterSeal.tap(name, () => {
|
|
200
|
+
// Rspack advances its HMR records even when the build has diagnostics.
|
|
201
|
+
previousHash = compilation.hash ?? undefined;
|
|
202
|
+
previousModules = currentModules;
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=MainThreadHMR.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Compiler } from '@rspack/core';
|
|
2
2
|
import type { ExtractStrConfig, TransformBuiltinAttributeNamesOptions } from '@lynx-js/react/transform';
|
|
3
|
+
import { LynxTemplatePlugin } from '@lynx-js/template-webpack-plugin';
|
|
3
4
|
import { LAYERS } from './layer.js';
|
|
4
5
|
interface ElementTemplateBuildInfo {
|
|
5
6
|
templateId: string;
|
|
@@ -36,6 +37,13 @@ export declare function mergeElementTemplatesFromModule(elementTemplates: Record
|
|
|
36
37
|
* @public
|
|
37
38
|
*/
|
|
38
39
|
interface ReactWebpackPluginOptions {
|
|
40
|
+
/**
|
|
41
|
+
* The template plugin implementation supplied by the build engine.
|
|
42
|
+
* Rsbuild integrations use the implementation exposed by `pluginLynx`.
|
|
43
|
+
*
|
|
44
|
+
* @defaultValue The `LynxTemplatePlugin` exported by `@lynx-js/template-webpack-plugin`.
|
|
45
|
+
*/
|
|
46
|
+
LynxTemplatePlugin?: typeof LynxTemplatePlugin;
|
|
39
47
|
/**
|
|
40
48
|
* Whether disable runtime warnings about using ReactLynx2.0-incompatible `SelectorQuery` APIs.
|
|
41
49
|
*/
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import invariant from 'tiny-invariant';
|
|
6
|
-
import { LynxTemplatePlugin } from '@lynx-js/template-webpack-plugin';
|
|
6
|
+
import { LynxEncodePlugin, LynxTemplatePlugin, } from '@lynx-js/template-webpack-plugin';
|
|
7
7
|
import { RuntimeGlobals } from '@lynx-js/webpack-runtime-globals';
|
|
8
8
|
import { applyDefinesInjection } from './DefinesInjection.js';
|
|
9
|
+
import { MAIN_THREAD_HMR } from './hmr/enabled.js';
|
|
9
10
|
import { LAYERS } from './layer.js';
|
|
10
11
|
import { ELEMENT_TEMPLATE_BUILD_INFO, REACT_RUNTIME_REQUIREMENTS_BUILD_INFO, } from './loaders/main-thread.js';
|
|
11
12
|
import { createLynxProcessEvalResultRuntimeModule } from './LynxProcessEvalResultRuntimeModule.js';
|
|
13
|
+
import { applyMainThreadHMR } from './MainThreadHMR.js';
|
|
12
14
|
const require = createRequire(import.meta.url);
|
|
13
15
|
const REACT_COMPILATION_RESULT = Symbol.for('@lynx-js/react/internal:compilation-result');
|
|
14
16
|
/**
|
|
@@ -222,6 +224,7 @@ class ReactWebpackPlugin {
|
|
|
222
224
|
*/
|
|
223
225
|
static { this.defaultOptions = Object
|
|
224
226
|
.freeze({
|
|
227
|
+
LynxTemplatePlugin,
|
|
225
228
|
disableCreateSelectorQueryIncompatibleWarning: false,
|
|
226
229
|
firstScreenSyncTiming: 'immediately',
|
|
227
230
|
globalPropsMode: 'reactive',
|
|
@@ -308,6 +311,13 @@ class ReactWebpackPlugin {
|
|
|
308
311
|
const entryPairs = options.entryPairs ?? [];
|
|
309
312
|
if (entryPairs.length > 0) {
|
|
310
313
|
applyDefinesInjection(compiler, entryPairs, this.constructor.name);
|
|
314
|
+
if (isDev && !options.experimental_isLazyBundle
|
|
315
|
+
&& compiler.options.plugins.some(plugin => plugin instanceof compiler.webpack.HotModuleReplacementPlugin)
|
|
316
|
+
&& compiler.options.plugins.some(plugin => plugin instanceof LynxEncodePlugin)) {
|
|
317
|
+
// ET template structure HMR is unsupported, so retain its existing
|
|
318
|
+
// acceptance boundaries instead of adding a root fallback.
|
|
319
|
+
applyMainThreadHMR(compiler, entryPairs, !options.experimental_useElementTemplate, options.LynxTemplatePlugin);
|
|
320
|
+
}
|
|
311
321
|
}
|
|
312
322
|
compiler.hooks.thisCompilation.tap(this.constructor.name, compilation => {
|
|
313
323
|
const onceForChunkSet = new WeakSet();
|
|
@@ -351,13 +361,13 @@ class ReactWebpackPlugin {
|
|
|
351
361
|
.forEach(name => this.#updateMainThreadInfo(compilation, name));
|
|
352
362
|
});
|
|
353
363
|
});
|
|
354
|
-
const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation);
|
|
364
|
+
const hooks = options.LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation);
|
|
355
365
|
// The transform appends `-react__<layer>` to a `webpackChunkName` so the
|
|
356
366
|
// two layers keep their own chunk. Strip it again here: the resulting
|
|
357
367
|
// chunk groups still make up a single lazy bundle.
|
|
358
368
|
hooks.asyncChunkName.tap(this.constructor.name, (chunkName) => chunkName.replace(/-react__(?:background|main-thread)$/, ''));
|
|
359
369
|
const { ConcatSource } = compiler.webpack.sources;
|
|
360
|
-
if (compiler.options.plugins.some((p) => p instanceof LynxTemplatePlugin)) {
|
|
370
|
+
if (compiler.options.plugins.some((p) => p instanceof options.LynxTemplatePlugin)) {
|
|
361
371
|
compilation.hooks.processAssets.tap({
|
|
362
372
|
name: this.constructor.name,
|
|
363
373
|
// This wrapper must be injected after size/minify optimizations have
|
|
@@ -378,6 +388,36 @@ class ReactWebpackPlugin {
|
|
|
378
388
|
+ 1,
|
|
379
389
|
}, () => {
|
|
380
390
|
const wrappedFiles = new Set();
|
|
391
|
+
const entryModuleIds = new Map();
|
|
392
|
+
if (compiler[MAIN_THREAD_HMR]) {
|
|
393
|
+
// Only dynamic import targets are entries. Requiring helpers as
|
|
394
|
+
// roots prevents their updates from bubbling to their owners.
|
|
395
|
+
for (const module of compilation.modules) {
|
|
396
|
+
const blocks = [...module.blocks];
|
|
397
|
+
for (const block of blocks) {
|
|
398
|
+
blocks.push(...block.blocks);
|
|
399
|
+
const group = compilation.chunkGraph.getBlockChunkGroup(block);
|
|
400
|
+
if (!group || group.isInitial()
|
|
401
|
+
|| !group.origins.every(origin => origin.module?.layer === LAYERS.MAIN_THREAD))
|
|
402
|
+
continue;
|
|
403
|
+
for (const chunk of group.chunks) {
|
|
404
|
+
let ids = entryModuleIds.get(chunk);
|
|
405
|
+
if (!ids)
|
|
406
|
+
entryModuleIds.set(chunk, ids = new Set());
|
|
407
|
+
const factories = new Set(compilation.chunkGraph
|
|
408
|
+
.getChunkModulesIterableBySourceType(chunk, 'javascript'));
|
|
409
|
+
for (const dependency of block.dependencies) {
|
|
410
|
+
const target = compilation.moduleGraph.getResolvedModule(dependency);
|
|
411
|
+
if (!target || !factories.has(target))
|
|
412
|
+
continue;
|
|
413
|
+
const id = compilation.chunkGraph.getModuleId(target);
|
|
414
|
+
if (id !== null)
|
|
415
|
+
ids.add(id);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
381
421
|
compilation.chunkGroups.forEach(chunkGroup => {
|
|
382
422
|
const isDynamicImport = !chunkGroup.isInitial()
|
|
383
423
|
&& chunkGroup.origins.every(origin => origin.module?.layer === LAYERS.MAIN_THREAD);
|
|
@@ -400,8 +440,14 @@ class ReactWebpackPlugin {
|
|
|
400
440
|
if (!asset) {
|
|
401
441
|
continue;
|
|
402
442
|
}
|
|
443
|
+
// HMR consumes CommonJS exports directly, not the lazy-bundle factory.
|
|
444
|
+
if (asset.info.hotModuleReplacement) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
403
447
|
wrappedFiles.add(file);
|
|
404
|
-
compilation.updateAsset(file, old => new ConcatSource(`(function (globDynamicComponentEntry) {\n`, ` const module = { exports: {} }\n`, ` const exports = module.exports;\n`, old,
|
|
448
|
+
compilation.updateAsset(file, old => new ConcatSource(`(function (globDynamicComponentEntry) {\n`, ` const module = { exports: {} }\n`, ` const exports = module.exports;\n`, old, entryModuleIds.has(chunk)
|
|
449
|
+
? `\n module.exports.entryModuleIds = ${JSON.stringify([...entryModuleIds.get(chunk)])};`
|
|
450
|
+
: '', `\n ;return module.exports\n})`));
|
|
405
451
|
}
|
|
406
452
|
});
|
|
407
453
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MAIN_THREAD_HMR: symbol;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 The Lynx Authors. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
export const MAIN_THREAD_HMR = Symbol.for('@lynx-js/react/internal:main-thread-hmr');
|
|
5
|
+
//# sourceMappingURL=enabled.js.map
|
|
@@ -6,6 +6,7 @@ import { UI_SOURCE_MAP_RECORDS_BUILD_INFO } from '@lynx-js/debug-metadata';
|
|
|
6
6
|
import { DEFINES_FOR_SNAPSHOT_BUILD_INFO, DEFINES_FOR_WORKLET_BUILD_INFO, } from '../Defines.js';
|
|
7
7
|
import { boundaryKey, definesImportByBoundary, } from './defines-import-by-boundary.js';
|
|
8
8
|
import { getMainThreadTransformOptions } from './options.js';
|
|
9
|
+
import { MAIN_THREAD_HMR } from '../hmr/enabled.js';
|
|
9
10
|
export const ELEMENT_TEMPLATE_BUILD_INFO = 'lynx:element-templates';
|
|
10
11
|
export const REACT_RUNTIME_REQUIREMENTS_BUILD_INFO = 'lynx:react-runtime-requirements';
|
|
11
12
|
const mainThreadLoader = function (content, sourceMap) {
|
|
@@ -110,6 +111,12 @@ const mainThreadLoader = function (content, sourceMap) {
|
|
|
110
111
|
: undefined;
|
|
111
112
|
this.callback(null, result.code
|
|
112
113
|
+ (definesImport ? `\nimport ${JSON.stringify(definesImport)};` : '')
|
|
114
|
+
+ (this.hot
|
|
115
|
+
&& this._compiler?.[MAIN_THREAD_HMR]
|
|
116
|
+
&& ((result.definesForSnapshot?.length ?? 0) > 0
|
|
117
|
+
|| (result.definesForWorklet?.length ?? 0) > 0)
|
|
118
|
+
? '\nif (module.hot && !module.hot._selfAccepted && !module.hot._selfDeclined) module.hot.accept();'
|
|
119
|
+
: '')
|
|
113
120
|
+ (this.hot
|
|
114
121
|
// TODO: temporary fix LEPUS error `$RefreshReg$ is not defined`
|
|
115
122
|
// should make react-refresh transform in `react-transform`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function (): void;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright 2026 The Lynx Authors. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
// @ts-nocheck
|
|
5
|
+
/* istanbul ignore file -- stringified into the application runtime */
|
|
6
|
+
export default function () {
|
|
7
|
+
var sequence = 0;
|
|
8
|
+
var session = Date.now().toString(36) + Math.random().toString(36).slice(2);
|
|
9
|
+
var pending;
|
|
10
|
+
var failed = false;
|
|
11
|
+
var applying = false;
|
|
12
|
+
var executionError;
|
|
13
|
+
var expectedHash;
|
|
14
|
+
// Fast Refresh's self-accept handler can consume a factory exception. Record
|
|
15
|
+
// it at execution, before that handler runs, and check it before committing.
|
|
16
|
+
__webpack_require__.i.push(function (options) {
|
|
17
|
+
var factory = options.factory;
|
|
18
|
+
options.factory = function () {
|
|
19
|
+
try {
|
|
20
|
+
return factory.apply(this, arguments);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (applying) {
|
|
24
|
+
executionError = error instanceof Error
|
|
25
|
+
? error
|
|
26
|
+
: new Error(String(error));
|
|
27
|
+
}
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
lynx.getCoreContext().addEventListener($EVENT$, function (event) {
|
|
33
|
+
var ack = JSON.parse(event.data);
|
|
34
|
+
if (failed || ack.session !== session || !pending
|
|
35
|
+
|| pending.sequence !== ack.sequence)
|
|
36
|
+
return;
|
|
37
|
+
var waiter = pending;
|
|
38
|
+
pending = undefined;
|
|
39
|
+
clearTimeout(waiter.timer);
|
|
40
|
+
if (ack.supported === false) {
|
|
41
|
+
$RuntimeGlobals_lynxHMR$ = undefined;
|
|
42
|
+
$RuntimeGlobals_lynxHMRLoad$ = undefined;
|
|
43
|
+
waiter.resolve(false);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (ack.ok) {
|
|
47
|
+
expectedHash = ack.hash;
|
|
48
|
+
applying = true;
|
|
49
|
+
waiter.resolve();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
waiter.reject(new Error(ack.error));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
$RuntimeGlobals_lynxHMR$ = {
|
|
56
|
+
prepare: function (hash) {
|
|
57
|
+
if (failed)
|
|
58
|
+
return Promise.reject(new Error('HMR transaction stopped'));
|
|
59
|
+
executionError = undefined;
|
|
60
|
+
return new Promise(function (resolve, reject) {
|
|
61
|
+
var currentSequence = ++sequence;
|
|
62
|
+
pending = {
|
|
63
|
+
sequence: currentSequence,
|
|
64
|
+
resolve: resolve,
|
|
65
|
+
reject: reject,
|
|
66
|
+
timer: setTimeout(function () {
|
|
67
|
+
pending = undefined;
|
|
68
|
+
reject(new Error('Main-thread HMR completion timed out'));
|
|
69
|
+
}, 10000),
|
|
70
|
+
};
|
|
71
|
+
lynx.getNativeApp().callLepusMethod($METHOD$, {
|
|
72
|
+
session: session,
|
|
73
|
+
sequence: currentSequence,
|
|
74
|
+
hash: hash,
|
|
75
|
+
}, function () { });
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
finish: function (hash) {
|
|
79
|
+
if (executionError)
|
|
80
|
+
throw executionError;
|
|
81
|
+
if (hash !== expectedHash)
|
|
82
|
+
throw new Error('HMR thread hashes differ');
|
|
83
|
+
applying = false;
|
|
84
|
+
},
|
|
85
|
+
stop: function () {
|
|
86
|
+
failed = true;
|
|
87
|
+
applying = false;
|
|
88
|
+
if (pending)
|
|
89
|
+
clearTimeout(pending.timer);
|
|
90
|
+
pending = undefined;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=hmr-background.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function (): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Copyright 2026 The Lynx Authors. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
// @ts-nocheck
|
|
5
|
+
/* istanbul ignore file -- stringified into the application runtime */
|
|
6
|
+
export default function () {
|
|
7
|
+
if (typeof lynx.fetchBundle !== 'function'
|
|
8
|
+
|| typeof lynx.loadScript !== 'function')
|
|
9
|
+
return;
|
|
10
|
+
var bundleName;
|
|
11
|
+
$RuntimeGlobals_lynxHMRLoad$ = function (name, callback) {
|
|
12
|
+
if (name.endsWith('.json')) {
|
|
13
|
+
// Native ResponseHandler is a thenable, not a chainable Promise.
|
|
14
|
+
new Promise(function (resolve, reject) {
|
|
15
|
+
lynx.fetchBundle(name.slice(0, -5) + '.bundle', {}).then(resolve, reject);
|
|
16
|
+
}).then(function (response) {
|
|
17
|
+
if (response.code !== 0)
|
|
18
|
+
throw new Error(JSON.stringify(response));
|
|
19
|
+
bundleName = response.url;
|
|
20
|
+
return lynx.loadScript('manifest', { bundleName: bundleName });
|
|
21
|
+
}).then(function (manifest) {
|
|
22
|
+
// Early BTS hosts expose loadScript but return the wrapper instead of
|
|
23
|
+
// initializing its app scope. Probe that contract before applying code.
|
|
24
|
+
if ($BACKGROUND$ && typeof manifest.init === 'function') {
|
|
25
|
+
$RuntimeGlobals_lynxHMRLoad$ = undefined;
|
|
26
|
+
return new Promise(function (resolve, reject) {
|
|
27
|
+
lynx.requireModuleAsync(name, function (error, result) {
|
|
28
|
+
if (error)
|
|
29
|
+
reject(error);
|
|
30
|
+
else
|
|
31
|
+
resolve(result);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return manifest;
|
|
36
|
+
}).then(function (manifest) {
|
|
37
|
+
callback(null, manifest);
|
|
38
|
+
}, callback);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
try {
|
|
42
|
+
var filename = name.slice(__webpack_require__.p.length);
|
|
43
|
+
callback(null, lynx.loadScript(filename, { bundleName: bundleName }));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
callback(error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=hmr-load.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function (): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Copyright 2026 The Lynx Authors. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
// @ts-nocheck
|
|
5
|
+
/* istanbul ignore file -- stringified into the application runtime */
|
|
6
|
+
export default function () {
|
|
7
|
+
var applying = false;
|
|
8
|
+
var executionError;
|
|
9
|
+
// CSS and app imports are parallel entry roots. Accept the actual roots,
|
|
10
|
+
// while helpers still bubble through and replay their worklet owners.
|
|
11
|
+
__webpack_require__.i.push(function (options) {
|
|
12
|
+
var factory = options.factory;
|
|
13
|
+
options.factory = function () {
|
|
14
|
+
try {
|
|
15
|
+
factory.apply(this, arguments);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
// A self-accept handler can consume this exception. Preserve it for
|
|
19
|
+
// the transaction check even when hot.check() subsequently resolves.
|
|
20
|
+
if (applying) {
|
|
21
|
+
executionError = error instanceof Error
|
|
22
|
+
? error
|
|
23
|
+
: new Error(String(error));
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
if ($ENTRY_MODULES$.includes(options.id)) {
|
|
28
|
+
var hot = options.module.hot;
|
|
29
|
+
if (!hot._selfAccepted && !hot._selfDeclined)
|
|
30
|
+
hot.accept();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
globalThis[$METHOD$] = function (request) {
|
|
35
|
+
var acknowledge = function (ok, error, supported) {
|
|
36
|
+
lynx.getJSContext().dispatchEvent({
|
|
37
|
+
type: $EVENT$,
|
|
38
|
+
data: JSON.stringify({
|
|
39
|
+
session: request.session,
|
|
40
|
+
sequence: request.sequence,
|
|
41
|
+
hash: __webpack_require__.h(),
|
|
42
|
+
ok: ok,
|
|
43
|
+
supported: supported,
|
|
44
|
+
error: error && String(error),
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
if (applying || request.hash !== __webpack_require__.h()) {
|
|
49
|
+
acknowledge(false, new Error('Main-thread HMR version mismatch'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Native loading is optional on older hosts; ordinary BTS HMR can continue.
|
|
53
|
+
if (typeof lynx.fetchBundle !== 'function'
|
|
54
|
+
|| typeof lynx.loadScript !== 'function') {
|
|
55
|
+
acknowledge(false, undefined, false);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
applying = true;
|
|
59
|
+
executionError = undefined;
|
|
60
|
+
Promise.resolve().then(function () {
|
|
61
|
+
return __webpack_require__.c[$HOT_MODULE$].hot.check(true);
|
|
62
|
+
}).then(function (updated) {
|
|
63
|
+
if (executionError)
|
|
64
|
+
throw executionError;
|
|
65
|
+
if (updated === null) {
|
|
66
|
+
throw new Error('Main-thread HMR update is missing');
|
|
67
|
+
}
|
|
68
|
+
applying = false;
|
|
69
|
+
acknowledge(true);
|
|
70
|
+
}).catch(function (error) {
|
|
71
|
+
applying = false;
|
|
72
|
+
acknowledge(false, error);
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=hmr-main-thread.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynx-js/react-webpack-plugin-canary",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-canary-20261027-749147c8",
|
|
4
4
|
"description": "A webpack plugin for ReactLynx",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"webpack",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@lynx-js/debug-metadata": "npm:@lynx-js/debug-metadata-canary@0.1.0",
|
|
37
|
-
"@lynx-js/webpack-runtime-globals": "npm:@lynx-js/webpack-runtime-globals-canary@0.0
|
|
37
|
+
"@lynx-js/webpack-runtime-globals": "npm:@lynx-js/webpack-runtime-globals-canary@0.1.0-canary-20261027-749147c8",
|
|
38
38
|
"tiny-invariant": "^1.3.3"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@lynx-js/chunk-loading-webpack-plugin": "npm:@lynx-js/chunk-loading-webpack-plugin-canary@0.4.
|
|
41
|
+
"@lynx-js/chunk-loading-webpack-plugin": "npm:@lynx-js/chunk-loading-webpack-plugin-canary@0.4.3-canary-20261027-749147c8",
|
|
42
42
|
"@lynx-js/css-extract-webpack-plugin": "npm:@lynx-js/css-extract-webpack-plugin-canary@0.11.1",
|
|
43
|
-
"@lynx-js/react": "npm:@lynx-js/react-canary@0.129.
|
|
44
|
-
"@lynx-js/template-webpack-plugin": "npm:@lynx-js/template-webpack-plugin-canary@0.16.
|
|
43
|
+
"@lynx-js/react": "npm:@lynx-js/react-canary@0.129.1-canary-20261027-749147c8",
|
|
44
|
+
"@lynx-js/template-webpack-plugin": "npm:@lynx-js/template-webpack-plugin-canary@0.16.6-canary-20261027-749147c8",
|
|
45
45
|
"@lynx-js/test-tools": "0.0.0",
|
|
46
46
|
"@microsoft/api-extractor": "7.59.4",
|
|
47
47
|
"@rspack/core": "2.2.7",
|