vxrn 1.25.16 → 1.26.0
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/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +2 -0
- package/dist/index.native.js.map +1 -1
- package/dist/patches/builtInDepPatches.mjs +21 -0
- package/dist/patches/builtInDepPatches.mjs.map +1 -1
- package/dist/patches/builtInDepPatches.native.js +21 -0
- package/dist/patches/builtInDepPatches.native.js.map +1 -1
- package/dist/plugins/reactNativeDevServer.mjs +5 -0
- package/dist/plugins/reactNativeDevServer.mjs.map +1 -1
- package/dist/plugins/reactNativeDevServer.native.js +5 -0
- package/dist/plugins/reactNativeDevServer.native.js.map +1 -1
- package/dist/plugins/rnCodegenPlugin.mjs +16 -0
- package/dist/plugins/rnCodegenPlugin.mjs.map +1 -0
- package/dist/plugins/rnCodegenPlugin.native.js +16 -0
- package/dist/plugins/rnCodegenPlugin.native.js.map +1 -0
- package/dist/plugins/rnCodegenPlugin.test.mjs +239 -0
- package/dist/plugins/rnCodegenPlugin.test.mjs.map +1 -0
- package/dist/plugins/rnCodegenPlugin.test.native.js +242 -0
- package/dist/plugins/rnCodegenPlugin.test.native.js.map +1 -0
- package/dist/plugins/workletImportsPlugin.mjs +160 -0
- package/dist/plugins/workletImportsPlugin.mjs.map +1 -0
- package/dist/plugins/workletImportsPlugin.native.js +230 -0
- package/dist/plugins/workletImportsPlugin.native.js.map +1 -0
- package/dist/utils/createNativeDevEngine.mjs +198 -92
- package/dist/utils/createNativeDevEngine.mjs.map +1 -1
- package/dist/utils/createNativeDevEngine.native.js +252 -99
- package/dist/utils/createNativeDevEngine.native.js.map +1 -1
- package/dist/utils/createNativeDevEngine.test.mjs +775 -4
- package/dist/utils/createNativeDevEngine.test.mjs.map +1 -1
- package/dist/utils/createNativeDevEngine.test.native.js +836 -4
- package/dist/utils/createNativeDevEngine.test.native.js.map +1 -1
- package/dist/utils/patches.mjs +12 -5
- package/dist/utils/patches.mjs.map +1 -1
- package/dist/utils/patches.native.js +13 -5
- package/dist/utils/patches.native.js.map +1 -1
- package/dist/utils/patches.test.mjs +28 -0
- package/dist/utils/patches.test.mjs.map +1 -1
- package/dist/utils/patches.test.native.js +47 -0
- package/dist/utils/patches.test.native.js.map +1 -1
- package/dist/utils/scanDepsToOptimize.mjs +5 -1
- package/dist/utils/scanDepsToOptimize.mjs.map +1 -1
- package/dist/utils/scanDepsToOptimize.native.js +5 -1
- package/dist/utils/scanDepsToOptimize.native.js.map +1 -1
- package/package.json +19 -12
- package/src/index.ts +2 -0
- package/src/patches/builtInDepPatches.ts +25 -0
- package/src/plugins/reactNativeDevServer.ts +12 -0
- package/src/plugins/rnCodegenPlugin.test.ts +313 -0
- package/src/plugins/rnCodegenPlugin.ts +20 -0
- package/src/plugins/workletImportsPlugin.ts +226 -0
- package/src/utils/createNativeDevEngine.test.ts +877 -3
- package/src/utils/createNativeDevEngine.ts +259 -107
- package/src/utils/patches.test.ts +33 -0
- package/src/utils/patches.ts +17 -6
- package/src/utils/scanDepsToOptimize.ts +9 -0
- package/types/index.d.ts +2 -0
- package/types/index.d.ts.map +1 -1
- package/types/patches/builtInDepPatches.d.ts.map +1 -1
- package/types/plugins/reactNativeDevServer.d.ts.map +1 -1
- package/types/plugins/rnCodegenPlugin.d.ts +6 -0
- package/types/plugins/rnCodegenPlugin.d.ts.map +1 -0
- package/types/plugins/rnCodegenPlugin.test.d.ts +2 -0
- package/types/plugins/rnCodegenPlugin.test.d.ts.map +1 -0
- package/types/plugins/workletImportsPlugin.d.ts +8 -0
- package/types/plugins/workletImportsPlugin.d.ts.map +1 -0
- package/types/utils/createNativeDevEngine.d.ts +13 -0
- package/types/utils/createNativeDevEngine.d.ts.map +1 -1
- package/types/utils/patches.d.ts.map +1 -1
- package/types/utils/scanDepsToOptimize.d.ts.map +1 -1
|
@@ -2,12 +2,13 @@ import { existsSync } from "fs";
|
|
|
2
2
|
import { mkdir, mkdtemp, rm, writeFile } from "fs/promises";
|
|
3
3
|
import { tmpdir } from "os";
|
|
4
4
|
import { join } from "path";
|
|
5
|
-
import { runInNewContext } from "vm";
|
|
5
|
+
import { createContext, runInContext, runInNewContext } from "vm";
|
|
6
6
|
import { rolldown } from "rolldown";
|
|
7
7
|
import { dev } from "rolldown/experimental";
|
|
8
|
-
import { describe, expect, it } from "vitest";
|
|
8
|
+
import { describe, expect, it, vi } from "vitest";
|
|
9
9
|
import { getNativePrelude } from "../runtime/native-prelude.native.js";
|
|
10
|
-
import {
|
|
10
|
+
import { workletImportsPlugin } from "../plugins/workletImportsPlugin.native.js";
|
|
11
|
+
import { buildNativeBundle, createNativeDevAssetRegistry, createNativeDevEngine, getHermesSWCIncludes, getHmrRuntimeSource, getNativeAssetData, getNativeTransformConfig, hermesCompatSWCPlugin, hmrClientNoopPlugin, nativeAnimatedGuardPlugin, normalizeNativeCommonJSInterop, vxrnCompilerPlugin, wrapNativeBundleModuleScope } from "./createNativeDevEngine.native.js";
|
|
11
12
|
function _instanceof(left, right) {
|
|
12
13
|
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);else return left instanceof right;
|
|
13
14
|
}
|
|
@@ -22,6 +23,265 @@ export const transformProbe = () => {
|
|
|
22
23
|
return 'transformed'
|
|
23
24
|
}
|
|
24
25
|
`;
|
|
26
|
+
describe.each(["rolldown-dev", "rolldown-build", "metro-module", "metro-script"])("native async through %s", function (pipeline) {
|
|
27
|
+
it("preserves defaults, lexical bindings, bigint, rejection, and iterator cleanup", async function () {
|
|
28
|
+
var id = "/project/native-async.js";
|
|
29
|
+
var source = `
|
|
30
|
+
globalThis.result = (function(parentArgument) {
|
|
31
|
+
const events = [];
|
|
32
|
+
const run = async(value = 2n, fail = false) => {
|
|
33
|
+
try {
|
|
34
|
+
const awaited = await (fail ? Promise.reject(new Error('rejected')) : Promise.resolve(3n));
|
|
35
|
+
events.push('after-await');
|
|
36
|
+
return [String(value + awaited), this.base, arguments[0]];
|
|
37
|
+
} catch (error) { return error.message; }
|
|
38
|
+
finally { events.push('finally'); }
|
|
39
|
+
};
|
|
40
|
+
const badDefault = async(value = (() => { throw new Error('default'); })()) => value;
|
|
41
|
+
let synchronousThrow = false;
|
|
42
|
+
let rejectedDefault;
|
|
43
|
+
try { rejectedDefault = badDefault().catch(error => error.message); }
|
|
44
|
+
catch { synchronousThrow = true; }
|
|
45
|
+
async function* values() {
|
|
46
|
+
try { yield 1n; yield 2n; }
|
|
47
|
+
finally { events.push('closed'); }
|
|
48
|
+
}
|
|
49
|
+
const first = async() => { for await (const value of values()) return String(value); };
|
|
50
|
+
return Promise.all([run(), run(4n), run(undefined, true), rejectedDefault, first()])
|
|
51
|
+
.then(values => ({ values, events, synchronousThrow }));
|
|
52
|
+
}).call({ base: 7 }, 'lexical');
|
|
53
|
+
`;
|
|
54
|
+
var output;
|
|
55
|
+
if (pipeline.startsWith("metro")) {
|
|
56
|
+
var {
|
|
57
|
+
transform
|
|
58
|
+
} = await import("@vxrn/vite-plugin-metro/metroNativeWorker");
|
|
59
|
+
var data = (await transform({}, "/project", id, Buffer.from(source), {
|
|
60
|
+
dev: false,
|
|
61
|
+
platform: "ios",
|
|
62
|
+
type: pipeline === "metro-script" ? "script" : "module"
|
|
63
|
+
})).output[0].data;
|
|
64
|
+
var {
|
|
65
|
+
fromRawMappings
|
|
66
|
+
} = await import("metro-source-map");
|
|
67
|
+
output = {
|
|
68
|
+
code: data.code,
|
|
69
|
+
map: fromRawMappings([{
|
|
70
|
+
code: data.code,
|
|
71
|
+
path: id,
|
|
72
|
+
source,
|
|
73
|
+
map: data.map
|
|
74
|
+
}]).toMap()
|
|
75
|
+
};
|
|
76
|
+
} else {
|
|
77
|
+
var plugin = hermesCompatSWCPlugin(pipeline === "rolldown-dev", true);
|
|
78
|
+
output = await Reflect.apply(plugin.transform, void 0, [source, id]);
|
|
79
|
+
}
|
|
80
|
+
var context = {};
|
|
81
|
+
context.__d = function (factory) {
|
|
82
|
+
var module = {
|
|
83
|
+
exports: {}
|
|
84
|
+
};
|
|
85
|
+
factory(context, function (name) {
|
|
86
|
+
throw new Error(`unexpected dependency ${name}`);
|
|
87
|
+
}, function () {}, function () {}, module, module.exports, []);
|
|
88
|
+
};
|
|
89
|
+
runInNewContext(output.code, context);
|
|
90
|
+
var result1 = await context.result;
|
|
91
|
+
expect(result1.values).toEqual([["5", 7, "lexical"], ["7", 7, "lexical"], "rejected", "default", "1"]);
|
|
92
|
+
expect(result1.synchronousThrow).toBe(false);
|
|
93
|
+
expect(result1.events.filter(function (value) {
|
|
94
|
+
return value === "finally";
|
|
95
|
+
})).toHaveLength(3);
|
|
96
|
+
expect(result1.events.filter(function (value) {
|
|
97
|
+
return value === "closed";
|
|
98
|
+
})).toHaveLength(1);
|
|
99
|
+
var {
|
|
100
|
+
originalPositionFor,
|
|
101
|
+
TraceMap
|
|
102
|
+
} = await import("@jridgewell/trace-mapping");
|
|
103
|
+
var lines = output.code.split("\n");
|
|
104
|
+
var line = lines.findIndex(function (value) {
|
|
105
|
+
return value.includes("after-await");
|
|
106
|
+
});
|
|
107
|
+
var position = originalPositionFor(new TraceMap(output.map), {
|
|
108
|
+
line: line + 1,
|
|
109
|
+
column: lines[line].indexOf("events.push")
|
|
110
|
+
});
|
|
111
|
+
expect(position.source).toBe(id);
|
|
112
|
+
expect(position.line).toBe(source.split("\n").findIndex(function (value) {
|
|
113
|
+
return value.includes("after-await");
|
|
114
|
+
}) + 1);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe.each(["shared", "rolldown", "metro"])("React Compiler worklets through %s", function (pipeline) {
|
|
118
|
+
it.each([["block", "useDerivedValue(() => { return value + 8 }, [value])", 18], ["expression", "useDerivedValue(() => value + 8, [value])", 18], ["object", "useDerivedValue(() => ({ lift: value + 8 }), [value])", {
|
|
119
|
+
lift: 18
|
|
120
|
+
}], ["nested", "useDerivedValue(() => runOnUI(() => value + 8), [value])", 18], ["gesture", "useDerivedValue(() => Gesture.Pan().onUpdate(() => value + 8), [value])", 18]])("preserves %s callbacks on the UI runtime and memoizes stable inputs", async function (_name, callback, expected) {
|
|
121
|
+
var compiler = await import("@vxrn/compiler");
|
|
122
|
+
var {
|
|
123
|
+
parseSync
|
|
124
|
+
} = await import("oxc-parser");
|
|
125
|
+
var {
|
|
126
|
+
default: MagicString
|
|
127
|
+
} = await import("magic-string");
|
|
128
|
+
var {
|
|
129
|
+
TraceMap,
|
|
130
|
+
originalPositionFor
|
|
131
|
+
} = await import("@jridgewell/trace-mapping");
|
|
132
|
+
var projectRoot = await createWorkletsProject(false);
|
|
133
|
+
var sourceMaps = process.env.VXRN_ENABLE_SOURCE_MAP;
|
|
134
|
+
process.env.VXRN_ENABLE_SOURCE_MAP = "1";
|
|
135
|
+
compiler.configureVXRNCompilerPlugin({
|
|
136
|
+
enableCompiler: true,
|
|
137
|
+
enableReanimated: true,
|
|
138
|
+
enableNativeWorklets: true
|
|
139
|
+
});
|
|
140
|
+
try {
|
|
141
|
+
var _first___initData;
|
|
142
|
+
var id = join(projectRoot, "useProbe.ts");
|
|
143
|
+
var source = `export function useProbe(value) {
|
|
144
|
+
return ${callback};
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
await writeFile(id, source);
|
|
148
|
+
var result;
|
|
149
|
+
if (pipeline === "shared") {
|
|
150
|
+
var plugin = (await compiler.createVXRNCompilerPlugin()).find(function (p) {
|
|
151
|
+
return p.name === "one:compiler";
|
|
152
|
+
});
|
|
153
|
+
await plugin.configResolved({
|
|
154
|
+
root: projectRoot,
|
|
155
|
+
build: {}
|
|
156
|
+
});
|
|
157
|
+
result = await (plugin.transform.handler || plugin.transform).call({
|
|
158
|
+
environment: {
|
|
159
|
+
name: "ios"
|
|
160
|
+
}
|
|
161
|
+
}, source, id);
|
|
162
|
+
} else if (pipeline === "metro") {
|
|
163
|
+
var {
|
|
164
|
+
transform
|
|
165
|
+
} = await import("@vxrn/vite-plugin-metro/metroNativeWorker");
|
|
166
|
+
var data = (await transform({}, projectRoot, id, Buffer.from(source), {
|
|
167
|
+
dev: false,
|
|
168
|
+
platform: "ios",
|
|
169
|
+
type: "module",
|
|
170
|
+
customTransformOptions: {
|
|
171
|
+
reactCompiler: true,
|
|
172
|
+
worklets: true
|
|
173
|
+
}
|
|
174
|
+
})).output[0].data;
|
|
175
|
+
var msm = await import("metro-source-map");
|
|
176
|
+
result = {
|
|
177
|
+
code: data.code,
|
|
178
|
+
map: msm.fromRawMappings([{
|
|
179
|
+
code: data.code,
|
|
180
|
+
path: id,
|
|
181
|
+
source,
|
|
182
|
+
map: data.map
|
|
183
|
+
}]).toMap()
|
|
184
|
+
};
|
|
185
|
+
} else {
|
|
186
|
+
var plugin1 = vxrnCompilerPlugin("ios", false, projectRoot, true);
|
|
187
|
+
result = await Reflect.apply(plugin1.transform, void 0, [source, id]);
|
|
188
|
+
}
|
|
189
|
+
var runnable = new MagicString(result.code);
|
|
190
|
+
var _iteratorNormalCompletion = true,
|
|
191
|
+
_didIteratorError = false,
|
|
192
|
+
_iteratorError = void 0;
|
|
193
|
+
try {
|
|
194
|
+
for (var _iterator = parseSync("probe.js", result.code).program.body[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
195
|
+
var node = _step.value;
|
|
196
|
+
if (node.type === "ImportDeclaration") runnable.remove(node.start, node.end);
|
|
197
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration) runnable.remove(node.start, node.declaration.start);
|
|
198
|
+
}
|
|
199
|
+
} catch (err) {
|
|
200
|
+
_didIteratorError = true;
|
|
201
|
+
_iteratorError = err;
|
|
202
|
+
} finally {
|
|
203
|
+
try {
|
|
204
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) _iterator.return();
|
|
205
|
+
} finally {
|
|
206
|
+
if (_didIteratorError) throw _iteratorError;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
var cache;
|
|
210
|
+
var cacheCalls = 0;
|
|
211
|
+
var memo = function (size) {
|
|
212
|
+
cacheCalls++;
|
|
213
|
+
return cache !== null && cache !== void 0 ? cache : cache = Array(size).fill(/* @__PURE__ */Symbol.for("react.memo_cache_sentinel"));
|
|
214
|
+
};
|
|
215
|
+
var module = {
|
|
216
|
+
exports: {}
|
|
217
|
+
};
|
|
218
|
+
var probe = new Function("_c", "useDerivedValue", "runOnUI", "Gesture", "__d", "module", `${runnable}
|
|
219
|
+
return ${pipeline === "metro" ? "module.exports.useProbe" : "useProbe"}`)(memo, function (fn2) {
|
|
220
|
+
return fn2;
|
|
221
|
+
}, function (fn2) {
|
|
222
|
+
return fn2;
|
|
223
|
+
}, {
|
|
224
|
+
Pan: function () {
|
|
225
|
+
return {
|
|
226
|
+
onUpdate: function (fn2) {
|
|
227
|
+
return fn2;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}, function (factory) {
|
|
232
|
+
return factory(globalThis, function () {
|
|
233
|
+
return {
|
|
234
|
+
c: memo
|
|
235
|
+
};
|
|
236
|
+
}, function () {}, function () {}, module, module.exports, []);
|
|
237
|
+
}, module);
|
|
238
|
+
var first = probe(10);
|
|
239
|
+
expect((_first___initData = first.__initData) === null || _first___initData === void 0 ? void 0 : _first___initData.code).toBeTypeOf("string");
|
|
240
|
+
for (var _i = 0, _iter = [false, true]; _i < _iter.length; _i++) {
|
|
241
|
+
var onUI = _iter[_i];
|
|
242
|
+
var fn = first;
|
|
243
|
+
var value = void 0;
|
|
244
|
+
for (var depth = 0; depth < 2; depth++) {
|
|
245
|
+
var _fn___initData;
|
|
246
|
+
expect((_fn___initData = fn.__initData) === null || _fn___initData === void 0 ? void 0 : _fn___initData.code).toBeTypeOf("string");
|
|
247
|
+
value = onUI ? new Function("runOnUI", `return (${fn.__initData.code})`)(function (fn2) {
|
|
248
|
+
return fn2;
|
|
249
|
+
}).call({
|
|
250
|
+
__closure: fn.__closure
|
|
251
|
+
}) : fn();
|
|
252
|
+
if (typeof value !== "function") break;
|
|
253
|
+
fn = value;
|
|
254
|
+
}
|
|
255
|
+
expect(value).toEqual(expected);
|
|
256
|
+
}
|
|
257
|
+
expect(probe(10)).toBe(first);
|
|
258
|
+
expect(cacheCalls).toBe(2);
|
|
259
|
+
expect(probe(20)).not.toBe(first);
|
|
260
|
+
var lines = result.code.split("\n");
|
|
261
|
+
var line = lines.findIndex(function (text) {
|
|
262
|
+
return text.includes("function useProbe(");
|
|
263
|
+
});
|
|
264
|
+
expect(line).toBeGreaterThanOrEqual(0);
|
|
265
|
+
var position = originalPositionFor(new TraceMap(result.map), {
|
|
266
|
+
line: line + 1,
|
|
267
|
+
column: lines[line].indexOf("function")
|
|
268
|
+
});
|
|
269
|
+
expect(position.source).toBe(id);
|
|
270
|
+
expect(position.line).toBe(1);
|
|
271
|
+
} finally {
|
|
272
|
+
if (sourceMaps === void 0) delete process.env.VXRN_ENABLE_SOURCE_MAP;else process.env.VXRN_ENABLE_SOURCE_MAP = sourceMaps;
|
|
273
|
+
compiler.configureVXRNCompilerPlugin({
|
|
274
|
+
enableCompiler: false,
|
|
275
|
+
enableReanimated: false,
|
|
276
|
+
enableNativeWorklets: false
|
|
277
|
+
});
|
|
278
|
+
await rm(projectRoot, {
|
|
279
|
+
recursive: true,
|
|
280
|
+
force: true
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
});
|
|
25
285
|
async function createWorkletsProject() {
|
|
26
286
|
var throwOnTransform = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : true;
|
|
27
287
|
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-transform-failure-"));
|
|
@@ -30,7 +290,8 @@ async function createWorkletsProject() {
|
|
|
30
290
|
recursive: true
|
|
31
291
|
});
|
|
32
292
|
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
33
|
-
name: "react-native-worklets"
|
|
293
|
+
name: "react-native-worklets",
|
|
294
|
+
version: "0.10.1"
|
|
34
295
|
}));
|
|
35
296
|
await writeFile(join(packageRoot, "plugin.js"), throwOnTransform ? `module.exports = () => ({
|
|
36
297
|
visitor: {
|
|
@@ -68,7 +329,258 @@ describe("native prelude", function () {
|
|
|
68
329
|
expect(context.removeEventListener).toBe(removeEventListener);
|
|
69
330
|
});
|
|
70
331
|
});
|
|
332
|
+
describe("native pure-function worklet imports", function () {
|
|
333
|
+
it("keeps live module versions isolated across a transitive HMR update", async function () {
|
|
334
|
+
var root2 = await createWorkletsProject(false);
|
|
335
|
+
var packageRoot = join(root2, "node_modules/pure-math");
|
|
336
|
+
await mkdir(packageRoot, {
|
|
337
|
+
recursive: true
|
|
338
|
+
});
|
|
339
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
340
|
+
type: "module",
|
|
341
|
+
exports: "./index.js"
|
|
342
|
+
}));
|
|
343
|
+
var dependency = join(packageRoot, "amount.ios.js");
|
|
344
|
+
await writeFile(dependency, "export const amount = 2");
|
|
345
|
+
await writeFile(join(packageRoot, "amount.android.js"), "export const amount = 99");
|
|
346
|
+
await writeFile(join(packageRoot, "index.js"), `
|
|
347
|
+
import { amount } from './amount'
|
|
348
|
+
const instance = globalThis.moduleInitializations = (globalThis.moduleInitializations || 0) + 1
|
|
349
|
+
export default function calculate(value) { return value + amount }
|
|
350
|
+
export function reads() { return instance }
|
|
351
|
+
`);
|
|
352
|
+
await writeFile(join(root2, "entry.mjs"), `
|
|
353
|
+
import calculate, { reads } from 'pure-math'
|
|
354
|
+
globalThis.calculate = calculate
|
|
355
|
+
globalThis.reads = reads
|
|
356
|
+
if (import.meta.hot) import.meta.hot.accept(() => {})
|
|
357
|
+
`);
|
|
358
|
+
var compiler = await import("@vxrn/compiler");
|
|
359
|
+
compiler.configureVXRNCompilerPlugin({
|
|
360
|
+
enableReanimated: true,
|
|
361
|
+
enableNativeWorklets: true
|
|
362
|
+
});
|
|
363
|
+
var resolveUpdate;
|
|
364
|
+
var updated = new Promise(function (resolve) {
|
|
365
|
+
resolveUpdate = resolve;
|
|
366
|
+
});
|
|
367
|
+
var native = await createNativeDevEngine({
|
|
368
|
+
root: root2,
|
|
369
|
+
port: 0,
|
|
370
|
+
platform: "ios",
|
|
371
|
+
plugins: [workletImportsPlugin({
|
|
372
|
+
"pure-math": ["default", "reads"]
|
|
373
|
+
}), {
|
|
374
|
+
name: "worklet-import-fixture",
|
|
375
|
+
transform(_code, id) {
|
|
376
|
+
if (id.endsWith("/__virtual-native-entry.tsx")) return `import './entry.mjs'`;
|
|
377
|
+
}
|
|
378
|
+
}],
|
|
379
|
+
onHmrUpdate: resolveUpdate
|
|
380
|
+
});
|
|
381
|
+
try {
|
|
382
|
+
var initial = await native.getBundle();
|
|
383
|
+
var rn = {
|
|
384
|
+
console,
|
|
385
|
+
setTimeout,
|
|
386
|
+
clearTimeout
|
|
387
|
+
};
|
|
388
|
+
runInNewContext(initial.code, rn);
|
|
389
|
+
expect(rn.calculate(10)).toBe(12);
|
|
390
|
+
expect(rn.reads()).toBe(1);
|
|
391
|
+
var ui = createContext({});
|
|
392
|
+
var compiled = /* @__PURE__ */new Map();
|
|
393
|
+
var reconstruct = function (worklet) {
|
|
394
|
+
if (!worklet.__initData || !worklet.__workletHash) throw new Error("remote function");
|
|
395
|
+
var fn = compiled.get(worklet.__workletHash);
|
|
396
|
+
if (!fn) {
|
|
397
|
+
fn = runInContext(`(${worklet.__initData.code})`, ui);
|
|
398
|
+
compiled.set(worklet.__workletHash, fn);
|
|
399
|
+
}
|
|
400
|
+
var closure = Object.fromEntries(Object.entries(worklet.__closure).map(function (param) {
|
|
401
|
+
var [name, value] = param;
|
|
402
|
+
return [name, typeof value === "function" ? reconstruct(value) : value];
|
|
403
|
+
}));
|
|
404
|
+
return fn.bind({
|
|
405
|
+
__closure: closure
|
|
406
|
+
});
|
|
407
|
+
};
|
|
408
|
+
expect(function () {
|
|
409
|
+
return reconstruct(function (value) {
|
|
410
|
+
return value + 2;
|
|
411
|
+
});
|
|
412
|
+
}).toThrow("remote function");
|
|
413
|
+
var old = reconstruct(rn.calculate);
|
|
414
|
+
var oldReads = reconstruct(rn.reads);
|
|
415
|
+
expect(old(10)).toBe(12);
|
|
416
|
+
expect(reconstruct(rn.calculate)(11)).toBe(13);
|
|
417
|
+
expect(oldReads()).toBe(1);
|
|
418
|
+
expect(rn.reads()).toBe(1);
|
|
419
|
+
var runtime = rn.__rolldown_runtime__;
|
|
420
|
+
await native.engine.registerClient(runtime.clientId);
|
|
421
|
+
await writeFile(dependency, "export const amount = 3");
|
|
422
|
+
var update = await updated;
|
|
423
|
+
expect(update.type).toBe("hmr:update");
|
|
424
|
+
expect(runtime.applyHmrUpdate(update.code, update.changedIds, update.seq)).toBe(true);
|
|
425
|
+
expect(rn.calculate(10)).toBe(13);
|
|
426
|
+
var next = reconstruct(rn.calculate);
|
|
427
|
+
expect([old(10), next(10), old(10), next(10)]).toEqual([12, 13, 12, 13]);
|
|
428
|
+
var nextReads = reconstruct(rn.reads);
|
|
429
|
+
expect([oldReads(), nextReads(), oldReads(), nextReads()]).toEqual([1, 2, 1, 2]);
|
|
430
|
+
expect(ui.moduleInitializations).toBe(2);
|
|
431
|
+
expect(rn.reads()).toBe(2);
|
|
432
|
+
await writeFile(join(root2, "production.mjs"), `import calculate, { reads } from 'pure-math'; globalThis.calculate = calculate; globalThis.reads = reads`);
|
|
433
|
+
var production = await buildNativeBundle({
|
|
434
|
+
root: root2,
|
|
435
|
+
platform: "android",
|
|
436
|
+
entryFile: "production.mjs",
|
|
437
|
+
plugins: [workletImportsPlugin({
|
|
438
|
+
"pure-math": ["default", "reads"]
|
|
439
|
+
})]
|
|
440
|
+
});
|
|
441
|
+
var productionRN = {
|
|
442
|
+
console
|
|
443
|
+
};
|
|
444
|
+
runInNewContext(production.code, productionRN);
|
|
445
|
+
expect(productionRN.calculate(10)).toBe(109);
|
|
446
|
+
expect(reconstruct(productionRN.calculate)(10)).toBe(109);
|
|
447
|
+
expect(reconstruct(productionRN.reads)()).toBe(3);
|
|
448
|
+
expect(productionRN.reads()).toBe(1);
|
|
449
|
+
var sharedPlugin = workletImportsPlugin({
|
|
450
|
+
"pure-math": ["default", "reads"]
|
|
451
|
+
});
|
|
452
|
+
expect(await Promise.all(["ios", "android"].map(async function (platform) {
|
|
453
|
+
var output = await buildNativeBundle({
|
|
454
|
+
root: root2,
|
|
455
|
+
platform,
|
|
456
|
+
entryFile: "production.mjs",
|
|
457
|
+
plugins: [sharedPlugin]
|
|
458
|
+
});
|
|
459
|
+
var context = {
|
|
460
|
+
console
|
|
461
|
+
};
|
|
462
|
+
runInNewContext(output.code, context);
|
|
463
|
+
return context.calculate(10);
|
|
464
|
+
}))).toEqual([13, 109]);
|
|
465
|
+
} finally {
|
|
466
|
+
await native.close();
|
|
467
|
+
compiler.configureVXRNCompilerPlugin({
|
|
468
|
+
enableReanimated: false,
|
|
469
|
+
enableNativeWorklets: false
|
|
470
|
+
});
|
|
471
|
+
await rm(root2, {
|
|
472
|
+
recursive: true,
|
|
473
|
+
force: true
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
it.each([["unselected", "export default function value() { return 1 }; export const other = 2", `import { other } from 'pure-math'; globalThis.value = other`, /unselected export other/], ["missing", "export const other = 2", `import value from 'pure-math'; globalThis.value = value`, /default.*not exported|MISSING_EXPORT/], ["builtin", `import fs from 'node:fs'; export default function value() { return fs.readFileSync('x') }`, `import value from 'pure-math'; globalThis.value = value`, /runtime dependency node:fs/], ["global", "export default function value() { return process.pid }", `import value from 'pure-math'; globalThis.value = value`, /unsupported runtime globals: process/], ["dynamic", `export default function value() { return import('./other.js') }`, `import value from 'pure-math'; globalThis.value = value`, /dynamic imports are unsupported/]])("rejects %s through the native engine", async function (_name, source, entry, expected) {
|
|
478
|
+
var root2 = await createWorkletsProject(false);
|
|
479
|
+
var packageRoot = join(root2, "node_modules/pure-math");
|
|
480
|
+
await mkdir(packageRoot, {
|
|
481
|
+
recursive: true
|
|
482
|
+
});
|
|
483
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
484
|
+
type: "module",
|
|
485
|
+
exports: "./index.js"
|
|
486
|
+
}));
|
|
487
|
+
await writeFile(join(packageRoot, "index.js"), source);
|
|
488
|
+
await writeFile(join(root2, "entry.mjs"), entry);
|
|
489
|
+
var compiler = await import("@vxrn/compiler");
|
|
490
|
+
compiler.configureVXRNCompilerPlugin({
|
|
491
|
+
enableReanimated: true,
|
|
492
|
+
enableNativeWorklets: true
|
|
493
|
+
});
|
|
494
|
+
var native = await createNativeDevEngine({
|
|
495
|
+
root: root2,
|
|
496
|
+
port: 0,
|
|
497
|
+
platform: "ios",
|
|
498
|
+
plugins: [workletImportsPlugin({
|
|
499
|
+
"pure-math": ["default"]
|
|
500
|
+
}), {
|
|
501
|
+
name: "worklet-import-negative-fixture",
|
|
502
|
+
transform(_code, id) {
|
|
503
|
+
if (id.endsWith("/__virtual-native-entry.tsx")) return `import './entry.mjs'`;
|
|
504
|
+
}
|
|
505
|
+
}]
|
|
506
|
+
});
|
|
507
|
+
try {
|
|
508
|
+
await expect(native.getBundle()).rejects.toThrow(expected);
|
|
509
|
+
} finally {
|
|
510
|
+
await native.close();
|
|
511
|
+
compiler.configureVXRNCompilerPlugin({
|
|
512
|
+
enableReanimated: false,
|
|
513
|
+
enableNativeWorklets: false
|
|
514
|
+
});
|
|
515
|
+
await rm(root2, {
|
|
516
|
+
recursive: true,
|
|
517
|
+
force: true
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
});
|
|
71
522
|
describe("native Rolldown HMR runtime", function () {
|
|
523
|
+
it.each([true, false])("keeps CommonJS default components callable through the native HMR wire path (Babel=%s)", async function (babel) {
|
|
524
|
+
var root2 = await mkdtemp(join(tmpdir(), "vxrn-native-hmr-interop-"));
|
|
525
|
+
var entry = join(root2, "entry.mjs");
|
|
526
|
+
var packageRoot = join(root2, "node_modules/component");
|
|
527
|
+
await mkdir(packageRoot, {
|
|
528
|
+
recursive: true
|
|
529
|
+
});
|
|
530
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
531
|
+
main: "./component(view).js"
|
|
532
|
+
}));
|
|
533
|
+
await writeFile(join(packageRoot, "component(view).js"), babel ? `Object.defineProperty(exports, '__esModule', { value: true }); exports.default = function Component() { return 42 }` : `module.exports = function Component() { return 42 }`);
|
|
534
|
+
var source = function (version) {
|
|
535
|
+
return `
|
|
536
|
+
import Component from 'component'
|
|
537
|
+
globalThis.renderComponent = Component
|
|
538
|
+
export const version = ${version}
|
|
539
|
+
if (import.meta.hot) import.meta.hot.accept(() => {})
|
|
540
|
+
`;
|
|
541
|
+
};
|
|
542
|
+
await writeFile(entry, source(1));
|
|
543
|
+
var resolveUpdate;
|
|
544
|
+
var updateReceived = new Promise(function (resolve) {
|
|
545
|
+
resolveUpdate = resolve;
|
|
546
|
+
});
|
|
547
|
+
var native = await createNativeDevEngine({
|
|
548
|
+
root: root2,
|
|
549
|
+
port: 0,
|
|
550
|
+
platform: "ios",
|
|
551
|
+
plugins: [{
|
|
552
|
+
name: "native-hmr-fixture-entry",
|
|
553
|
+
transform(_code, id) {
|
|
554
|
+
if (id.endsWith("/__virtual-native-entry.tsx")) return `import './entry.mjs'`;
|
|
555
|
+
}
|
|
556
|
+
}],
|
|
557
|
+
onHmrUpdate: resolveUpdate
|
|
558
|
+
});
|
|
559
|
+
try {
|
|
560
|
+
var initial = await native.getBundle();
|
|
561
|
+
var context = {
|
|
562
|
+
console,
|
|
563
|
+
setTimeout,
|
|
564
|
+
clearTimeout
|
|
565
|
+
};
|
|
566
|
+
runInNewContext(initial.code, context);
|
|
567
|
+
expect(context.renderComponent()).toBe(42);
|
|
568
|
+
var runtime = context.__rolldown_runtime__;
|
|
569
|
+
await native.engine.registerClient(runtime.clientId);
|
|
570
|
+
await writeFile(entry, source(2));
|
|
571
|
+
var update = await updateReceived;
|
|
572
|
+
expect(update.type).toBe("hmr:update");
|
|
573
|
+
expect(update.clientId).toBe(runtime.clientId);
|
|
574
|
+
expect(runtime.applyHmrUpdate(update.code, update.changedIds, update.seq)).toBe(true);
|
|
575
|
+
expect(context.renderComponent()).toBe(42);
|
|
576
|
+
} finally {
|
|
577
|
+
await native.close();
|
|
578
|
+
await rm(root2, {
|
|
579
|
+
recursive: true,
|
|
580
|
+
force: true
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
});
|
|
72
584
|
it("registers a Rolldown 1.2 client and applies a self-accepted patch", {
|
|
73
585
|
timeout: 3e4
|
|
74
586
|
}, async function () {
|
|
@@ -390,6 +902,27 @@ describe("getHermesSWCIncludes", function () {
|
|
|
390
902
|
expect(result.code).not.toContain("async function*");
|
|
391
903
|
expect(result.code).not.toContain("async function *");
|
|
392
904
|
});
|
|
905
|
+
it("downlevels private fields, public class fields, and static blocks for Hermes", async function () {
|
|
906
|
+
var plugin = hermesCompatSWCPlugin(true);
|
|
907
|
+
if (typeof plugin.transform !== "function") throw new Error("Hermes compatibility transform hook is not callable");
|
|
908
|
+
var result = await Reflect.apply(plugin.transform, void 0, [`
|
|
909
|
+
class TransformProbe {
|
|
910
|
+
#privateField = 1
|
|
911
|
+
publicField = 2
|
|
912
|
+
static {
|
|
913
|
+
TransformProbe.initialized = true
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
getSecret() {
|
|
917
|
+
return this.#privateField
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
`, "/project/TransformProbe.ts"]);
|
|
921
|
+
expect(result.code).not.toContain("#privateField");
|
|
922
|
+
expect(result.code).not.toMatch(/^\s*publicField\s*=/m);
|
|
923
|
+
expect(result.code).not.toContain("static {");
|
|
924
|
+
expect(result.code).toContain("this.publicField = 2");
|
|
925
|
+
});
|
|
393
926
|
it("preserves per-iteration bindings used by lazy method getters", async function () {
|
|
394
927
|
var plugin = hermesCompatSWCPlugin(true);
|
|
395
928
|
if (typeof plugin.transform !== "function") throw new Error("Hermes compatibility transform hook is not callable");
|
|
@@ -505,6 +1038,7 @@ describe("native required transform failures", function () {
|
|
|
505
1038
|
it.each([true, false])("rejects valid worklet source when its required compiler transform fails (dev=%s)", async function (dev2) {
|
|
506
1039
|
var testRoot = await createWorkletsProject();
|
|
507
1040
|
var compiler = await import("@vxrn/compiler");
|
|
1041
|
+
var spy = vi.spyOn(compiler, "transformWorklets").mockRejectedValue(/* @__PURE__ */new Error("NATIVE_TRANSFORM_NEGATIVE_CONTROL"));
|
|
508
1042
|
compiler.configureVXRNCompilerPlugin({
|
|
509
1043
|
enableReanimated: true
|
|
510
1044
|
});
|
|
@@ -513,6 +1047,7 @@ describe("native required transform failures", function () {
|
|
|
513
1047
|
if (typeof plugin.transform !== "function") throw new Error("vxrn compiler transform hook is not callable");
|
|
514
1048
|
await expect(Reflect.apply(plugin.transform, void 0, [nativeTransformProbe, join(testRoot, "entry.ts")])).rejects.toThrow("NATIVE_TRANSFORM_NEGATIVE_CONTROL");
|
|
515
1049
|
} finally {
|
|
1050
|
+
spy.mockRestore();
|
|
516
1051
|
compiler.configureVXRNCompilerPlugin({
|
|
517
1052
|
enableReanimated: false
|
|
518
1053
|
});
|
|
@@ -525,6 +1060,7 @@ describe("native required transform failures", function () {
|
|
|
525
1060
|
it("returns a dev build error and no output when the required compiler transform fails", async function () {
|
|
526
1061
|
var testRoot = await createWorkletsProject();
|
|
527
1062
|
var compiler = await import("@vxrn/compiler");
|
|
1063
|
+
var spy = vi.spyOn(compiler, "transformWorklets").mockRejectedValue(/* @__PURE__ */new Error("NATIVE_TRANSFORM_NEGATIVE_CONTROL"));
|
|
528
1064
|
compiler.configureVXRNCompilerPlugin({
|
|
529
1065
|
enableReanimated: true
|
|
530
1066
|
});
|
|
@@ -547,6 +1083,7 @@ describe("native required transform failures", function () {
|
|
|
547
1083
|
expect(result).toBeInstanceOf(Error);
|
|
548
1084
|
expect(String(result)).toContain("NATIVE_TRANSFORM_NEGATIVE_CONTROL");
|
|
549
1085
|
} finally {
|
|
1086
|
+
spy.mockRestore();
|
|
550
1087
|
await engine.close();
|
|
551
1088
|
compiler.configureVXRNCompilerPlugin({
|
|
552
1089
|
enableReanimated: false
|
|
@@ -560,6 +1097,7 @@ describe("native required transform failures", function () {
|
|
|
560
1097
|
it("emits no production bundle when the required compiler transform fails", async function () {
|
|
561
1098
|
var testRoot = await createWorkletsProject();
|
|
562
1099
|
var compiler = await import("@vxrn/compiler");
|
|
1100
|
+
var spy = vi.spyOn(compiler, "transformWorklets").mockRejectedValue(/* @__PURE__ */new Error("NATIVE_TRANSFORM_NEGATIVE_CONTROL"));
|
|
563
1101
|
compiler.configureVXRNCompilerPlugin({
|
|
564
1102
|
enableReanimated: true
|
|
565
1103
|
});
|
|
@@ -570,6 +1108,7 @@ describe("native required transform failures", function () {
|
|
|
570
1108
|
entryFile: "entry.ts"
|
|
571
1109
|
})).rejects.toThrow("NATIVE_TRANSFORM_NEGATIVE_CONTROL");
|
|
572
1110
|
} finally {
|
|
1111
|
+
spy.mockRestore();
|
|
573
1112
|
compiler.configureVXRNCompilerPlugin({
|
|
574
1113
|
enableReanimated: false
|
|
575
1114
|
});
|
|
@@ -607,6 +1146,238 @@ describe("native required transform failures", function () {
|
|
|
607
1146
|
});
|
|
608
1147
|
}
|
|
609
1148
|
});
|
|
1149
|
+
it("composes source maps across React Compiler, Fast Refresh, and module wrapper back to original source lines", async function () {
|
|
1150
|
+
var {
|
|
1151
|
+
TraceMap,
|
|
1152
|
+
originalPositionFor
|
|
1153
|
+
} = await import("@jridgewell/trace-mapping");
|
|
1154
|
+
var compiler = await import("@vxrn/compiler");
|
|
1155
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1156
|
+
enableCompiler: true
|
|
1157
|
+
});
|
|
1158
|
+
try {
|
|
1159
|
+
var plugin = vxrnCompilerPlugin("ios", true, "/project", true);
|
|
1160
|
+
if (typeof plugin.transform !== "function") throw new Error("transform hook not callable");
|
|
1161
|
+
var inputCode = `import { useState } from 'react'
|
|
1162
|
+
|
|
1163
|
+
export function Counter() {
|
|
1164
|
+
const [count, setCount] = useState(0)
|
|
1165
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
|
1166
|
+
}
|
|
1167
|
+
`;
|
|
1168
|
+
var id = "/project/Counter.tsx";
|
|
1169
|
+
var result = await Reflect.apply(plugin.transform, void 0, [inputCode, id]);
|
|
1170
|
+
expect(result).toBeDefined();
|
|
1171
|
+
expect(result.map).toBeDefined();
|
|
1172
|
+
var tracer = new TraceMap(result.map);
|
|
1173
|
+
var counterLineIndex = result.code.split("\n").findIndex(function (l) {
|
|
1174
|
+
return l.includes("function Counter");
|
|
1175
|
+
});
|
|
1176
|
+
expect(counterLineIndex).toBeGreaterThan(0);
|
|
1177
|
+
var pos = originalPositionFor(tracer, {
|
|
1178
|
+
line: counterLineIndex + 1,
|
|
1179
|
+
column: 16
|
|
1180
|
+
});
|
|
1181
|
+
expect(pos.source).toBe(id);
|
|
1182
|
+
expect(pos.line).toBe(3);
|
|
1183
|
+
} finally {
|
|
1184
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1185
|
+
enableCompiler: false
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
});
|
|
1189
|
+
it("composes source maps accurately across mixed path (React Compiler + Babel + Fast Refresh + module wrapper)", async function () {
|
|
1190
|
+
var {
|
|
1191
|
+
TraceMap,
|
|
1192
|
+
originalPositionFor
|
|
1193
|
+
} = await import("@jridgewell/trace-mapping");
|
|
1194
|
+
var compiler = await import("@vxrn/compiler");
|
|
1195
|
+
var origEnv = process.env.VXRN_USE_BABEL_FOR_GENERATORS;
|
|
1196
|
+
process.env.VXRN_USE_BABEL_FOR_GENERATORS = "1";
|
|
1197
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1198
|
+
enableCompiler: true,
|
|
1199
|
+
enableReanimated: false
|
|
1200
|
+
});
|
|
1201
|
+
try {
|
|
1202
|
+
var plugin = vxrnCompilerPlugin("ios", true, "/project", true);
|
|
1203
|
+
if (typeof plugin.transform !== "function") throw new Error("transform hook not callable");
|
|
1204
|
+
var inputCode = `export function Counter() { return <View />; }
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
export async function* probe() { throw new Error("MARKER"); }
|
|
1213
|
+
`;
|
|
1214
|
+
var id = "/project/Counter.tsx";
|
|
1215
|
+
var result = await Reflect.apply(plugin.transform, void 0, [inputCode, id]);
|
|
1216
|
+
expect(result).toBeDefined();
|
|
1217
|
+
expect(result.map).toBeDefined();
|
|
1218
|
+
expect(result.code.includes("_wrapAsyncGenerator") || result.code.includes("regeneratorRuntime")).toBe(true);
|
|
1219
|
+
var tracer = new TraceMap(result.map);
|
|
1220
|
+
var lines = result.code.split("\n");
|
|
1221
|
+
var markerLineIndex = lines.findIndex(function (l) {
|
|
1222
|
+
return l.includes("MARKER");
|
|
1223
|
+
});
|
|
1224
|
+
expect(markerLineIndex).toBeGreaterThan(0);
|
|
1225
|
+
var markerCol = lines[markerLineIndex].indexOf("throw");
|
|
1226
|
+
var pos = originalPositionFor(tracer, {
|
|
1227
|
+
line: markerLineIndex + 1,
|
|
1228
|
+
column: markerCol
|
|
1229
|
+
});
|
|
1230
|
+
expect(pos.source).toBe(id);
|
|
1231
|
+
expect(pos.line).toBe(9);
|
|
1232
|
+
expect(pos.column).toBe(33);
|
|
1233
|
+
var compilerOut = await compiler.transformOxcReactCompiler(id, inputCode, "19", true);
|
|
1234
|
+
var remapping = (await import("@jridgewell/remapping")).default;
|
|
1235
|
+
var badPos = originalPositionFor(new TraceMap(remapping([result.map, compilerOut.map], function () {
|
|
1236
|
+
return null;
|
|
1237
|
+
})), {
|
|
1238
|
+
line: markerLineIndex + 1,
|
|
1239
|
+
column: markerCol
|
|
1240
|
+
});
|
|
1241
|
+
expect(badPos.source).toBeNull();
|
|
1242
|
+
expect(badPos.line).toBeNull();
|
|
1243
|
+
} finally {
|
|
1244
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1245
|
+
enableCompiler: false
|
|
1246
|
+
});
|
|
1247
|
+
if (origEnv !== void 0) process.env.VXRN_USE_BABEL_FOR_GENERATORS = origEnv;else delete process.env.VXRN_USE_BABEL_FOR_GENERATORS;
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
it("transforms worklets via native Rust/Wasm SWC with zero Babel execution and accurate sourcemaps", async function () {
|
|
1251
|
+
var {
|
|
1252
|
+
TraceMap,
|
|
1253
|
+
originalPositionFor
|
|
1254
|
+
} = await import("@jridgewell/trace-mapping");
|
|
1255
|
+
var compiler = await import("@vxrn/compiler");
|
|
1256
|
+
var {
|
|
1257
|
+
vi: vi2
|
|
1258
|
+
} = await import("vitest");
|
|
1259
|
+
var babelSpy = vi2.spyOn(compiler, "transformBabel");
|
|
1260
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1261
|
+
enableReanimated: true,
|
|
1262
|
+
enableNativeWorklets: true,
|
|
1263
|
+
enableCompiler: false
|
|
1264
|
+
});
|
|
1265
|
+
try {
|
|
1266
|
+
var projectRoot = process.cwd();
|
|
1267
|
+
var plugin = vxrnCompilerPlugin("ios", true, projectRoot, true);
|
|
1268
|
+
if (typeof plugin.transform !== "function") throw new Error("transform hook not callable");
|
|
1269
|
+
var inputCode = `import { useAnimatedStyle } from 'react-native-reanimated'
|
|
1270
|
+
|
|
1271
|
+
export function Box() {
|
|
1272
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
1273
|
+
return { opacity: 1 }
|
|
1274
|
+
})
|
|
1275
|
+
return <div style={animatedStyle} />
|
|
1276
|
+
}
|
|
1277
|
+
`;
|
|
1278
|
+
var id = join(projectRoot, "Box.tsx");
|
|
1279
|
+
var result = await Reflect.apply(plugin.transform, void 0, [inputCode, id]);
|
|
1280
|
+
expect(result).toBeDefined();
|
|
1281
|
+
expect(result.code).toContain("__workletHash");
|
|
1282
|
+
expect(result.code).toContain("__closure");
|
|
1283
|
+
expect(babelSpy).not.toHaveBeenCalled();
|
|
1284
|
+
expect(result.map).toBeDefined();
|
|
1285
|
+
var tracer = new TraceMap(result.map);
|
|
1286
|
+
var boxLineIndex = result.code.split("\n").findIndex(function (l) {
|
|
1287
|
+
return l.includes("export function Box");
|
|
1288
|
+
});
|
|
1289
|
+
expect(boxLineIndex).toBeGreaterThan(0);
|
|
1290
|
+
var pos = originalPositionFor(tracer, {
|
|
1291
|
+
line: boxLineIndex + 1,
|
|
1292
|
+
column: 16
|
|
1293
|
+
});
|
|
1294
|
+
expect(pos.source).toBe(id);
|
|
1295
|
+
expect(pos.line).toBe(3);
|
|
1296
|
+
} finally {
|
|
1297
|
+
babelSpy.mockRestore();
|
|
1298
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1299
|
+
enableReanimated: false,
|
|
1300
|
+
enableNativeWorklets: false
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1304
|
+
it("retains the existing Babel backend by default when enableNativeWorklets is false for auto-detected Reanimated and ordinary configured worklets plugin", async function () {
|
|
1305
|
+
var compiler = await import("@vxrn/compiler");
|
|
1306
|
+
var {
|
|
1307
|
+
vi: vi2
|
|
1308
|
+
} = await import("vitest");
|
|
1309
|
+
var babelSpy = vi2.spyOn(compiler, "transformBabel").mockResolvedValue({
|
|
1310
|
+
code: "/* babel transformed */"
|
|
1311
|
+
});
|
|
1312
|
+
var workletSpy = vi2.spyOn(compiler, "transformWorklets");
|
|
1313
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1314
|
+
enableReanimated: true,
|
|
1315
|
+
enableNativeWorklets: false
|
|
1316
|
+
});
|
|
1317
|
+
var getBabelOptionsSpy = vi2.spyOn(compiler, "getBabelOptions").mockReturnValue({
|
|
1318
|
+
plugins: ["react-native-reanimated/plugin"]
|
|
1319
|
+
});
|
|
1320
|
+
try {
|
|
1321
|
+
var projectRoot = process.cwd();
|
|
1322
|
+
var plugin = vxrnCompilerPlugin("ios", true, projectRoot, false);
|
|
1323
|
+
if (typeof plugin.transform !== "function") throw new Error("transform hook not callable");
|
|
1324
|
+
var inputCode = `export function fn() { 'worklet'; return 1 }`;
|
|
1325
|
+
var id = join(projectRoot, "DefaultWorklet.tsx");
|
|
1326
|
+
expect(await Reflect.apply(plugin.transform, void 0, [inputCode, id])).toBeDefined();
|
|
1327
|
+
expect(babelSpy).toHaveBeenCalledWith(id, inputCode, expect.objectContaining({
|
|
1328
|
+
plugins: expect.arrayContaining(["react-native-reanimated/plugin"])
|
|
1329
|
+
}));
|
|
1330
|
+
expect(workletSpy).not.toHaveBeenCalled();
|
|
1331
|
+
} finally {
|
|
1332
|
+
babelSpy.mockRestore();
|
|
1333
|
+
workletSpy.mockRestore();
|
|
1334
|
+
getBabelOptionsSpy.mockRestore();
|
|
1335
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1336
|
+
enableReanimated: false,
|
|
1337
|
+
enableNativeWorklets: false
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
it("intercepts tuple worklet plugins with options, executes native SWC with options, and skips Babel when enableNativeWorklets is true", async function () {
|
|
1342
|
+
var compiler = await import("@vxrn/compiler");
|
|
1343
|
+
var {
|
|
1344
|
+
vi: vi2
|
|
1345
|
+
} = await import("vitest");
|
|
1346
|
+
var babelSpy = vi2.spyOn(compiler, "transformBabel");
|
|
1347
|
+
var workletSpy = vi2.spyOn(compiler, "transformWorklets");
|
|
1348
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1349
|
+
enableReanimated: true,
|
|
1350
|
+
enableNativeWorklets: true
|
|
1351
|
+
});
|
|
1352
|
+
var getBabelOptionsSpy = vi2.spyOn(compiler, "getBabelOptions").mockReturnValue({
|
|
1353
|
+
plugins: [["react-native-reanimated/plugin", {
|
|
1354
|
+
globals: ["customGlobal"]
|
|
1355
|
+
}]]
|
|
1356
|
+
});
|
|
1357
|
+
try {
|
|
1358
|
+
var projectRoot = process.cwd();
|
|
1359
|
+
var plugin = vxrnCompilerPlugin("ios", true, projectRoot, false);
|
|
1360
|
+
if (typeof plugin.transform !== "function") throw new Error("transform hook not callable");
|
|
1361
|
+
var inputCode = `export function fn() { 'worklet'; return customGlobal * 2 }`;
|
|
1362
|
+
var id = join(projectRoot, "TupleWorklet.tsx");
|
|
1363
|
+
var result = await Reflect.apply(plugin.transform, void 0, [inputCode, id]);
|
|
1364
|
+
expect(result).toBeDefined();
|
|
1365
|
+
expect(result.code).toContain("__workletHash");
|
|
1366
|
+
expect(workletSpy).toHaveBeenCalledWith(id, expect.any(String), false, expect.objectContaining({
|
|
1367
|
+
globals: ["customGlobal"],
|
|
1368
|
+
projectRoot
|
|
1369
|
+
}));
|
|
1370
|
+
expect(babelSpy).not.toHaveBeenCalled();
|
|
1371
|
+
} finally {
|
|
1372
|
+
babelSpy.mockRestore();
|
|
1373
|
+
workletSpy.mockRestore();
|
|
1374
|
+
getBabelOptionsSpy.mockRestore();
|
|
1375
|
+
compiler.configureVXRNCompilerPlugin({
|
|
1376
|
+
enableReanimated: false,
|
|
1377
|
+
enableNativeWorklets: false
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
});
|
|
610
1381
|
});
|
|
611
1382
|
describe("native production assets", function () {
|
|
612
1383
|
it("registers scale siblings and keeps monorepo assets inside assetsDest", async function () {
|
|
@@ -811,4 +1582,65 @@ globalThis.__vxrnConditionalExportProbe = helper()
|
|
|
811
1582
|
}
|
|
812
1583
|
});
|
|
813
1584
|
});
|
|
1585
|
+
describe("native Flow sources", function () {
|
|
1586
|
+
it.each(["", `/* ${"license text ".repeat(150)} */
|
|
1587
|
+
`])("strips third-party Flow following a license header (%#)", async function (license) {
|
|
1588
|
+
var testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-flow-"));
|
|
1589
|
+
var packageRoot = join(testRoot, "node_modules/@flowy-scope/flowy-lib");
|
|
1590
|
+
await mkdir(packageRoot, {
|
|
1591
|
+
recursive: true
|
|
1592
|
+
});
|
|
1593
|
+
await writeFile(join(packageRoot, "package.json"), JSON.stringify({
|
|
1594
|
+
name: "@flowy-scope/flowy-lib",
|
|
1595
|
+
main: "./js/Flowy.js"
|
|
1596
|
+
}));
|
|
1597
|
+
await mkdir(join(packageRoot, "js"), {
|
|
1598
|
+
recursive: true
|
|
1599
|
+
});
|
|
1600
|
+
await writeFile(join(packageRoot, "js/Flowy.js"), `${license}/**
|
|
1601
|
+
* @flow
|
|
1602
|
+
* @format
|
|
1603
|
+
*/
|
|
1604
|
+
|
|
1605
|
+
type FlowyProps = {|
|
|
1606
|
+
+value: number,
|
|
1607
|
+
|}
|
|
1608
|
+
|
|
1609
|
+
export default class Flowy {
|
|
1610
|
+
_seen: boolean = false
|
|
1611
|
+
|
|
1612
|
+
measure(props: FlowyProps): number {
|
|
1613
|
+
const { value, ...rest }: FlowyProps = props
|
|
1614
|
+
this._seen = true
|
|
1615
|
+
return ((value: any): number) + Object.keys(rest).length
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
`);
|
|
1619
|
+
await writeFile(join(testRoot, "entry.js"), `import Flowy from '@flowy-scope/flowy-lib'
|
|
1620
|
+
globalThis.__vxrnFlowProbe = new Flowy().measure({ value: 41 }) + 1
|
|
1621
|
+
`);
|
|
1622
|
+
try {
|
|
1623
|
+
var result = await buildNativeBundle({
|
|
1624
|
+
root: testRoot,
|
|
1625
|
+
platform: "ios",
|
|
1626
|
+
entryFile: "entry.js"
|
|
1627
|
+
});
|
|
1628
|
+
var context = {
|
|
1629
|
+
clearTimeout,
|
|
1630
|
+
console,
|
|
1631
|
+
process: {
|
|
1632
|
+
env: {}
|
|
1633
|
+
},
|
|
1634
|
+
setTimeout
|
|
1635
|
+
};
|
|
1636
|
+
runInNewContext(result.code, context);
|
|
1637
|
+
expect(Reflect.get(context, "__vxrnFlowProbe")).toBe(42);
|
|
1638
|
+
} finally {
|
|
1639
|
+
await rm(testRoot, {
|
|
1640
|
+
recursive: true,
|
|
1641
|
+
force: true
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
});
|
|
814
1646
|
//# sourceMappingURL=createNativeDevEngine.test.native.js.map
|