vxrn 1.26.0 → 2.0.0-beta.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/patches/builtInDepPatches.mjs +23 -42
  2. package/dist/patches/builtInDepPatches.mjs.map +1 -1
  3. package/dist/patches/builtInDepPatches.native.js +23 -42
  4. package/dist/patches/builtInDepPatches.native.js.map +1 -1
  5. package/dist/plugins/reactNativeDevServer.mjs +88 -42
  6. package/dist/plugins/reactNativeDevServer.mjs.map +1 -1
  7. package/dist/plugins/reactNativeDevServer.native.js +113 -44
  8. package/dist/plugins/reactNativeDevServer.native.js.map +1 -1
  9. package/dist/rn-commands/bundle/buildBundle.mjs +29 -10
  10. package/dist/rn-commands/bundle/buildBundle.mjs.map +1 -1
  11. package/dist/rn-commands/bundle/buildBundle.native.js +29 -10
  12. package/dist/rn-commands/bundle/buildBundle.native.js.map +1 -1
  13. package/dist/utils/createNativeDevEngine.mjs +288 -95
  14. package/dist/utils/createNativeDevEngine.mjs.map +1 -1
  15. package/dist/utils/createNativeDevEngine.native.js +329 -95
  16. package/dist/utils/createNativeDevEngine.native.js.map +1 -1
  17. package/dist/utils/createNativeDevEngine.test.mjs +285 -23
  18. package/dist/utils/createNativeDevEngine.test.mjs.map +1 -1
  19. package/dist/utils/createNativeDevEngine.test.native.js +319 -23
  20. package/dist/utils/createNativeDevEngine.test.native.js.map +1 -1
  21. package/dist/utils/patches.test.mjs.map +1 -1
  22. package/dist/utils/patches.test.native.js.map +1 -1
  23. package/dist/utils/scanDepsToOptimize.mjs +1 -3
  24. package/dist/utils/scanDepsToOptimize.mjs.map +1 -1
  25. package/dist/utils/scanDepsToOptimize.native.js +1 -3
  26. package/dist/utils/scanDepsToOptimize.native.js.map +1 -1
  27. package/dist/utils/symbolicateNativeStack.mjs +66 -0
  28. package/dist/utils/symbolicateNativeStack.mjs.map +1 -0
  29. package/dist/utils/symbolicateNativeStack.native.js +70 -0
  30. package/dist/utils/symbolicateNativeStack.native.js.map +1 -0
  31. package/dist/utils/symbolicateNativeStack.test.mjs +96 -0
  32. package/dist/utils/symbolicateNativeStack.test.mjs.map +1 -0
  33. package/dist/utils/symbolicateNativeStack.test.native.js +96 -0
  34. package/dist/utils/symbolicateNativeStack.test.native.js.map +1 -0
  35. package/expo-plugin.cjs +12 -6
  36. package/package.json +13 -12
  37. package/src/patches/builtInDepPatches.ts +24 -48
  38. package/src/plugins/reactNativeDevServer.ts +124 -52
  39. package/src/rn-commands/bundle/buildBundle.ts +28 -9
  40. package/src/utils/createNativeDevEngine.test.ts +581 -193
  41. package/src/utils/createNativeDevEngine.ts +506 -123
  42. package/src/utils/patches.test.ts +1 -4
  43. package/src/utils/scanDepsToOptimize.ts +0 -3
  44. package/src/utils/symbolicateNativeStack.test.ts +78 -0
  45. package/src/utils/symbolicateNativeStack.ts +129 -0
  46. package/types/patches/builtInDepPatches.d.ts.map +1 -1
  47. package/types/plugins/reactNativeDevServer.d.ts.map +1 -1
  48. package/types/rn-commands/bundle/buildBundle.d.ts.map +1 -1
  49. package/types/utils/createNativeDevEngine.d.ts +22 -4
  50. package/types/utils/createNativeDevEngine.d.ts.map +1 -1
  51. package/types/utils/scanDepsToOptimize.d.ts.map +1 -1
  52. package/types/utils/symbolicateNativeStack.d.ts +46 -0
  53. package/types/utils/symbolicateNativeStack.d.ts.map +1 -0
  54. package/types/utils/symbolicateNativeStack.test.d.ts +2 -0
  55. package/types/utils/symbolicateNativeStack.test.d.ts.map +1 -0
@@ -1,7 +1,8 @@
1
1
  import { createHash } from "crypto";
2
2
  import { basename, dirname, extname, join, relative, resolve } from "path";
3
- import { copyFileSync, mkdirSync, readFileSync, readdirSync, realpathSync } from "fs";
3
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, watch, writeFileSync } from "fs";
4
4
  import { pathToFileURL } from "url";
5
+ import micromatch from "micromatch";
5
6
  import { loadEnv, normalizePath } from "vite";
6
7
  import { shouldStripFlow, transformHermesAsync } from "@vxrn/compiler";
7
8
  import { DEFAULT_ASSET_EXTS } from "../constants/defaults.native.js";
@@ -145,7 +146,13 @@ function getNativeTransformConfig(platform, dev, root) {
145
146
  };
146
147
  }
147
148
  function getNativePlugins(root, platform, viteImportGlobPlugin, dev, assetsDest, onAsset) {
148
- var sourceMaps = arguments.length > 6 && arguments[6] !== void 0 ? arguments[6] : false;
149
+ var sourceMaps = arguments.length > 6 && arguments[6] !== void 0 ? arguments[6] : false,
150
+ userPlugins = arguments.length > 7 && arguments[7] !== void 0 ? arguments[7] : [];
151
+ var context = {
152
+ root,
153
+ platform,
154
+ dev
155
+ };
149
156
  return [...(globalThis.__vxrnAddNativePlugins || []), serverFileExclusionPlugin(), environmentGuardPlugin(), hmrClientNoopPlugin(), cssStubPlugin(), viteImportGlobPlugin({
150
157
  root
151
158
  }), vxrnCompilerPlugin(platform, dev, root, sourceMaps), rnCodegenPlugin({
@@ -155,25 +162,47 @@ function getNativePlugins(root, platform, viteImportGlobPlugin, dev, assetsDest,
155
162
  platform,
156
163
  assetsDest,
157
164
  onAsset
158
- }), hermesCompatSWCPlugin(dev, sourceMaps), hermesLoopsPlugin(sourceMaps)];
165
+ }), hermesCompatSWCPlugin(dev, sourceMaps), hermesLoopsPlugin(sourceMaps), ...userPlugins].map(function (plugin) {
166
+ var _plugin_api;
167
+ return ((_plugin_api = plugin.api) === null || _plugin_api === void 0 ? void 0 : _plugin_api.vxrnNative) ? plugin.api.vxrnNative(context) : plugin;
168
+ });
159
169
  }
160
- function getNativeOutputOptions(prelude, sourcemap) {
170
+ function getNativeOutputOptions(prelude, sourcemap, minify) {
161
171
  return {
162
172
  format: "esm",
163
173
  sourcemap,
174
+ sourcemapPathTransform: function (relativeSourcePath, sourcemapPath) {
175
+ return normalizePath(resolve(dirname(sourcemapPath), relativeSourcePath));
176
+ },
164
177
  intro: prelude,
165
178
  codeSplitting: false,
166
- strictExecutionOrder: true
179
+ strictExecutionOrder: true,
180
+ minify: minify || "dce-only"
167
181
  };
168
182
  }
169
183
  function normalizeNativeCommonJSInterop(code) {
170
184
  return code.replace(/(\b__toESM(?:\$\d+)?\(\s*(?:require[\w$]*\(\)|__rolldown_runtime__\.loadExports\("(?:\\.|[^"\\])*"\))\s*),\s*1(\s*\))/g, "$1$2");
171
185
  }
186
+ function blankPreservingLines(match) {
187
+ var _ref;
188
+ var _match_match;
189
+ return "\n".repeat((_ref = (_match_match = match.match(/\n/g)) === null || _match_match === void 0 ? void 0 : _match_match.length) !== null && _ref !== void 0 ? _ref : 0);
190
+ }
191
+ function countLines(code) {
192
+ var _ref;
193
+ var _code_match;
194
+ return ((_ref = (_code_match = code.match(/\n/g)) === null || _code_match === void 0 ? void 0 : _code_match.length) !== null && _ref !== void 0 ? _ref : 0) + 1;
195
+ }
196
+ function assertBundleLinesPreserved(before, after, stage) {
197
+ var beforeLines = countLines(before);
198
+ var afterLines = countLines(after);
199
+ if (beforeLines !== afterLines) throw new Error(`[vxrn] native bundle post-processing (${stage}) changed the line count (${beforeLines} -> ${afterLines}), which invalidates the source map. Every pass after Rolldown emits the map must preserve lines.`);
200
+ }
172
201
  function postProcessNativeBundle(code) {
173
202
  code = normalizeNativeCommonJSInterop(code);
174
203
  code = code.replace(/\btypeof\s+import\.meta\b/g, "\"object\"");
175
- code = code.replace(/^\s*export\s*\{[^}]*\}\s*;?\s*$/gm, "");
176
- code = code.replace(/^\s*export\s+default\s+([^;\n]+);?\s*$/gm, "$1;");
204
+ code = code.replace(/^[^\S\n]*export[^\S\n]*\{[^}]*\}[^\S\n]*;?[^\S\n]*$/gm, blankPreservingLines);
205
+ code = code.replace(/^([^\S\n]*)export[^\S\n]+default[^\S\n]+([^;\n]+);?[^\S\n]*$/gm, "$1$2;");
177
206
  code = code.replace(/^if \(import\.meta\.hot\).*$/gm, "");
178
207
  var idx = code.indexOf("NativeAnimatedModule_default ?? NativeAnimatedTurboModule_default;");
179
208
  if (idx !== -1) {
@@ -185,7 +214,8 @@ function postProcessNativeBundle(code) {
185
214
  var afterMarker = code.indexOf("})();", idx);
186
215
  if (afterMarker !== -1) {
187
216
  var end = afterMarker + 5;
188
- code = code.slice(0, beforeMarker) + "NativeAnimatedModule = NativeAnimatedModule_default ?? NativeAnimatedTurboModule_default;" + code.slice(end);
217
+ var removed = code.slice(beforeMarker, end);
218
+ code = code.slice(0, beforeMarker) + "NativeAnimatedModule = NativeAnimatedModule_default ?? NativeAnimatedTurboModule_default;" + blankPreservingLines(removed) + code.slice(end);
189
219
  }
190
220
  }
191
221
  }
@@ -195,7 +225,7 @@ function postProcessNativeBundle(code) {
195
225
  function wrapNativeBundleModuleScope(code) {
196
226
  var idx = code.indexOf("//#region \\0rolldown/runtime.js");
197
227
  if (idx === -1) return code;
198
- return code.slice(0, idx) + ";(function() {\n" + code.slice(idx) + "\n})();\n";
228
+ return code.slice(0, idx) + ";(function() {" + code.slice(idx) + "\n})();\n";
199
229
  }
200
230
  async function downlevelClassFieldsInBundle(code) {
201
231
  var _ref, _ref1;
@@ -229,7 +259,21 @@ ${transformedCode}`;
229
259
  var linePreservingRuntime = transformed + "\n".repeat(originalNewlines - transformedNewlines);
230
260
  return code.slice(0, startIdx) + linePreservingRuntime + code.slice(runtimeEnd);
231
261
  }
262
+ function nativeBundlePostProcessPlugin() {
263
+ return {
264
+ name: "vxrn:native-post-process",
265
+ async renderChunk(code) {
266
+ var processed = await downlevelClassFieldsInBundle(postProcessNativeBundle(code));
267
+ assertBundleLinesPreserved(code, processed, "production");
268
+ return {
269
+ code: processed,
270
+ map: null
271
+ };
272
+ }
273
+ };
274
+ }
232
275
  async function createNativeDevEngine(options) {
276
+ var _statSync;
233
277
  var {
234
278
  root,
235
279
  port,
@@ -256,7 +300,18 @@ async function createNativeDevEngine(options) {
256
300
  var bundleReject = null;
257
301
  var bundlePromise = null;
258
302
  var resolvedHost = host === "0.0.0.0" ? "localhost" : host;
259
- var engine = await dev({
303
+ var virtualEntry = nativeVirtualEntryPlugin(root, {
304
+ dev: true,
305
+ platform,
306
+ dynamicRoutes: true
307
+ });
308
+ var engineWork = Promise.resolve();
309
+ var queueEngineWork = function (work) {
310
+ var result = engineWork.then(work, work);
311
+ engineWork = result.catch(function () {});
312
+ return result;
313
+ };
314
+ var inputOptions = {
260
315
  input: VIRTUAL_NATIVE_ENTRY,
261
316
  cwd: root,
262
317
  platform: "neutral",
@@ -276,74 +331,50 @@ async function createNativeDevEngine(options) {
276
331
  moduleTypes: {
277
332
  ".js": "jsx"
278
333
  },
279
- plugins: [nativeVirtualEntryPlugin(root, {
280
- dev: true
281
- }), ...getNativePlugins(root, platform, viteImportGlobPlugin, true, void 0, assetRegistry.register, false), ...userPlugins]
282
- }, {
283
- ...getNativeOutputOptions(prelude, false),
334
+ plugins: [virtualEntry.plugin, ...getNativePlugins(root, platform, viteImportGlobPlugin, true, void 0, assetRegistry.register, true, userPlugins)]
335
+ };
336
+ var outputOptions = {
337
+ ...getNativeOutputOptions(prelude, true, false),
284
338
  outro: `
285
339
  try {
286
340
  var __WS = (init_WebSocket(), __toCommonJS(WebSocket_exports)).default;
287
341
  var __hmrUrl = 'ws://${resolvedHost}:${port}/hot?platform=${platform}&clientId=' + encodeURIComponent(__rolldown_runtime__.clientId);
288
- var __hmrWS = new __WS(__hmrUrl);
289
- __hmrWS.onmessage = function(event) {
290
- try {
291
- var msg = JSON.parse(event.data);
292
- var g = typeof global !== 'undefined' ? global : globalThis;
293
- if (msg.type === 'hmr:update' && msg.code) {
294
- var applied = __rolldown_runtime__.applyHmrUpdate(msg.code, msg.changedIds, msg.seq);
295
- if (!applied) {
296
- var updateSettings = g.__turboModuleProxy ? g.__turboModuleProxy('DevSettings') : null;
297
- if (updateSettings && updateSettings.reload) updateSettings.reload();
298
- }
299
- } else if (msg.type === 'hmr:reload') {
300
- var ds = g.__turboModuleProxy ? g.__turboModuleProxy('DevSettings') : null;
301
- if (ds && ds.reload) ds.reload();
302
- }
303
- } catch(e) { console.error('[vxrn] HMR eval error:', e); }
342
+ __rolldown_runtime__.setup(new __WS(__hmrUrl));
343
+ } catch(e) {
344
+ // a swallowed failure here leaves the app permanently without Fast Refresh and
345
+ // nothing on screen or in the terminal says so.
346
+ console.error('[vxrn] HMR client failed to start:', (e && e.message) || e);
347
+ }
348
+ `
304
349
  };
305
- __hmrWS.onopen = function() {
306
- if (typeof __rolldown_runtime__ !== 'undefined' && __rolldown_runtime__.setup) {
307
- __rolldown_runtime__.setup(__hmrWS);
308
- }
350
+ var outputProcessed = Promise.resolve();
351
+ var engine;
352
+ var routeWatcher;
353
+ var rebuildIfRouteGraphChanged = function () {
354
+ return queueEngineWork(async function () {
355
+ var {
356
+ files: knownRoutes,
357
+ scanFiles,
358
+ updateFiles
359
+ } = virtualEntry.routes;
360
+ var currentRoutes = scanFiles();
361
+ if (!(currentRoutes.size !== knownRoutes.size || [...currentRoutes].some(function (route) {
362
+ return !knownRoutes.has(route);
363
+ }))) return false;
364
+ updateFiles(currentRoutes);
365
+ return true;
366
+ });
309
367
  };
310
- __hmrWS.onerror = function(e) { console.warn('[vxrn] HMR connection error:', e.message || e); };
311
- } catch(e) {}
312
- `
313
- }, {
368
+ engine = await dev(inputOptions, outputOptions, {
314
369
  onOutput: async function (result) {
315
- if (_instanceof(result, Error)) {
316
- console.error("[vxrn] native bundle error:", result.message);
317
- if (!currentBundle) {
318
- firstBuildError || (firstBuildError = result);
319
- if (bundleReject) {
320
- var reject = bundleReject;
321
- bundleResolve = null;
322
- bundleReject = null;
323
- bundlePromise = null;
324
- reject(firstBuildError);
325
- }
326
- }
327
- return;
328
- }
329
- var chunk = result.output.find(function (o) {
330
- return o.type === "chunk" && o.isEntry;
370
+ var finishOutput = function () {};
371
+ outputProcessed = new Promise(function (resolve2) {
372
+ finishOutput = resolve2;
331
373
  });
332
- if (chunk && "code" in chunk) {
333
- firstBuildError = null;
334
- var code = postProcessNativeBundle(chunk.code);
335
- code = await downlevelClassFieldsInBundle(code);
336
- code = wrapNativeBundleModuleScope(code);
337
- currentBundle = {
338
- code
339
- };
340
- console.info(`[vxrn] native bundle ready (${Math.round(code.length / 1024)}KB)`);
341
- if (bundleResolve) {
342
- bundleResolve(currentBundle);
343
- bundleResolve = null;
344
- bundleReject = null;
345
- bundlePromise = null;
346
- }
374
+ try {
375
+ await handleOutput(result);
376
+ } finally {
377
+ finishOutput();
347
378
  }
348
379
  },
349
380
  onHmrUpdates: async function (result) {
@@ -354,6 +385,7 @@ try {
354
385
  });
355
386
  return;
356
387
  }
388
+ if (await rebuildIfRouteGraphChanged()) return;
357
389
  var _iteratorNormalCompletion = true,
358
390
  _didIteratorError = false,
359
391
  _iteratorError = void 0;
@@ -388,11 +420,76 @@ try {
388
420
  rebuildStrategy: "never",
389
421
  watch: {}
390
422
  });
423
+ async function handleOutput(result) {
424
+ if (_instanceof(result, Error)) {
425
+ console.error("[vxrn] native bundle error:", result.message);
426
+ if (/panic/i.test(result.message)) console.error("[vxrn] rolldown itself panicked. Fast Refresh will full-reload until you restart the dev server.");
427
+ if (!currentBundle) {
428
+ firstBuildError || (firstBuildError = result);
429
+ if (bundleReject) {
430
+ var reject = bundleReject;
431
+ bundleResolve = null;
432
+ bundleReject = null;
433
+ bundlePromise = null;
434
+ reject(firstBuildError);
435
+ }
436
+ }
437
+ return;
438
+ }
439
+ var chunk = result.output.find(function (o) {
440
+ return o.type === "chunk" && o.isEntry;
441
+ });
442
+ if (chunk && "code" in chunk) {
443
+ firstBuildError = null;
444
+ var code = postProcessNativeBundle(chunk.code);
445
+ code = await downlevelClassFieldsInBundle(code);
446
+ assertBundleLinesPreserved(chunk.code, code, "dev");
447
+ code = wrapNativeBundleModuleScope(code);
448
+ if (!chunk.map) throw new Error("[vxrn] rolldown produced no source map for the dev bundle, so /symbolicate cannot resolve a frame");
449
+ currentBundle = {
450
+ code,
451
+ map: chunk.map.toString()
452
+ };
453
+ console.info(`[vxrn] native bundle ready (${Math.round(code.length / 1024)}KB)`);
454
+ if (bundleResolve) {
455
+ bundleResolve(currentBundle);
456
+ bundleResolve = null;
457
+ bundleReject = null;
458
+ bundlePromise = null;
459
+ }
460
+ }
461
+ }
391
462
  await engine.run();
463
+ var routeWatchTarget = virtualEntry.routes.routeRoot;
464
+ while (!((_statSync = statSync(routeWatchTarget, {
465
+ throwIfNoEntry: false
466
+ })) === null || _statSync === void 0 ? void 0 : _statSync.isDirectory())) {
467
+ var parent = dirname(routeWatchTarget);
468
+ if (parent === routeWatchTarget) break;
469
+ routeWatchTarget = parent;
470
+ }
471
+ var normalizedRouteRoot = normalizePath(virtualEntry.routes.routeRoot);
472
+ routeWatcher = watch(routeWatchTarget, {
473
+ recursive: true
474
+ }, function (_eventType, file) {
475
+ if (file === null) return;
476
+ var changed = normalizePath(resolve(routeWatchTarget, file.toString()));
477
+ if (changed !== normalizedRouteRoot && !changed.startsWith(`${normalizedRouteRoot}/`)) return;
478
+ rebuildIfRouteGraphChanged().catch(function (error) {
479
+ console.error(`[vxrn] rebuilding the native route map failed`, error);
480
+ });
481
+ });
482
+ routeWatcher.on("error", function (error) {
483
+ console.error(`[vxrn] watching the native route map failed`, error);
484
+ });
485
+ await rebuildIfRouteGraphChanged();
392
486
  return {
393
487
  engine,
394
488
  async getBundle() {
395
- await engine.ensureLatestBuildOutput();
489
+ await queueEngineWork(async function () {
490
+ await engine.ensureLatestBuildOutput();
491
+ await outputProcessed;
492
+ });
396
493
  if (currentBundle) return currentBundle;
397
494
  if (firstBuildError) throw firstBuildError;
398
495
  if (!bundlePromise) {
@@ -420,6 +517,7 @@ try {
420
517
  return assetRegistry.resolve(pathname, hash);
421
518
  },
422
519
  async close() {
520
+ routeWatcher === null || routeWatcher === void 0 || routeWatcher.close();
423
521
  await engine.close();
424
522
  }
425
523
  };
@@ -434,7 +532,8 @@ async function buildNativeBundle(options) {
434
532
  entryFile,
435
533
  assetsDest,
436
534
  plugins: userPlugins = [],
437
- sourcemap = false
535
+ sourcemap = false,
536
+ minify = !dev
438
537
  } = options;
439
538
  var {
440
539
  build
@@ -462,23 +561,24 @@ async function buildNativeBundle(options) {
462
561
  ".js": "jsx"
463
562
  },
464
563
  plugins: [...(entryFile ? [] : [nativeVirtualEntryPlugin(root, {
465
- dev
466
- })]), ...getNativePlugins(root, platform, viteImportGlobPlugin, dev, assetsDest, void 0, sourcemap), ...userPlugins],
467
- output: getNativeOutputOptions(prelude, sourcemap)
564
+ dev,
565
+ platform
566
+ }).plugin]), ...getNativePlugins(root, platform, viteImportGlobPlugin, dev, assetsDest, void 0, sourcemap, userPlugins), nativeBundlePostProcessPlugin()],
567
+ output: getNativeOutputOptions(prelude, sourcemap, minify)
468
568
  })).output.find(function (o) {
469
569
  return o.type === "chunk" && o.isEntry;
470
570
  });
471
571
  if (!chunk || !("code" in chunk)) throw new Error("[vxrn] production build produced no output");
472
- var code = postProcessNativeBundle(chunk.code);
473
- code = await downlevelClassFieldsInBundle(code);
572
+ if (sourcemap && !chunk.map) throw new Error("[vxrn] a source map was requested but rolldown produced none for the production bundle");
474
573
  return {
475
- code,
574
+ code: chunk.code,
476
575
  map: sourcemap ? (_chunk_map = chunk.map) === null || _chunk_map === void 0 ? void 0 : _chunk_map.toString() : void 0
477
576
  };
478
577
  }
479
578
  var VIRTUAL_NATIVE_ENTRY = "virtual:native-entry";
480
579
  function nativeVirtualEntryPlugin(root, opts) {
481
580
  var isDev = (opts === null || opts === void 0 ? void 0 : opts.dev) !== false;
581
+ var useDynamicRouteRegistry = opts.dynamicRoutes === true;
482
582
  var resolvedId = normalizePath(resolve(root, "__virtual-native-entry.tsx"));
483
583
  var entryConfig = globalThis.__vxrnNativeEntryConfig || {};
484
584
  var routerRoot = entryConfig.routerRoot || "app";
@@ -495,8 +595,7 @@ function nativeVirtualEntryPlugin(root, opts) {
495
595
  var routeGlobs = [`./${routerRoot}/**/*.tsx`, `./${routerRoot}/**/*.ts`, `!./${routerRoot}/**/*+api.*`, `!./${routerRoot}/**/*.test.*`, `!./${routerRoot}/**/*.d.ts`, `!./${routerRoot}/**/*.server.*`, `!./${routerRoot}/**/_middleware.*`, `!./${routerRoot}/**/*.web.*`, ...(entryConfig.ignoredRouteFiles || []).map(function (pattern) {
496
596
  return `!./${routerRoot}/${pattern}`;
497
597
  })];
498
- var entryCode = `
499
- ${isDev ? `
598
+ var refreshSetup = isDev ? `
500
599
  // react-refresh/runtime MUST initialize before React loads
501
600
  import RefreshRuntime from 'react-refresh/runtime';
502
601
  RefreshRuntime.injectIntoGlobalHook(globalThis);
@@ -505,22 +604,26 @@ globalThis.$RefreshReg$ = function(type, id) {
505
604
  RefreshRuntime.register(type, id);
506
605
  };
507
606
  globalThis.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
508
- ` : ""}
607
+ ` : "";
608
+ var entryCode = function () {
609
+ return `
610
+ ${refreshSetup}
509
611
  import * as ReactNativeInitializeCore from 'react-native/Libraries/Core/InitializeCore';
510
612
  import NativeWebSocket from 'react-native/Libraries/WebSocket/WebSocket';
613
+ import DevSettings from 'react-native/Libraries/Utilities/DevSettings';
511
614
  ${setupFileImport}
615
+ ${routeImports}
512
616
  import { createApp } from 'one';
513
617
 
514
618
  void ReactNativeInitializeCore;
515
619
  globalThis.WebSocket = NativeWebSocket;
620
+ globalThis.__VXRN_RELOAD_NATIVE_DEV_BUNDLE__ = function(reason) {
621
+ DevSettings.reload(reason);
622
+ };
516
623
 
517
- var _routes = import.meta.glob(${JSON.stringify(routeGlobs)}, { exhaustive: true });
518
- // fix route keys: One expects '/${routerRoot}/...' prefix but import.meta.glob returns './${routerRoot}/...'
519
- var routes = {};
520
- Object.keys(_routes).forEach(function(key) {
521
- var normalizedKey = key.replace(/^\\.\\//, '');
522
- routes['/' + normalizedKey] = _routes[key];
523
- });
624
+ // React Native reloads a dev bundle in the existing JS runtime. Advance One's
625
+ // route-cache version so a full reload cannot reuse the previous context.
626
+ globalThis.__vxrnVersion = (globalThis.__vxrnVersion || 0) + 1;
524
627
 
525
628
  createApp({
526
629
  routes: routes,
@@ -528,14 +631,108 @@ createApp({
528
631
  flags: ${JSON.stringify(flags)},
529
632
  linking: ${JSON.stringify(linking)},
530
633
  });
634
+
635
+ ${routeHmr}
531
636
  `;
637
+ };
638
+ var routeRoot = resolve(root, routerRoot);
639
+ var stripDot = function (pattern) {
640
+ return pattern.replace(/^\.\//, "");
641
+ };
642
+ var includeGlobs = routeGlobs.filter(function (p) {
643
+ return !p.startsWith("!");
644
+ }).map(stripDot);
645
+ var excludeGlobs = routeGlobs.filter(function (p) {
646
+ return p.startsWith("!");
647
+ }).map(function (p) {
648
+ return stripDot(p.slice(1));
649
+ });
650
+ var isRouteFile = function (file) {
651
+ var relativeToRoot = normalizePath(relative(root, file));
652
+ return micromatch.isMatch(relativeToRoot, includeGlobs) && !micromatch.isMatch(relativeToRoot, excludeGlobs);
653
+ };
654
+ var scanFiles = function () {
655
+ var _statSync;
656
+ var files = /* @__PURE__ */new Set();
657
+ var walkRouteRoot = function (dir) {
658
+ var _iteratorNormalCompletion = true,
659
+ _didIteratorError = false,
660
+ _iteratorError = void 0;
661
+ try {
662
+ for (var _iterator = readdirSync(dir, {
663
+ withFileTypes: true
664
+ })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
665
+ var entry = _step.value;
666
+ var child = resolve(dir, entry.name);
667
+ if (entry.isDirectory()) walkRouteRoot(child);else if (isRouteFile(child)) files.add(normalizePath(child));
668
+ }
669
+ } catch (err) {
670
+ _didIteratorError = true;
671
+ _iteratorError = err;
672
+ } finally {
673
+ try {
674
+ if (!_iteratorNormalCompletion && _iterator.return != null) _iterator.return();
675
+ } finally {
676
+ if (_didIteratorError) throw _iteratorError;
677
+ }
678
+ }
679
+ };
680
+ if ((_statSync = statSync(routeRoot, {
681
+ throwIfNoEntry: false
682
+ })) === null || _statSync === void 0 ? void 0 : _statSync.isDirectory()) walkRouteRoot(routeRoot);
683
+ return files;
684
+ };
685
+ var registrySpecifier = `./node_modules/.vxrn/native-routes-${opts.platform}.mjs`;
686
+ var registryPath = resolve(root, registrySpecifier);
687
+ var routes = {
688
+ routeRoot,
689
+ files: /* @__PURE__ */new Set(),
690
+ isRouteFile,
691
+ scanFiles,
692
+ updateFiles(files) {
693
+ routes.files = files;
694
+ if (!useDynamicRouteRegistry) return;
695
+ var source = `export const routes = {
696
+ ${[...files].sort().map(function (file) {
697
+ var routeKey = `/${normalizePath(relative(root, file))}`;
698
+ var importPath = normalizePath(relative(dirname(registryPath), file));
699
+ if (!importPath.startsWith(".")) importPath = `./${importPath}`;
700
+ return ` ${JSON.stringify(routeKey)}: () => import(${JSON.stringify(importPath)})`;
701
+ }).join(",\n")}
702
+ }
703
+ `;
704
+ mkdirSync(dirname(registryPath), {
705
+ recursive: true
706
+ });
707
+ if (!existsSync(registryPath) || readFileSync(registryPath, "utf8") !== source) writeFileSync(registryPath, source);
708
+ }
709
+ };
710
+ routes.updateFiles(routes.scanFiles());
711
+ var routeImports = useDynamicRouteRegistry ? `import { routes } from ${JSON.stringify(registrySpecifier)};` : `var _routes = import.meta.glob(${JSON.stringify(routeGlobs)}, { exhaustive: true });
712
+ // fix route keys: One expects '/${routerRoot}/...' prefix but import.meta.glob returns './${routerRoot}/...'
713
+ var routes = {};
714
+ Object.keys(_routes).forEach(function(key) {
715
+ var normalizedKey = key.replace(/^\\.\\//, '');
716
+ routes['/' + normalizedKey] = _routes[key];
717
+ });`;
718
+ var routeHmr = useDynamicRouteRegistry ? `if (import.meta.hot) {
719
+ import.meta.hot.accept(${JSON.stringify(registrySpecifier)}, function(next) {
720
+ if (globalThis.__VXRN_UPDATE_NATIVE_ROUTES__) {
721
+ globalThis.__VXRN_UPDATE_NATIVE_ROUTES__(next.routes);
722
+ }
723
+ });
724
+ }` : "";
532
725
  return {
533
- name: "vxrn:native-virtual-entry",
534
- resolveId(id) {
535
- if (id === VIRTUAL_NATIVE_ENTRY) return resolvedId;
536
- },
537
- load(id) {
538
- if (id === resolvedId) return entryCode;
726
+ routes,
727
+ plugin: {
728
+ name: "vxrn:native-virtual-entry",
729
+ resolveId(id) {
730
+ if (id === VIRTUAL_NATIVE_ENTRY) return resolvedId;
731
+ },
732
+ load(id) {
733
+ if (id !== resolvedId) return;
734
+ return entryCode();
735
+ }
539
736
  }
540
737
  };
541
738
  }
@@ -1328,14 +1525,51 @@ class ReactNativeDevRuntime extends BaseDevRuntime {
1328
1525
  }
1329
1526
  }
1330
1527
 
1528
+ reload(reason) {
1529
+ var reloadNativeBundle = globalThis.__VXRN_RELOAD_NATIVE_DEV_BUNDLE__;
1530
+ if (typeof reloadNativeBundle === 'function') {
1531
+ reloadNativeBundle(reason);
1532
+ return;
1533
+ }
1534
+ console.error('[vxrn HMR]: DevSettings.reload is unavailable');
1535
+ }
1536
+
1331
1537
  setup(socket) {
1332
1538
  if (this._socket) return;
1333
1539
  this._socket = socket;
1540
+ var runtime = this;
1541
+ // addEventListener rather than socket.onmessage: the bundle's WebSocket is
1542
+ // whatever the host platform provides, and a host that does not honor on*
1543
+ // property assignment would otherwise leave the app permanently without
1544
+ // Fast Refresh and say nothing.
1545
+ socket.addEventListener('message', function(event) {
1546
+ var message;
1547
+ try {
1548
+ message = JSON.parse(event.data);
1549
+ } catch (error) {
1550
+ return;
1551
+ }
1552
+ try {
1553
+ if (message.type === 'hmr:update') {
1554
+ // a patch that cannot be applied in place is the reload signal
1555
+ if (!runtime.applyHmrUpdate(message.code, message.changedIds, message.seq)) {
1556
+ runtime.reload('native HMR update could not be applied');
1557
+ }
1558
+ } else if (message.type === 'hmr:reload') {
1559
+ runtime.reload('native route map changed');
1560
+ }
1561
+ } catch (error) {
1562
+ console.error('[vxrn HMR]: failed to apply update', error);
1563
+ }
1564
+ });
1565
+ socket.addEventListener('error', function(event) {
1566
+ console.warn('[vxrn HMR]: connection error', (event && event.message) || event);
1567
+ });
1334
1568
  }
1335
1569
  }
1336
1570
 
1337
1571
  globalThis.__rolldown_runtime__ = new ReactNativeDevRuntime();
1338
1572
  `;
1339
1573
  }
1340
- export { buildNativeBundle, createNativeDevAssetRegistry, createNativeDevEngine, getHermesSWCIncludes, getHmrRuntimeSource, getNativeAssetData, getNativeTransformConfig, hermesCompatPlugin, hermesCompatSWCPlugin, hermesLoopsPlugin, hmrClientNoopPlugin, nativeAnimatedGuardPlugin, normalizeNativeCommonJSInterop, vxrnCompilerPlugin, wrapNativeBundleModuleScope };
1574
+ export { buildNativeBundle, createNativeDevAssetRegistry, createNativeDevEngine, getHermesSWCIncludes, getHmrRuntimeSource, getNativeAssetData, getNativeTransformConfig, hermesCompatPlugin, hermesCompatSWCPlugin, hermesLoopsPlugin, hmrClientNoopPlugin, nativeAnimatedGuardPlugin, normalizeNativeCommonJSInterop, postProcessNativeBundle, vxrnCompilerPlugin, wrapNativeBundleModuleScope };
1341
1575
  //# sourceMappingURL=createNativeDevEngine.native.js.map