rollipop 1.0.0-beta.2 → 1.0.0-beta.4
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/dist/config/types.d.ts +3 -2
- package/dist/constants.js +1 -1
- package/dist/core/plugins/babel-plugin.js +1 -1
- package/dist/core/plugins/dev-server-plugin.js +30 -5
- package/dist/core/rolldown.js +4 -10
- package/dist/hmr-runtime.iife.js +213 -139
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/node/commands/bundle/command.js +8 -0
- package/dist/package.js +1 -1
- package/dist/server/devframe/index.js +1 -1
- package/dist/server/devframe/setup.js +4 -1
- package/dist/storage/file-storage.js +1 -1
- package/dist/utils/transform.js +2 -1
- package/dist/utils/worklets.d.ts +7 -0
- package/dist/utils/worklets.js +32 -0
- package/package.json +3 -3
- package/src/runtime/__tests__/hmr-runtime.spec.ts +171 -72
- package/src/runtime/hmr-client.ts +1 -1
- package/src/runtime/hmr-runtime.ts +76 -0
|
@@ -14,6 +14,14 @@ const command = {
|
|
|
14
14
|
description: "Path to the CLI configuration file",
|
|
15
15
|
parse: resolvePath
|
|
16
16
|
},
|
|
17
|
+
{
|
|
18
|
+
name: "--config-cmd <string>",
|
|
19
|
+
description: "Accepted for React Native Xcode compatibility; ignored."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "--load-config <string>",
|
|
23
|
+
description: "Accepted for React Native Xcode compatibility; ignored."
|
|
24
|
+
},
|
|
17
25
|
{
|
|
18
26
|
name: "--entry-file <path>",
|
|
19
27
|
description: "Path to the root JS file, either absolute or relative to JS root"
|
package/dist/package.js
CHANGED
|
@@ -21,7 +21,7 @@ var RollipopDevframeController = class {
|
|
|
21
21
|
this.definition = defineDevframe({
|
|
22
22
|
id: "rollipop",
|
|
23
23
|
name: "Rollipop",
|
|
24
|
-
version: "1.0.0-beta.
|
|
24
|
+
version: "1.0.0-beta.4",
|
|
25
25
|
packageName: "rollipop",
|
|
26
26
|
homepage: "https://github.com/rollipop-dev/rollipop",
|
|
27
27
|
description: "React Native development dashboard powered by Rollipop.",
|
|
@@ -16,7 +16,7 @@ async function setupDevframe(context, server, inspectorDeviceServer) {
|
|
|
16
16
|
const controller = new RollipopDevframeController(context, createAgentToolContext(context));
|
|
17
17
|
const devtools = initHub({
|
|
18
18
|
name: DEVFRAME_NAME,
|
|
19
|
-
version: "1.0.0-beta.
|
|
19
|
+
version: "1.0.0-beta.4",
|
|
20
20
|
base: ROLLIPOP_DEVFRAME_BASE,
|
|
21
21
|
cwd: context.config.root,
|
|
22
22
|
ui: createUi({
|
|
@@ -39,6 +39,9 @@ async function setupDevframe(context, server, inspectorDeviceServer) {
|
|
|
39
39
|
mcp: mcpEnabled ? { path: ROLLIPOP_DEVFRAME_MCP_PATH } : false,
|
|
40
40
|
origin: context.serverBaseUrl,
|
|
41
41
|
configure: async (devtoolsContext) => {
|
|
42
|
+
(await devtoolsContext.rpc.sharedState.get("devframe:user-settings")).mutate((state) => {
|
|
43
|
+
state.autoCollapseEdgeToolbar ??= false;
|
|
44
|
+
});
|
|
42
45
|
await controller.definition.setup(devtoolsContext);
|
|
43
46
|
await invokeDevToolsSetup(devtoolsContext, server, context.config.plugins ?? []);
|
|
44
47
|
}
|
|
@@ -28,7 +28,7 @@ var FileStorage = class FileStorage {
|
|
|
28
28
|
this.dataFilePath = path.join(FileStorage.getPath(basePath, { prepare: true }), DATA_FILENAME);
|
|
29
29
|
if (fs.existsSync(this.dataFilePath)) {
|
|
30
30
|
const loadedData = JSON.parse(fs.readFileSync(this.dataFilePath, "utf-8"));
|
|
31
|
-
if ("version" in loadedData && loadedData.version === "1.0.0-beta.
|
|
31
|
+
if ("version" in loadedData && loadedData.version === "1.0.0-beta.4") this.data = loadedData;
|
|
32
32
|
else {
|
|
33
33
|
this.data = createDefaultData();
|
|
34
34
|
this.flush();
|
package/dist/utils/transform.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveWorkletsConfig } from "./worklets.js";
|
|
1
2
|
import { RollipopReactNativeTransformer } from "@rollipop/rolldown/experimental";
|
|
2
3
|
//#region src/utils/transform.ts
|
|
3
4
|
const transformers = /* @__PURE__ */ new WeakMap();
|
|
@@ -8,7 +9,7 @@ function transformWithRollipop(id, code, config) {
|
|
|
8
9
|
envName: config.mode,
|
|
9
10
|
runtimeTarget: config.runtimeTarget,
|
|
10
11
|
flow: config.transform.flow,
|
|
11
|
-
worklets: config.experimental.worklets,
|
|
12
|
+
worklets: resolveWorkletsConfig(config.experimental.worklets, config),
|
|
12
13
|
swc: {
|
|
13
14
|
externalHelpers: true,
|
|
14
15
|
...config.transform.swc?.native
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RollipopReactNativeWorkletsConfig as WorkletsConfig } from "../config/types.js";
|
|
2
|
+
import "../config/index.js";
|
|
3
|
+
import { ResolvedConfig } from "../config/defaults.js";
|
|
4
|
+
import { RollipopReactNativeWorkletsConfig } from "@rollipop/rolldown/experimental";
|
|
5
|
+
//#region src/utils/worklets.d.ts
|
|
6
|
+
export declare function resolveWorkletsConfig(worklets: WorkletsConfig | undefined, { root, mode }: Pick<ResolvedConfig, 'root' | 'mode'>): RollipopReactNativeWorkletsConfig | undefined;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { resolvePackageJson } from "./node-resolve.js";
|
|
2
|
+
import { satisfies } from "semver";
|
|
3
|
+
//#region src/utils/worklets.ts
|
|
4
|
+
function resolveWorkletsConfig(worklets, { root, mode }) {
|
|
5
|
+
if (worklets == null) return;
|
|
6
|
+
const { pluginVersion, reanimatedVersion, ...options } = worklets;
|
|
7
|
+
const defaults = {
|
|
8
|
+
...options,
|
|
9
|
+
isRelease: options.isRelease ?? mode === "production"
|
|
10
|
+
};
|
|
11
|
+
if (pluginVersion != null) return {
|
|
12
|
+
...defaults,
|
|
13
|
+
pluginVersion
|
|
14
|
+
};
|
|
15
|
+
if (reanimatedVersion != null) return {
|
|
16
|
+
...defaults,
|
|
17
|
+
reanimatedVersion
|
|
18
|
+
};
|
|
19
|
+
const installedReanimatedVersion = resolvePackageJson(root, "react-native-reanimated")?.version;
|
|
20
|
+
if (installedReanimatedVersion != null && satisfies(installedReanimatedVersion, "3.x", { includePrerelease: true })) return {
|
|
21
|
+
...defaults,
|
|
22
|
+
reanimatedVersion: installedReanimatedVersion
|
|
23
|
+
};
|
|
24
|
+
const installedWorkletsVersion = resolvePackageJson(root, "react-native-worklets")?.version;
|
|
25
|
+
if (installedWorkletsVersion != null) return {
|
|
26
|
+
...defaults,
|
|
27
|
+
pluginVersion: installedWorkletsVersion
|
|
28
|
+
};
|
|
29
|
+
throw new Error("Could not resolve a worklet runtime. Install react-native-reanimated 3.x or react-native-worklets, or set reanimatedVersion or pluginVersion in the worklets configuration.");
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { resolveWorkletsConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rollipop",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.4",
|
|
4
4
|
"homepage": "https://github.com/rollipop-dev/rollipop#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/rollipop-dev/rollipop/issues"
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"@react-native-community/cli-server-api": "20.2.0",
|
|
68
68
|
"@react-native-community/cli-types": "20.2.0",
|
|
69
69
|
"@react-native/dev-middleware": "0.88.0",
|
|
70
|
-
"@rollipop/dashboard": "1.0.0-beta.
|
|
71
|
-
"@rollipop/rolldown": "1.
|
|
70
|
+
"@rollipop/dashboard": "1.0.0-beta.4",
|
|
71
|
+
"@rollipop/rolldown": "1.2.0",
|
|
72
72
|
"@swc/core": "1.16.13",
|
|
73
73
|
"@swc/helpers": "0.5.23",
|
|
74
74
|
"@types/ws": "8.18.2",
|
|
@@ -2,12 +2,13 @@ import fs from 'node:fs';
|
|
|
2
2
|
import { stripVTControlCharacters } from 'node:util';
|
|
3
3
|
import vm from 'node:vm';
|
|
4
4
|
|
|
5
|
+
import { DevRuntime } from '@rollipop/rolldown/experimental/runtime';
|
|
5
6
|
import { transformSync } from '@swc/core';
|
|
6
7
|
import * as prettyFormat from 'pretty-format';
|
|
7
8
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vite-plus/test';
|
|
8
9
|
|
|
9
10
|
import type { HMRContext } from '../../types/hmr';
|
|
10
|
-
import type { HMRGraphRuntime
|
|
11
|
+
import type { HMRGraphRuntime } from '../../types/runtime';
|
|
11
12
|
|
|
12
13
|
const clientCode = transformSync(
|
|
13
14
|
fs.readFileSync(new URL('../hmr-client.ts', import.meta.url), 'utf8'),
|
|
@@ -18,73 +19,6 @@ const clientCode = transformSync(
|
|
|
18
19
|
},
|
|
19
20
|
).code;
|
|
20
21
|
|
|
21
|
-
class FakeDevRuntime {
|
|
22
|
-
clientId: string;
|
|
23
|
-
hooks: {
|
|
24
|
-
createModuleHotContext(moduleId: string): unknown;
|
|
25
|
-
onModuleCacheRemoval(moduleId: string): void;
|
|
26
|
-
} | null = null;
|
|
27
|
-
private readonly factories = new Map<string, (id: string) => void>();
|
|
28
|
-
private readonly importers = new Map<string, Set<string>>();
|
|
29
|
-
private readonly modules = new Map<string, { exports: any }>();
|
|
30
|
-
|
|
31
|
-
constructor(clientId: string) {
|
|
32
|
-
this.clientId = clientId;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
registerGraph(delta: ModuleGraphDelta) {
|
|
36
|
-
for (let index = 0; index < delta.localCount; index++) {
|
|
37
|
-
const importer = delta.ids[index];
|
|
38
|
-
for (const targetIndex of delta.edges[index]) {
|
|
39
|
-
const target = delta.ids[targetIndex];
|
|
40
|
-
const importers = this.importers.get(target) ?? new Set();
|
|
41
|
-
importers.add(importer);
|
|
42
|
-
this.importers.set(target, importers);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
registerFactory(id: string, _kind: 'esm' | 'cjs', factory: (id: string) => void) {
|
|
48
|
-
this.factories.set(id, factory);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
registerModule(id: string, exportsHolder: { exports: any }) {
|
|
52
|
-
this.modules.set(id, exportsHolder);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
getImporters(id: string) {
|
|
56
|
-
return [...(this.importers.get(id) ?? [])];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
isExecuted(id: string) {
|
|
60
|
-
return this.modules.has(id);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
hasFactory(id: string) {
|
|
64
|
-
return this.factories.has(id);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
removeModuleCache(id: string) {
|
|
68
|
-
this.modules.delete(id);
|
|
69
|
-
this.hooks?.onModuleCacheRemoval(id);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
initModule(id: string) {
|
|
73
|
-
if (!this.modules.has(id)) {
|
|
74
|
-
this.factories.get(id)?.(id);
|
|
75
|
-
}
|
|
76
|
-
return this.loadExports(id);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
loadExports(id: string) {
|
|
80
|
-
return this.modules.get(id)?.exports ?? {};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
createModuleHotContext(moduleId: string) {
|
|
84
|
-
return this.hooks?.createModuleHotContext(moduleId);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
22
|
class FakeWebSocket {
|
|
89
23
|
static readonly CONNECTING = 0;
|
|
90
24
|
static readonly OPEN = 1;
|
|
@@ -124,7 +58,7 @@ describe('HMR runtime', () => {
|
|
|
124
58
|
reload.mockReset();
|
|
125
59
|
FakeWebSocket.instances = [];
|
|
126
60
|
Object.assign(globalThis, {
|
|
127
|
-
DevRuntime
|
|
61
|
+
DevRuntime,
|
|
128
62
|
WebSocket: FakeWebSocket,
|
|
129
63
|
__rollipop_runtime__: undefined,
|
|
130
64
|
__turboModuleProxy: undefined,
|
|
@@ -133,6 +67,7 @@ describe('HMR runtime', () => {
|
|
|
133
67
|
});
|
|
134
68
|
|
|
135
69
|
afterEach(() => {
|
|
70
|
+
delete (globalThis as any).__rollipop_require__;
|
|
136
71
|
delete (globalThis as any).globalEvalWithSourceUrl;
|
|
137
72
|
delete (globalThis as any).__rollipop_runtime__;
|
|
138
73
|
});
|
|
@@ -143,6 +78,145 @@ describe('HMR runtime', () => {
|
|
|
143
78
|
expect((runtime.createModuleHotContext('entry.js') as any).runtime).toBe(runtime);
|
|
144
79
|
});
|
|
145
80
|
|
|
81
|
+
describe('initial bundle factories and cache', () => {
|
|
82
|
+
it.each(['esm', 'cjs'])(
|
|
83
|
+
'reuses an initial %s factory after eviction through either executor',
|
|
84
|
+
async (kind) => {
|
|
85
|
+
const { runtime } = await setupRuntime();
|
|
86
|
+
const bundleRequire = createBundleRequire();
|
|
87
|
+
let executions = 0;
|
|
88
|
+
bundleRequire.m['parent.js'] = (_global, module, exports) => {
|
|
89
|
+
const value = ++executions;
|
|
90
|
+
if (kind === 'esm') {
|
|
91
|
+
Object.defineProperty(exports, 'value', { get: () => value });
|
|
92
|
+
runtime.registerModule('parent.js', { exports });
|
|
93
|
+
} else {
|
|
94
|
+
runtime.registerModule('parent.js', module);
|
|
95
|
+
module.exports = () => value;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const readValue = (exports: any) => (kind === 'esm' ? exports.value : exports());
|
|
99
|
+
|
|
100
|
+
expect(runtime.hasFactory('parent.js')).toBe(true);
|
|
101
|
+
expect(runtime.isExecuted('parent.js')).toBe(false);
|
|
102
|
+
const first = bundleRequire('parent.js');
|
|
103
|
+
expect(runtime.initModule('parent.js')).toBe(first);
|
|
104
|
+
expect(runtime.loadExports('parent.js')).toBe(first);
|
|
105
|
+
expect(readValue(first)).toBe(1);
|
|
106
|
+
|
|
107
|
+
runtime.removeModuleCache('parent.js');
|
|
108
|
+
expect(bundleRequire.c['parent.js']).toBeUndefined();
|
|
109
|
+
expect(runtime.isExecuted('parent.js')).toBe(false);
|
|
110
|
+
const second = runtime.initModule('parent.js');
|
|
111
|
+
expect(bundleRequire('parent.js')).toBe(second);
|
|
112
|
+
expect(readValue(second)).toBe(2);
|
|
113
|
+
|
|
114
|
+
runtime.removeModuleCache('parent.js');
|
|
115
|
+
const third = bundleRequire('parent.js');
|
|
116
|
+
expect(runtime.loadExports('parent.js')).toBe(third);
|
|
117
|
+
expect(readValue(third)).toBe(3);
|
|
118
|
+
},
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
it.each(['esm', 'cjs'])(
|
|
122
|
+
'uses the latest %s patch from ordinary require after repeated eviction',
|
|
123
|
+
async (kind) => {
|
|
124
|
+
const { runtime } = await setupRuntime();
|
|
125
|
+
const bundleRequire = createBundleRequire();
|
|
126
|
+
const original = vi.fn((_global, module: BundleModule) => {
|
|
127
|
+
runtime.registerModule('dep.js', module);
|
|
128
|
+
module.exports = { value: 'initial' };
|
|
129
|
+
});
|
|
130
|
+
bundleRequire.m['dep.js'] = original;
|
|
131
|
+
expect(bundleRequire('dep.js')).toEqual({ value: 'initial' });
|
|
132
|
+
|
|
133
|
+
for (let version = 1; version <= 2; version++) {
|
|
134
|
+
const factory = vi.fn((id: string) => {
|
|
135
|
+
const holder = { exports: {} as any };
|
|
136
|
+
runtime.registerModule(id, holder);
|
|
137
|
+
if (kind === 'esm') {
|
|
138
|
+
Object.defineProperty(holder.exports, 'value', { get: () => version });
|
|
139
|
+
} else {
|
|
140
|
+
holder.exports = () => version;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
runtime.registerFactory('dep.js', factory, version);
|
|
144
|
+
runtime.removeModuleCache('dep.js');
|
|
145
|
+
const updated = runtime.initModule('dep.js');
|
|
146
|
+
expect(bundleRequire('dep.js')).toBe(updated);
|
|
147
|
+
expect(kind === 'esm' ? (updated as any).value : (updated as any)()).toBe(version);
|
|
148
|
+
|
|
149
|
+
const stale = vi.fn();
|
|
150
|
+
runtime.registerFactory('dep.js', stale, version - 1);
|
|
151
|
+
runtime.removeModuleCache('dep.js');
|
|
152
|
+
const reexecuted = bundleRequire('dep.js');
|
|
153
|
+
expect(runtime.initModule('dep.js')).toBe(reexecuted);
|
|
154
|
+
expect(runtime.loadExports('dep.js')).toBe(reexecuted);
|
|
155
|
+
expect(kind === 'esm' ? reexecuted.value : reexecuted()).toBe(version);
|
|
156
|
+
expect(factory).toHaveBeenCalledTimes(2);
|
|
157
|
+
expect(stale).not.toHaveBeenCalled();
|
|
158
|
+
}
|
|
159
|
+
expect(original).toHaveBeenCalledOnce();
|
|
160
|
+
},
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
it.each([null, undefined, 0, false])(
|
|
164
|
+
'shares CommonJS module.exports reassignment to %s',
|
|
165
|
+
async (value) => {
|
|
166
|
+
const { runtime } = await setupRuntime();
|
|
167
|
+
const bundleRequire = createBundleRequire();
|
|
168
|
+
const module = { exports: {} as any };
|
|
169
|
+
runtime.registerModule('dep.cjs', module);
|
|
170
|
+
module.exports = value;
|
|
171
|
+
expect(bundleRequire('dep.cjs')).toBe(value);
|
|
172
|
+
expect(runtime.loadExports('dep.cjs')).toBe(value);
|
|
173
|
+
expect(runtime.initModule('dep.cjs')).toBe(value);
|
|
174
|
+
},
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
it('recognizes modules cached only by the bundle and removes both caches before disposal', async () => {
|
|
178
|
+
const { runtime } = await setupRuntime();
|
|
179
|
+
const bundleRequire = createBundleRequire();
|
|
180
|
+
const exports = { value: 'cached' };
|
|
181
|
+
bundleRequire.c['helper.js'] = { exports };
|
|
182
|
+
expect(runtime.isExecuted('helper.js')).toBe(true);
|
|
183
|
+
expect(runtime.loadExports('helper.js')).toBe(exports);
|
|
184
|
+
expect(runtime.initModule('helper.js')).toBe(exports);
|
|
185
|
+
const dispose = vi.fn(() => {
|
|
186
|
+
expect(bundleRequire.c['helper.js']).toBeUndefined();
|
|
187
|
+
expect(runtime.isExecuted('helper.js')).toBe(false);
|
|
188
|
+
});
|
|
189
|
+
runtime.createModuleHotContext('helper.js').dispose(dispose);
|
|
190
|
+
runtime.removeModuleCache('helper.js');
|
|
191
|
+
expect(dispose).toHaveBeenCalledOnce();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('shares the bundle holder when a side-effect module registers without exports', async () => {
|
|
195
|
+
const { runtime } = await setupRuntime();
|
|
196
|
+
const bundleRequire = createBundleRequire();
|
|
197
|
+
bundleRequire.m['side-effect.js'] = () => runtime.registerModule('side-effect.js');
|
|
198
|
+
const exports = bundleRequire('side-effect.js');
|
|
199
|
+
expect(bundleRequire('side-effect.js')).toBe(exports);
|
|
200
|
+
expect(runtime.initModule('side-effect.js')).toBe(exports);
|
|
201
|
+
expect(runtime.loadExports('side-effect.js')).toBe(exports);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('reloads when an invalidated non-component module has no accepting ancestor', async () => {
|
|
205
|
+
const { runtime } = await setupRuntime();
|
|
206
|
+
const bundleRequire = createBundleRequire();
|
|
207
|
+
runtime.registerGraph({ ids: ['route.js', 'entry.js'], localCount: 2, edges: [[], [0]] });
|
|
208
|
+
const entry = vi.fn((_global, module: BundleModule) => {
|
|
209
|
+
runtime.registerModule('entry.js', module);
|
|
210
|
+
runtime.registerModule('route.js', { exports: { Router: {} } });
|
|
211
|
+
});
|
|
212
|
+
bundleRequire.m['entry.js'] = entry;
|
|
213
|
+
bundleRequire('entry.js');
|
|
214
|
+
runtime.createModuleHotContext('route.js').invalidate();
|
|
215
|
+
await vi.waitFor(() => expect(reload).toHaveBeenCalledOnce());
|
|
216
|
+
expect(entry).toHaveBeenCalledOnce();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
146
220
|
describe('client logs', () => {
|
|
147
221
|
const formatter = { format: prettyFormat.format, plugins: prettyFormat.plugins };
|
|
148
222
|
|
|
@@ -527,7 +601,7 @@ describe('HMR runtime', () => {
|
|
|
527
601
|
const evaluate = vi.fn((source: string) => (0, eval)(source));
|
|
528
602
|
globalThis.globalEvalWithSourceUrl = evaluate;
|
|
529
603
|
const { runtime, socket } = await setupRuntime();
|
|
530
|
-
runtime.registerFactory('dep.js',
|
|
604
|
+
runtime.registerFactory('dep.js', (id) => {
|
|
531
605
|
runtime.registerModule(id, { exports: { value: 'before' } });
|
|
532
606
|
});
|
|
533
607
|
|
|
@@ -565,7 +639,7 @@ describe('HMR runtime', () => {
|
|
|
565
639
|
});
|
|
566
640
|
runtime.registerModule('dep.js', { exports: {} });
|
|
567
641
|
runtime.registerModule('entry.js', { exports: { value: 'before' } });
|
|
568
|
-
runtime.registerFactory('entry.js',
|
|
642
|
+
runtime.registerFactory('entry.js', (id) => {
|
|
569
643
|
runtime.registerModule(id, { exports: { value: 'after' } });
|
|
570
644
|
runtime.createModuleHotContext(id).accept();
|
|
571
645
|
});
|
|
@@ -711,9 +785,34 @@ function createPatch(value: string, createHotContext = true) {
|
|
|
711
785
|
edges: [[], [0]],
|
|
712
786
|
dynamicEdges: [[], []]
|
|
713
787
|
});
|
|
714
|
-
__rolldown_runtime__.registerFactory("dep.js",
|
|
788
|
+
__rolldown_runtime__.registerFactory("dep.js", function (id) {
|
|
715
789
|
__rolldown_runtime__.registerModule(id, { exports: { value: "${value}" } });
|
|
716
790
|
${createHotContext ? '__rolldown_runtime__.createModuleHotContext(id);' : ''}
|
|
717
791
|
});
|
|
718
792
|
})(globalThis.__rollipop_runtime__.graphs.get("host").runtime);`;
|
|
719
793
|
}
|
|
794
|
+
|
|
795
|
+
type BundleModule = { exports: any };
|
|
796
|
+
type BundleRequire = {
|
|
797
|
+
(id: string): any;
|
|
798
|
+
m: Record<
|
|
799
|
+
string,
|
|
800
|
+
(global: unknown, module: BundleModule, exports: any, require: BundleRequire) => void
|
|
801
|
+
>;
|
|
802
|
+
c: Record<string, BundleModule>;
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
function createBundleRequire() {
|
|
806
|
+
const require: BundleRequire = Object.assign(
|
|
807
|
+
(id: string) => {
|
|
808
|
+
if (require.c[id] !== undefined) return require.c[id].exports;
|
|
809
|
+
const module = { exports: {} };
|
|
810
|
+
require.c[id] = module;
|
|
811
|
+
require.m[id].call(module.exports, globalThis, module, module.exports, require);
|
|
812
|
+
return module.exports;
|
|
813
|
+
},
|
|
814
|
+
{ m: {} as BundleRequire['m'], c: {} as BundleRequire['c'] },
|
|
815
|
+
);
|
|
816
|
+
(globalThis as any).__rollipop_require__ = require;
|
|
817
|
+
return require;
|
|
818
|
+
}
|
|
@@ -315,7 +315,7 @@ class HMRClient implements HMRClientNativeInterface {
|
|
|
315
315
|
case 'hmr:update-start':
|
|
316
316
|
connection.pendingUpdatesCount++;
|
|
317
317
|
connection.compileErrorMessage = null;
|
|
318
|
-
DevLoadingView.showMessage(
|
|
318
|
+
DevLoadingView.showMessage('Refreshing...', 'refresh');
|
|
319
319
|
break;
|
|
320
320
|
case 'hmr:update':
|
|
321
321
|
this.dismissRedbox();
|
|
@@ -25,6 +25,19 @@ declare global {
|
|
|
25
25
|
// DO NOT EDIT THIS CLASS NAME (`DevRuntime`)
|
|
26
26
|
declare const DevRuntime: typeof DefaultDevRuntime;
|
|
27
27
|
|
|
28
|
+
type BundleModule = { exports: any };
|
|
29
|
+
interface BundleRequire {
|
|
30
|
+
(id: string): any;
|
|
31
|
+
m: Record<
|
|
32
|
+
string,
|
|
33
|
+
(global: unknown, module: BundleModule, exports: any, require: BundleRequire) => void
|
|
34
|
+
>;
|
|
35
|
+
c: Record<string, BundleModule>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Defined in the enclosing Rollipop bundle, separately for each bundle runtime.
|
|
39
|
+
declare const __rollipop_require__: BundleRequire;
|
|
40
|
+
|
|
28
41
|
var BaseDevRuntime = DevRuntime;
|
|
29
42
|
|
|
30
43
|
interface AcceptCallback {
|
|
@@ -194,6 +207,69 @@ class ReactNativeDevRuntime extends BaseDevRuntime {
|
|
|
194
207
|
};
|
|
195
208
|
}
|
|
196
209
|
|
|
210
|
+
hasFactory(moduleId: string) {
|
|
211
|
+
return (
|
|
212
|
+
super.hasFactory(moduleId) ||
|
|
213
|
+
(typeof __rollipop_require__ !== 'undefined' && __rollipop_require__.m[moduleId] != null)
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
isExecuted(moduleId: string) {
|
|
218
|
+
return (
|
|
219
|
+
super.isExecuted(moduleId) ||
|
|
220
|
+
(typeof __rollipop_require__ !== 'undefined' && __rollipop_require__.c[moduleId] != null)
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
loadExports(moduleId: string) {
|
|
225
|
+
if (!super.isExecuted(moduleId) && typeof __rollipop_require__ !== 'undefined') {
|
|
226
|
+
const module = __rollipop_require__.c[moduleId];
|
|
227
|
+
if (module != null) {
|
|
228
|
+
return module.exports;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return super.loadExports(moduleId);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
initModule(moduleId: string) {
|
|
235
|
+
if (this.isExecuted(moduleId)) {
|
|
236
|
+
return this.loadExports(moduleId);
|
|
237
|
+
}
|
|
238
|
+
if (super.hasFactory(moduleId) || !this.hasFactory(moduleId)) {
|
|
239
|
+
return super.initModule(moduleId);
|
|
240
|
+
}
|
|
241
|
+
return __rollipop_require__(moduleId);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
registerFactory(moduleId: string, factory: (id: string) => void, stamp?: number) {
|
|
245
|
+
super.registerFactory(moduleId, factory, stamp);
|
|
246
|
+
if (typeof __rollipop_require__ !== 'undefined') {
|
|
247
|
+
__rollipop_require__.m[moduleId] = (_global, module) => {
|
|
248
|
+
// require() has already inserted an empty cache entry.
|
|
249
|
+
// The base executor bypasses that entry and selects the latest factory accepted by its stamp.
|
|
250
|
+
module.exports = super.initModule(moduleId);
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
registerModule(moduleId: string, module?: BundleModule) {
|
|
256
|
+
module ??=
|
|
257
|
+
typeof __rollipop_require__ !== 'undefined' ? __rollipop_require__.c[moduleId] : undefined;
|
|
258
|
+
module ??= { exports: {} };
|
|
259
|
+
super.registerModule(moduleId, module);
|
|
260
|
+
if (typeof __rollipop_require__ !== 'undefined') {
|
|
261
|
+
// Share the holder itself so CommonJS module.exports reassignments stay live.
|
|
262
|
+
__rollipop_require__.c[moduleId] = module;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
removeModuleCache(moduleId: string) {
|
|
267
|
+
if (typeof __rollipop_require__ !== 'undefined') {
|
|
268
|
+
delete __rollipop_require__.c[moduleId];
|
|
269
|
+
}
|
|
270
|
+
super.removeModuleCache(moduleId);
|
|
271
|
+
}
|
|
272
|
+
|
|
197
273
|
private createHotContext(moduleId: string) {
|
|
198
274
|
let data = this.moduleHotData.get(moduleId);
|
|
199
275
|
if (data == null) {
|