vxrn 1.25.8 → 1.25.9
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/getViteServerConfig.mjs +6 -0
- package/dist/config/getViteServerConfig.mjs.map +1 -1
- package/dist/config/getViteServerConfig.native.js +6 -0
- package/dist/config/getViteServerConfig.native.js.map +1 -1
- package/dist/config/getViteServerConfig.test.mjs +26 -0
- package/dist/config/getViteServerConfig.test.mjs.map +1 -0
- package/dist/config/getViteServerConfig.test.native.js +26 -0
- package/dist/config/getViteServerConfig.test.native.js.map +1 -0
- package/dist/exports/dev.mjs +26 -1
- package/dist/exports/dev.mjs.map +1 -1
- package/dist/exports/dev.native.js +26 -1
- package/dist/exports/dev.native.js.map +1 -1
- package/dist/plugins/reactNativeDevServer.mjs +80 -7
- package/dist/plugins/reactNativeDevServer.mjs.map +1 -1
- package/dist/plugins/reactNativeDevServer.native.js +80 -7
- package/dist/plugins/reactNativeDevServer.native.js.map +1 -1
- package/dist/runtime/native-prelude.mjs +7 -0
- package/dist/runtime/native-prelude.mjs.map +1 -1
- package/dist/runtime/native-prelude.native.js +7 -0
- package/dist/runtime/native-prelude.native.js.map +1 -1
- package/dist/utils/createNativeDevEngine.mjs +302 -197
- package/dist/utils/createNativeDevEngine.mjs.map +1 -1
- package/dist/utils/createNativeDevEngine.native.js +410 -221
- package/dist/utils/createNativeDevEngine.native.js.map +1 -1
- package/dist/utils/createNativeDevEngine.test.mjs +536 -6
- package/dist/utils/createNativeDevEngine.test.mjs.map +1 -1
- package/dist/utils/createNativeDevEngine.test.native.js +559 -6
- package/dist/utils/createNativeDevEngine.test.native.js.map +1 -1
- package/package.json +11 -11
- package/src/config/getViteServerConfig.test.ts +29 -0
- package/src/config/getViteServerConfig.ts +11 -0
- package/src/exports/dev.ts +34 -3
- package/src/plugins/reactNativeDevServer.ts +89 -12
- package/src/runtime/native-prelude.ts +7 -0
- package/src/utils/createNativeDevEngine.test.ts +682 -5
- package/src/utils/createNativeDevEngine.ts +516 -229
- package/types/config/getViteServerConfig.d.ts.map +1 -1
- package/types/config/getViteServerConfig.test.d.ts +2 -0
- package/types/config/getViteServerConfig.test.d.ts.map +1 -0
- package/types/exports/dev.d.ts.map +1 -1
- package/types/plugins/reactNativeDevServer.d.ts +1 -0
- package/types/plugins/reactNativeDevServer.d.ts.map +1 -1
- package/types/runtime/native-prelude.d.ts.map +1 -1
- package/types/utils/createNativeDevEngine.d.ts +40 -2
- package/types/utils/createNativeDevEngine.d.ts.map +1 -1
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from "fs/promises";
|
|
2
3
|
import { tmpdir } from "os";
|
|
3
4
|
import { join } from "path";
|
|
5
|
+
import { runInNewContext } from "vm";
|
|
4
6
|
import { rolldown } from "rolldown";
|
|
5
7
|
import { dev } from "rolldown/experimental";
|
|
6
8
|
import { describe, expect, it } from "vitest";
|
|
7
|
-
import {
|
|
9
|
+
import { getNativePrelude } from "../runtime/native-prelude.native.js";
|
|
10
|
+
import { buildNativeBundle, createNativeDevAssetRegistry, getHermesSWCIncludes, getHmrRuntimeSource, getNativeAssetData, getNativeTransformConfig, hermesCompatSWCPlugin, hmrClientNoopPlugin, nativeAnimatedGuardPlugin, normalizeNativeCommonJSInterop, vxrnCompilerPlugin, wrapNativeBundleModuleScope } from "./createNativeDevEngine.native.js";
|
|
8
11
|
function _instanceof(left, right) {
|
|
9
12
|
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);else return left instanceof right;
|
|
10
13
|
}
|
|
@@ -13,6 +16,58 @@ function _type_of(obj) {
|
|
|
13
16
|
|
|
14
17
|
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
15
18
|
}
|
|
19
|
+
var nativeTransformProbe = `
|
|
20
|
+
export const transformProbe = () => {
|
|
21
|
+
'worklet'
|
|
22
|
+
return 'transformed'
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
async function createWorkletsProject() {
|
|
26
|
+
var throwOnTransform = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : true;
|
|
27
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-transform-failure-"));
|
|
28
|
+
var packageRoot = join(testRoot, "node_modules/react-native-worklets");
|
|
29
|
+
await mkdir(packageRoot, {
|
|
30
|
+
recursive: true
|
|
31
|
+
});
|
|
32
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
33
|
+
name: "react-native-worklets"
|
|
34
|
+
}));
|
|
35
|
+
await writeFile(join(packageRoot, "plugin.js"), throwOnTransform ? `module.exports = () => ({
|
|
36
|
+
visitor: {
|
|
37
|
+
Program() {
|
|
38
|
+
throw new Error('NATIVE_TRANSFORM_NEGATIVE_CONTROL')
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
})` : `module.exports = () => ({ visitor: {} })`);
|
|
42
|
+
await writeFile(join(testRoot, "entry.ts"), nativeTransformProbe);
|
|
43
|
+
return testRoot;
|
|
44
|
+
}
|
|
45
|
+
describe("native prelude", function () {
|
|
46
|
+
it("does not advertise a host event API that cannot remove listeners", function () {
|
|
47
|
+
var context = {
|
|
48
|
+
addEventListener() {}
|
|
49
|
+
};
|
|
50
|
+
runInNewContext(getNativePrelude({
|
|
51
|
+
dev: false,
|
|
52
|
+
platform: "ios"
|
|
53
|
+
}), context);
|
|
54
|
+
expect(Reflect.get(context, "addEventListener")).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
it("preserves a complete host event API", function () {
|
|
57
|
+
var addEventListener = function () {};
|
|
58
|
+
var removeEventListener = function () {};
|
|
59
|
+
var context = {
|
|
60
|
+
addEventListener,
|
|
61
|
+
removeEventListener
|
|
62
|
+
};
|
|
63
|
+
runInNewContext(getNativePrelude({
|
|
64
|
+
dev: false,
|
|
65
|
+
platform: "ios"
|
|
66
|
+
}), context);
|
|
67
|
+
expect(context.addEventListener).toBe(addEventListener);
|
|
68
|
+
expect(context.removeEventListener).toBe(removeEventListener);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
16
71
|
describe("native Rolldown HMR runtime", function () {
|
|
17
72
|
it("registers a Rolldown 1.2 client and applies a self-accepted patch", {
|
|
18
73
|
timeout: 3e4
|
|
@@ -84,7 +139,8 @@ if (import.meta.hot) {
|
|
|
84
139
|
return item.clientId === runtime.clientId && item.update.type === "Patch";
|
|
85
140
|
})) === null || _result_updates_find === void 0 ? void 0 : _result_updates_find.update;
|
|
86
141
|
expect(patch).toBeTruthy();
|
|
87
|
-
|
|
142
|
+
var applyHmrUpdate = Reflect.get(runtime, "applyHmrUpdate");
|
|
143
|
+
expect(Reflect.apply(applyHmrUpdate, runtime, [patch.code, patch.changedIds, patch.seq])).toBe(true);
|
|
88
144
|
expect(globalThis.__vxrnHmrBody).toBe("v2");
|
|
89
145
|
expect(globalThis.__vxrnHmrAccepted).toBe("v2");
|
|
90
146
|
} finally {
|
|
@@ -98,6 +154,141 @@ if (import.meta.hot) {
|
|
|
98
154
|
delete globalThis.__vxrnHmrAccepted;
|
|
99
155
|
}
|
|
100
156
|
});
|
|
157
|
+
it("propagates a non-component update to a React Refresh boundary", {
|
|
158
|
+
timeout: 3e4
|
|
159
|
+
}, async function () {
|
|
160
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-refresh-boundary-"));
|
|
161
|
+
var entry = join(testRoot, "entry.js");
|
|
162
|
+
var leaf = join(testRoot, "leaf.js");
|
|
163
|
+
await writeFile(entry, `
|
|
164
|
+
import { value } from './leaf.js'
|
|
165
|
+
globalThis.__vxrnRefreshBoundaryValue = value
|
|
166
|
+
export function App() {}
|
|
167
|
+
if (import.meta.hot) {
|
|
168
|
+
import.meta.hot.acceptReactRefresh(() => {
|
|
169
|
+
globalThis.__vxrnRefreshBoundaryAccepted = true
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
`);
|
|
173
|
+
await writeFile(leaf, `export const value = 'v1'`);
|
|
174
|
+
var resolveInitialOutput;
|
|
175
|
+
var initialOutput = new Promise(function (resolve) {
|
|
176
|
+
resolveInitialOutput = resolve;
|
|
177
|
+
});
|
|
178
|
+
var resolveHmrUpdate;
|
|
179
|
+
var hmrUpdate = new Promise(function (resolve) {
|
|
180
|
+
resolveHmrUpdate = resolve;
|
|
181
|
+
});
|
|
182
|
+
var registeredClientId;
|
|
183
|
+
var engine = await dev({
|
|
184
|
+
cwd: testRoot,
|
|
185
|
+
input: entry,
|
|
186
|
+
experimental: {
|
|
187
|
+
devMode: {
|
|
188
|
+
implement: getHmrRuntimeSource()
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}, {
|
|
192
|
+
format: "esm"
|
|
193
|
+
}, {
|
|
194
|
+
onOutput(result2) {
|
|
195
|
+
resolveInitialOutput(result2);
|
|
196
|
+
},
|
|
197
|
+
onHmrUpdates(result2) {
|
|
198
|
+
if (!_instanceof(result2, Error) && result2.updates.some(function (item) {
|
|
199
|
+
return item.clientId === registeredClientId && item.update.type === "Patch";
|
|
200
|
+
})) resolveHmrUpdate(result2);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
var previousRefreshRuntime = Reflect.get(globalThis, "__ReactRefresh");
|
|
204
|
+
Reflect.set(globalThis, "__ReactRefresh", {
|
|
205
|
+
isLikelyComponentType(value) {
|
|
206
|
+
return typeof value === "function";
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
try {
|
|
210
|
+
var _result_updates_find;
|
|
211
|
+
await engine.run();
|
|
212
|
+
var initial = await initialOutput;
|
|
213
|
+
if (_instanceof(initial, Error)) throw initial;
|
|
214
|
+
var chunk = initial.output.find(function (item) {
|
|
215
|
+
return item.type === "chunk" && item.isEntry;
|
|
216
|
+
});
|
|
217
|
+
expect(chunk).toBeTruthy();
|
|
218
|
+
Reflect.deleteProperty(globalThis, "__rolldown_runtime__");
|
|
219
|
+
await import(`data:text/javascript;base64,${Buffer.from(chunk.code).toString("base64")}`);
|
|
220
|
+
var runtime = Reflect.get(globalThis, "__rolldown_runtime__");
|
|
221
|
+
registeredClientId = runtime.clientId;
|
|
222
|
+
await engine.registerClient(runtime.clientId);
|
|
223
|
+
await writeFile(leaf, `export const value = 'v2'`);
|
|
224
|
+
var patch = (_result_updates_find = (await Promise.race([hmrUpdate, new Promise(function (_, reject) {
|
|
225
|
+
return setTimeout(function () {
|
|
226
|
+
return reject(/* @__PURE__ */new Error("timed out waiting for HMR patch"));
|
|
227
|
+
}, 1e4);
|
|
228
|
+
})])).updates.find(function (item) {
|
|
229
|
+
return item.clientId === runtime.clientId && item.update.type === "Patch";
|
|
230
|
+
})) === null || _result_updates_find === void 0 ? void 0 : _result_updates_find.update;
|
|
231
|
+
expect(patch).toBeTruthy();
|
|
232
|
+
var applyHmrUpdate = Reflect.get(runtime, "applyHmrUpdate");
|
|
233
|
+
expect(Reflect.apply(applyHmrUpdate, runtime, [patch.code, patch.changedIds, patch.seq])).toBe(true);
|
|
234
|
+
expect(Reflect.get(globalThis, "__vxrnRefreshBoundaryValue")).toBe("v2");
|
|
235
|
+
expect(Reflect.get(globalThis, "__vxrnRefreshBoundaryAccepted")).toBe(true);
|
|
236
|
+
} finally {
|
|
237
|
+
await engine.close();
|
|
238
|
+
await rm(testRoot, {
|
|
239
|
+
recursive: true,
|
|
240
|
+
force: true
|
|
241
|
+
});
|
|
242
|
+
Reflect.deleteProperty(globalThis, "__rolldown_runtime__");
|
|
243
|
+
Reflect.deleteProperty(globalThis, "__vxrnRefreshBoundaryValue");
|
|
244
|
+
Reflect.deleteProperty(globalThis, "__vxrnRefreshBoundaryAccepted");
|
|
245
|
+
if (previousRefreshRuntime === void 0) Reflect.deleteProperty(globalThis, "__ReactRefresh");else Reflect.set(globalThis, "__ReactRefresh", previousRefreshRuntime);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
describe("native production import.meta lowering", function () {
|
|
250
|
+
it("emits a Hermes-compatible bundle for guarded import.meta.env reads", async function () {
|
|
251
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-import-meta-"));
|
|
252
|
+
await writeFile(join(testRoot, "entry.js"), `globalThis.__vxrnNativeImportMetaProbe = typeof import.meta !== 'undefined' && import.meta.env.DEV`);
|
|
253
|
+
try {
|
|
254
|
+
var result = await buildNativeBundle({
|
|
255
|
+
root: testRoot,
|
|
256
|
+
platform: "ios",
|
|
257
|
+
entryFile: "entry.js"
|
|
258
|
+
});
|
|
259
|
+
expect(result.code).not.toContain("typeof import.meta");
|
|
260
|
+
var context = {
|
|
261
|
+
globalThis: {},
|
|
262
|
+
process: {
|
|
263
|
+
env: {}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
runInNewContext(result.code, context);
|
|
267
|
+
expect(Reflect.get(context.globalThis, "__vxrnNativeImportMetaProbe")).toBe(false);
|
|
268
|
+
} finally {
|
|
269
|
+
await rm(testRoot, {
|
|
270
|
+
recursive: true,
|
|
271
|
+
force: true
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
describe("native animated guard transform", function () {
|
|
277
|
+
it("preserves line count and returns a composable source map", async function () {
|
|
278
|
+
var plugin = nativeAnimatedGuardPlugin();
|
|
279
|
+
if (typeof plugin.transform !== "function") throw new Error("native animated guard transform hook is not callable");
|
|
280
|
+
var source = ["function call(methodName) {", " const method = nullthrows(NativeAnimatedModule)[methodName];", " method();", "}"].join("\n");
|
|
281
|
+
var result = await Reflect.apply(plugin.transform, void 0, [source, "/project/node_modules/react-native/src/private/animated/NativeAnimatedHelper.js"]);
|
|
282
|
+
expect(result.code.split("\n")).toHaveLength(source.split("\n").length);
|
|
283
|
+
expect(result.code).toContain("if (typeof method !== 'function') return");
|
|
284
|
+
expect(result.map).toEqual({
|
|
285
|
+
version: 3,
|
|
286
|
+
sources: ["/project/node_modules/react-native/src/private/animated/NativeAnimatedHelper.js"],
|
|
287
|
+
sourcesContent: [source],
|
|
288
|
+
names: [],
|
|
289
|
+
mappings: "AAAA;AACA;AACA;AACA"
|
|
290
|
+
});
|
|
291
|
+
});
|
|
101
292
|
});
|
|
102
293
|
var root = "/tmp/vxrn-native-env-define-test-nonexistent";
|
|
103
294
|
describe("getNativeTransformConfig platform env defines", function () {
|
|
@@ -123,6 +314,21 @@ describe("getNativeTransformConfig platform env defines", function () {
|
|
|
123
314
|
for (var _i1 = 0, _iter1 = [true, false]; _i1 < _iter1.length; _i1++) _loop2(_i1, _iter1);
|
|
124
315
|
};
|
|
125
316
|
for (var _i = 0, _iter = ["ios", "android"]; _i < _iter.length; _i++) _loop(_i, _iter);
|
|
317
|
+
it("inlines EXPO_PUBLIC values supplied by the native build environment", function () {
|
|
318
|
+
var key = "EXPO_PUBLIC_VXRN_NATIVE_ENV_PROBE";
|
|
319
|
+
var previous = process.env[key];
|
|
320
|
+
process.env[key] = "native-env-value";
|
|
321
|
+
try {
|
|
322
|
+
var {
|
|
323
|
+
define
|
|
324
|
+
} = getNativeTransformConfig("ios", false, root);
|
|
325
|
+
expect(define[`process.env.${key}`]).toBe("\"native-env-value\"");
|
|
326
|
+
expect(define[`import.meta.env.${key}`]).toBe("\"native-env-value\"");
|
|
327
|
+
expect(JSON.parse(define["import.meta.env"])[key]).toBe("native-env-value");
|
|
328
|
+
} finally {
|
|
329
|
+
if (previous === void 0) delete process.env[key];else process.env[key] = previous;
|
|
330
|
+
}
|
|
331
|
+
});
|
|
126
332
|
});
|
|
127
333
|
describe("wrapNativeBundleModuleScope", function () {
|
|
128
334
|
var RUNTIME_MARKER = "//#region \\0rolldown/runtime.js";
|
|
@@ -147,15 +353,51 @@ globalThis.__rolldown_runtime__ = {};
|
|
|
147
353
|
});
|
|
148
354
|
});
|
|
149
355
|
describe("getHermesSWCIncludes", function () {
|
|
150
|
-
var CLASS_SET = ["transform-classes", "transform-parameters", "transform-class-properties", "transform-class-static-block", "transform-private-methods", "transform-private-property-in-object"];
|
|
356
|
+
var CLASS_SET = ["transform-classes", "transform-parameters", "transform-block-scoping", "transform-class-properties", "transform-class-static-block", "transform-private-methods", "transform-private-property-in-object"];
|
|
151
357
|
it("always includes the full Hermes class-transform set (dev and prod)", function () {
|
|
152
358
|
expect(getHermesSWCIncludes(true)).toEqual(expect.arrayContaining(CLASS_SET));
|
|
153
359
|
expect(getHermesSWCIncludes(false)).toEqual(expect.arrayContaining(CLASS_SET));
|
|
154
360
|
});
|
|
155
|
-
it("adds transform-async-to-generator
|
|
156
|
-
expect(getHermesSWCIncludes(true)).
|
|
361
|
+
it("adds transform-async-to-generator in development and production", function () {
|
|
362
|
+
expect(getHermesSWCIncludes(true)).toContain("transform-async-to-generator");
|
|
157
363
|
expect(getHermesSWCIncludes(false)).toContain("transform-async-to-generator");
|
|
158
364
|
});
|
|
365
|
+
it("lowers async generators for the Hermes development interpreter", async function () {
|
|
366
|
+
var plugin = hermesCompatSWCPlugin(true);
|
|
367
|
+
if (typeof plugin.transform !== "function") throw new Error("Hermes compatibility transform hook is not callable");
|
|
368
|
+
var result = await Reflect.apply(plugin.transform, void 0, ["export async function* values() { yield await Promise.resolve(1) }", "/project/async-generator.ts"]);
|
|
369
|
+
expect(result.code).not.toContain("async function*");
|
|
370
|
+
expect(result.code).not.toContain("async function *");
|
|
371
|
+
});
|
|
372
|
+
it("preserves per-iteration bindings used by lazy method getters", async function () {
|
|
373
|
+
var plugin = hermesCompatSWCPlugin(true);
|
|
374
|
+
if (typeof plugin.transform !== "function") throw new Error("Hermes compatibility transform hook is not callable");
|
|
375
|
+
var result = await Reflect.apply(plugin.transform, void 0, [`
|
|
376
|
+
const installedGroups = new WeakMap()
|
|
377
|
+
function install(inst, methods) {
|
|
378
|
+
const proto = Object.getPrototypeOf(inst)
|
|
379
|
+
for (const key in methods) {
|
|
380
|
+
const fn = methods[key]
|
|
381
|
+
Object.defineProperty(proto, key, {
|
|
382
|
+
get() { return fn.bind(this) }
|
|
383
|
+
})
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function Schema() {
|
|
387
|
+
install(this, {
|
|
388
|
+
nullish() { return 'nullish' },
|
|
389
|
+
apply(fn) { return fn(this) }
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
globalThis.__vxrnBlockScopeProbe = new Schema().nullish()
|
|
393
|
+
`, "/project/block-scope-loop.ts"]);
|
|
394
|
+
try {
|
|
395
|
+
new Function(result.code)();
|
|
396
|
+
expect(Reflect.get(globalThis, "__vxrnBlockScopeProbe")).toBe("nullish");
|
|
397
|
+
} finally {
|
|
398
|
+
Reflect.deleteProperty(globalThis, "__vxrnBlockScopeProbe");
|
|
399
|
+
}
|
|
400
|
+
});
|
|
159
401
|
it("bundles lowered classes whose constructors use default and rest parameters", async function () {
|
|
160
402
|
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-hermes-parameters-"));
|
|
161
403
|
var entry = join(testRoot, "entry.js");
|
|
@@ -232,9 +474,320 @@ describe("vxrnCompilerPlugin React Refresh registration", function () {
|
|
|
232
474
|
expect(code).toContain("var __vxrnRefreshReg = globalThis.$RefreshReg$");
|
|
233
475
|
expect(code).toContain("__vxrnRefreshReg(");
|
|
234
476
|
expect(code).toContain("\"$RefreshReg$(\"");
|
|
477
|
+
expect(code).toContain("import.meta.hot.acceptReactRefresh(");
|
|
235
478
|
} finally {
|
|
236
479
|
process.env.NODE_ENV = previousNodeEnv;
|
|
237
480
|
}
|
|
238
481
|
});
|
|
239
482
|
});
|
|
483
|
+
describe("native required transform failures", function () {
|
|
484
|
+
it.each([true, false])("rejects valid worklet source when its required compiler transform fails (dev=%s)", async function (dev2) {
|
|
485
|
+
var testRoot = await createWorkletsProject();
|
|
486
|
+
var compiler = await import("@vxrn/compiler");
|
|
487
|
+
compiler.configureVXRNCompilerPlugin({
|
|
488
|
+
enableReanimated: true
|
|
489
|
+
});
|
|
490
|
+
try {
|
|
491
|
+
var plugin = vxrnCompilerPlugin("ios", dev2, testRoot);
|
|
492
|
+
if (typeof plugin.transform !== "function") throw new Error("vxrn compiler transform hook is not callable");
|
|
493
|
+
await expect(Reflect.apply(plugin.transform, void 0, [nativeTransformProbe, join(testRoot, "entry.ts")])).rejects.toThrow("NATIVE_TRANSFORM_NEGATIVE_CONTROL");
|
|
494
|
+
} finally {
|
|
495
|
+
compiler.configureVXRNCompilerPlugin({
|
|
496
|
+
enableReanimated: false
|
|
497
|
+
});
|
|
498
|
+
await rm(testRoot, {
|
|
499
|
+
recursive: true,
|
|
500
|
+
force: true
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
it("returns a dev build error and no output when the required compiler transform fails", async function () {
|
|
505
|
+
var testRoot = await createWorkletsProject();
|
|
506
|
+
var compiler = await import("@vxrn/compiler");
|
|
507
|
+
compiler.configureVXRNCompilerPlugin({
|
|
508
|
+
enableReanimated: true
|
|
509
|
+
});
|
|
510
|
+
var resolveOutput;
|
|
511
|
+
var output = new Promise(function (resolve) {
|
|
512
|
+
resolveOutput = resolve;
|
|
513
|
+
});
|
|
514
|
+
var engine = await dev({
|
|
515
|
+
cwd: testRoot,
|
|
516
|
+
input: join(testRoot, "entry.ts"),
|
|
517
|
+
plugins: [vxrnCompilerPlugin("ios", true, testRoot)]
|
|
518
|
+
}, {
|
|
519
|
+
format: "esm"
|
|
520
|
+
}, {
|
|
521
|
+
onOutput: resolveOutput
|
|
522
|
+
});
|
|
523
|
+
try {
|
|
524
|
+
await engine.run();
|
|
525
|
+
var result = await output;
|
|
526
|
+
expect(result).toBeInstanceOf(Error);
|
|
527
|
+
expect(String(result)).toContain("NATIVE_TRANSFORM_NEGATIVE_CONTROL");
|
|
528
|
+
} finally {
|
|
529
|
+
await engine.close();
|
|
530
|
+
compiler.configureVXRNCompilerPlugin({
|
|
531
|
+
enableReanimated: false
|
|
532
|
+
});
|
|
533
|
+
await rm(testRoot, {
|
|
534
|
+
recursive: true,
|
|
535
|
+
force: true
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
it("emits no production bundle when the required compiler transform fails", async function () {
|
|
540
|
+
var testRoot = await createWorkletsProject();
|
|
541
|
+
var compiler = await import("@vxrn/compiler");
|
|
542
|
+
compiler.configureVXRNCompilerPlugin({
|
|
543
|
+
enableReanimated: true
|
|
544
|
+
});
|
|
545
|
+
try {
|
|
546
|
+
await expect(buildNativeBundle({
|
|
547
|
+
root: testRoot,
|
|
548
|
+
platform: "ios",
|
|
549
|
+
entryFile: "entry.ts"
|
|
550
|
+
})).rejects.toThrow("NATIVE_TRANSFORM_NEGATIVE_CONTROL");
|
|
551
|
+
} finally {
|
|
552
|
+
compiler.configureVXRNCompilerPlugin({
|
|
553
|
+
enableReanimated: false
|
|
554
|
+
});
|
|
555
|
+
await rm(testRoot, {
|
|
556
|
+
recursive: true,
|
|
557
|
+
force: true
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
it("rejects Hermes compatibility transform errors instead of returning source", async function () {
|
|
562
|
+
var plugin = hermesCompatSWCPlugin(true);
|
|
563
|
+
if (typeof plugin.transform !== "function") throw new Error("Hermes compatibility transform hook is not callable");
|
|
564
|
+
await expect(Reflect.apply(plugin.transform, void 0, ["class TransformProbe { value = ; }", "/project/TransformProbe.ts"])).rejects.toBeTruthy();
|
|
565
|
+
});
|
|
566
|
+
it("returns maps for every required production transform", async function () {
|
|
567
|
+
var testRoot = await createWorkletsProject(false);
|
|
568
|
+
var compiler = await import("@vxrn/compiler");
|
|
569
|
+
compiler.configureVXRNCompilerPlugin({
|
|
570
|
+
enableReanimated: true
|
|
571
|
+
});
|
|
572
|
+
try {
|
|
573
|
+
var compilerPlugin = vxrnCompilerPlugin("ios", false, testRoot, true);
|
|
574
|
+
if (typeof compilerPlugin.transform !== "function") throw new Error("vxrn compiler transform hook is not callable");
|
|
575
|
+
expect((await Reflect.apply(compilerPlugin.transform, void 0, [nativeTransformProbe, join(testRoot, "entry.ts")])).map).toBeTruthy();
|
|
576
|
+
var hermesPlugin = hermesCompatSWCPlugin(false, true);
|
|
577
|
+
if (typeof hermesPlugin.transform !== "function") throw new Error("Hermes compatibility transform hook is not callable");
|
|
578
|
+
expect((await Reflect.apply(hermesPlugin.transform, void 0, ["export class TransformProbe { value = 1 }", join(testRoot, "TransformProbe.ts")])).map).toBeTruthy();
|
|
579
|
+
} finally {
|
|
580
|
+
compiler.configureVXRNCompilerPlugin({
|
|
581
|
+
enableReanimated: false
|
|
582
|
+
});
|
|
583
|
+
await rm(testRoot, {
|
|
584
|
+
recursive: true,
|
|
585
|
+
force: true
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
describe("native production assets", function () {
|
|
591
|
+
it("registers scale siblings and keeps monorepo assets inside assetsDest", async function () {
|
|
592
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-assets-"));
|
|
593
|
+
var appRoot = join(testRoot, "workspace/apps/native-app");
|
|
594
|
+
var appAssets = join(appRoot, "assets");
|
|
595
|
+
var packageAssets = join(testRoot, "workspace/node_modules/example/assets");
|
|
596
|
+
var assetsDest = join(testRoot, "output");
|
|
597
|
+
await mkdir(appAssets, {
|
|
598
|
+
recursive: true
|
|
599
|
+
});
|
|
600
|
+
await mkdir(packageAssets, {
|
|
601
|
+
recursive: true
|
|
602
|
+
});
|
|
603
|
+
await writeFile(join(appAssets, "icon.png"), "icon-1x");
|
|
604
|
+
await writeFile(join(appAssets, "icon@2x.png"), "icon-2x");
|
|
605
|
+
await writeFile(join(appAssets, "icon@3x.png"), "icon-3x");
|
|
606
|
+
await writeFile(join(packageAssets, "back.png"), "back-1x");
|
|
607
|
+
await writeFile(join(packageAssets, "back@2x.png"), "back-2x");
|
|
608
|
+
await writeFile(join(appRoot, "entry.js"), `
|
|
609
|
+
import icon from './assets/icon.png'
|
|
610
|
+
import back from '../../node_modules/example/assets/back.png'
|
|
611
|
+
globalThis.__nativeAssetProbe = [icon, back]
|
|
612
|
+
`);
|
|
613
|
+
try {
|
|
614
|
+
var _registry_resolve;
|
|
615
|
+
var assetData = await getNativeAssetData(join(appAssets, "icon.png"), appRoot, "ios");
|
|
616
|
+
expect(assetData.scales).toEqual([1, 2, 3]);
|
|
617
|
+
expect(assetData.files.map(function (file2) {
|
|
618
|
+
return file2.slice(appAssets.length + 1);
|
|
619
|
+
})).toEqual(["icon.png", "icon@2x.png", "icon@3x.png"]);
|
|
620
|
+
expect(assetData.hash).not.toBe("");
|
|
621
|
+
var registry = createNativeDevAssetRegistry();
|
|
622
|
+
registry.register(assetData);
|
|
623
|
+
expect((_registry_resolve = registry.resolve("/assets/assets/icon@2x.png", assetData.hash)) === null || _registry_resolve === void 0 ? void 0 : _registry_resolve.filePath).toBe(join(appAssets, "icon@2x.png"));
|
|
624
|
+
expect(registry.resolve("/assets/assets/icon.png", "stale-content-hash")).toBeUndefined();
|
|
625
|
+
expect(registry.resolve("/assets/../../package.json", assetData.hash)).toBeUndefined();
|
|
626
|
+
expect((await buildNativeBundle({
|
|
627
|
+
root: appRoot,
|
|
628
|
+
platform: "ios",
|
|
629
|
+
entryFile: "entry.js",
|
|
630
|
+
assetsDest
|
|
631
|
+
})).code).toMatch(/"scales":\s*\[\s*1,\s*2,\s*3\s*\]/);
|
|
632
|
+
for (var _i = 0, _iter = ["icon.png", "icon@2x.png", "icon@3x.png"]; _i < _iter.length; _i++) {
|
|
633
|
+
var file = _iter[_i];
|
|
634
|
+
expect(existsSync(join(assetsDest, "assets/assets", file))).toBe(true);
|
|
635
|
+
}
|
|
636
|
+
for (var _i1 = 0, _iter1 = ["back.png", "back@2x.png"]; _i1 < _iter1.length; _i1++) {
|
|
637
|
+
var file1 = _iter1[_i1];
|
|
638
|
+
expect(existsSync(join(assetsDest, "assets/_/_/node_modules/example/assets", file1))).toBe(true);
|
|
639
|
+
}
|
|
640
|
+
expect(existsSync(join(testRoot, "node_modules/example/assets/back.png"))).toBe(false);
|
|
641
|
+
} finally {
|
|
642
|
+
await rm(testRoot, {
|
|
643
|
+
recursive: true,
|
|
644
|
+
force: true
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
describe("native conditional exports", function () {
|
|
650
|
+
it("uses the require condition for CommonJS calls", async function () {
|
|
651
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-conditions-"));
|
|
652
|
+
var packageRoot = join(testRoot, "node_modules/conditional-helper");
|
|
653
|
+
await mkdir(packageRoot, {
|
|
654
|
+
recursive: true
|
|
655
|
+
});
|
|
656
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
657
|
+
name: "conditional-helper",
|
|
658
|
+
exports: {
|
|
659
|
+
".": {
|
|
660
|
+
import: "./esm.js",
|
|
661
|
+
require: "./cjs.cjs"
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
type: "module"
|
|
665
|
+
}));
|
|
666
|
+
await writeFile(join(packageRoot, "esm.js"), `export default function helper() { return 'import' }`);
|
|
667
|
+
await writeFile(join(packageRoot, "cjs.cjs"), `module.exports = function helper() { return 'require' }`);
|
|
668
|
+
await writeFile(join(testRoot, "entry.cjs"), `
|
|
669
|
+
const helper = require('conditional-helper')
|
|
670
|
+
globalThis.__vxrnConditionalExportProbe = helper()
|
|
671
|
+
`);
|
|
672
|
+
try {
|
|
673
|
+
var result = await buildNativeBundle({
|
|
674
|
+
root: testRoot,
|
|
675
|
+
platform: "ios",
|
|
676
|
+
entryFile: "entry.cjs",
|
|
677
|
+
dev: true
|
|
678
|
+
});
|
|
679
|
+
var context = {
|
|
680
|
+
clearTimeout,
|
|
681
|
+
console,
|
|
682
|
+
process: {
|
|
683
|
+
env: {}
|
|
684
|
+
},
|
|
685
|
+
setTimeout
|
|
686
|
+
};
|
|
687
|
+
runInNewContext(result.code, context);
|
|
688
|
+
expect(Reflect.get(context, "__vxrnConditionalExportProbe")).toBe("require");
|
|
689
|
+
} finally {
|
|
690
|
+
await rm(testRoot, {
|
|
691
|
+
recursive: true,
|
|
692
|
+
force: true
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
it("unwraps the default export of Babel CommonJS modules in dev output", {
|
|
697
|
+
timeout: 3e4
|
|
698
|
+
}, async function () {
|
|
699
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-cjs-default-"));
|
|
700
|
+
var packageRoot = join(testRoot, "node_modules/default-export-helper");
|
|
701
|
+
await mkdir(packageRoot, {
|
|
702
|
+
recursive: true
|
|
703
|
+
});
|
|
704
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
705
|
+
name: "default-export-helper",
|
|
706
|
+
main: "./index.js"
|
|
707
|
+
}));
|
|
708
|
+
await writeFile(join(packageRoot, "index.js"), `Object.defineProperty(exports, '__esModule', { value: true }); exports.default = function Component() {}`);
|
|
709
|
+
await writeFile(join(testRoot, "entry.js"), `import Component from 'default-export-helper'; globalThis.__vxrnCjsDefaultProbe = typeof Component`);
|
|
710
|
+
var resolveOutput;
|
|
711
|
+
var output = new Promise(function (resolve) {
|
|
712
|
+
resolveOutput = resolve;
|
|
713
|
+
});
|
|
714
|
+
var engine = await dev({
|
|
715
|
+
cwd: testRoot,
|
|
716
|
+
input: join(testRoot, "entry.js"),
|
|
717
|
+
experimental: {
|
|
718
|
+
devMode: {
|
|
719
|
+
implement: getHmrRuntimeSource()
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}, {
|
|
723
|
+
format: "esm",
|
|
724
|
+
codeSplitting: false,
|
|
725
|
+
strictExecutionOrder: true
|
|
726
|
+
}, {
|
|
727
|
+
onOutput: resolveOutput
|
|
728
|
+
});
|
|
729
|
+
try {
|
|
730
|
+
await engine.run();
|
|
731
|
+
var result = await output;
|
|
732
|
+
if (_instanceof(result, Error)) throw result;
|
|
733
|
+
var chunk = result.output.find(function (item) {
|
|
734
|
+
return item.type === "chunk" && item.isEntry;
|
|
735
|
+
});
|
|
736
|
+
if (!chunk || chunk.type !== "chunk") throw new Error("Rolldown did not emit a native dev entry chunk");
|
|
737
|
+
var nodeModeCode = chunk.code.replace(/(\b__toESM(?:\$\d+)?\(\s*require[\w$]*\(\)\s*)\)/, "$1, 1)");
|
|
738
|
+
expect(nodeModeCode).not.toBe(chunk.code);
|
|
739
|
+
Reflect.deleteProperty(globalThis, "__rolldown_runtime__");
|
|
740
|
+
await import(`data:text/javascript;base64,${Buffer.from(nodeModeCode).toString("base64")}`);
|
|
741
|
+
expect(Reflect.get(globalThis, "__vxrnCjsDefaultProbe")).toBe("object");
|
|
742
|
+
Reflect.deleteProperty(globalThis, "__rolldown_runtime__");
|
|
743
|
+
Reflect.deleteProperty(globalThis, "__vxrnCjsDefaultProbe");
|
|
744
|
+
var normalized = normalizeNativeCommonJSInterop(nodeModeCode);
|
|
745
|
+
await import(`data:text/javascript;base64,${Buffer.from(normalized).toString("base64")}`);
|
|
746
|
+
expect(Reflect.get(globalThis, "__vxrnCjsDefaultProbe")).toBe("function");
|
|
747
|
+
} finally {
|
|
748
|
+
await engine.close();
|
|
749
|
+
Reflect.deleteProperty(globalThis, "__rolldown_runtime__");
|
|
750
|
+
Reflect.deleteProperty(globalThis, "__vxrnCjsDefaultProbe");
|
|
751
|
+
await rm(testRoot, {
|
|
752
|
+
recursive: true,
|
|
753
|
+
force: true
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
it("unwraps the default export of Babel CommonJS modules in production output", async function () {
|
|
758
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-prod-cjs-default-"));
|
|
759
|
+
var packageRoot = join(testRoot, "node_modules/default-export-helper");
|
|
760
|
+
await mkdir(packageRoot, {
|
|
761
|
+
recursive: true
|
|
762
|
+
});
|
|
763
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
764
|
+
name: "default-export-helper",
|
|
765
|
+
main: "./index.js"
|
|
766
|
+
}));
|
|
767
|
+
await writeFile(join(packageRoot, "index.js"), `Object.defineProperty(exports, '__esModule', { value: true }); exports.default = function Component() {}`);
|
|
768
|
+
await writeFile(join(testRoot, "entry.js"), `import Component from 'default-export-helper'; globalThis.__vxrnProdCjsDefaultProbe = typeof Component`);
|
|
769
|
+
try {
|
|
770
|
+
var result = await buildNativeBundle({
|
|
771
|
+
root: testRoot,
|
|
772
|
+
platform: "ios",
|
|
773
|
+
entryFile: "entry.js"
|
|
774
|
+
});
|
|
775
|
+
var context = {
|
|
776
|
+
clearTimeout,
|
|
777
|
+
console,
|
|
778
|
+
process: {
|
|
779
|
+
env: {}
|
|
780
|
+
},
|
|
781
|
+
setTimeout
|
|
782
|
+
};
|
|
783
|
+
runInNewContext(result.code, context);
|
|
784
|
+
expect(Reflect.get(context, "__vxrnProdCjsDefaultProbe")).toBe("function");
|
|
785
|
+
} finally {
|
|
786
|
+
await rm(testRoot, {
|
|
787
|
+
recursive: true,
|
|
788
|
+
force: true
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
});
|
|
240
793
|
//# sourceMappingURL=createNativeDevEngine.test.native.js.map
|