vxrn 1.26.1 → 1.27.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.
@@ -1,10 +1,11 @@
1
1
  import { createHash } from "crypto";
2
2
  import { basename, dirname, extname, join, relative, resolve } from "path";
3
- import { copyFileSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync } from "fs";
3
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, watch, writeFileSync } from "fs";
4
4
  import { pathToFileURL } from "url";
5
5
  import micromatch from "micromatch";
6
6
  import { loadEnv, normalizePath } from "vite";
7
7
  import { shouldStripFlow, transformHermesAsync } from "@vxrn/compiler";
8
+ import { resolvePath } from "@vxrn/resolve";
8
9
  import { DEFAULT_ASSET_EXTS } from "../constants/defaults.native.js";
9
10
  import { getNativePrelude } from "../runtime/native-prelude.native.js";
10
11
  import { rnCodegenPlugin } from "../plugins/rnCodegenPlugin.native.js";
@@ -153,7 +154,7 @@ function getNativePlugins(root, platform, viteImportGlobPlugin, dev, assetsDest,
153
154
  platform,
154
155
  dev
155
156
  };
156
- return [...(globalThis.__vxrnAddNativePlugins || []), serverFileExclusionPlugin(), environmentGuardPlugin(), hmrClientNoopPlugin(), cssStubPlugin(), viteImportGlobPlugin({
157
+ return [...(globalThis.__vxrnAddNativePlugins || []), serverFileExclusionPlugin(), environmentGuardPlugin(), hmrClientNoopPlugin(), ...(dev ? [reactNativeDedupePlugin(root)] : []), cssStubPlugin(), viteImportGlobPlugin({
157
158
  root
158
159
  }), vxrnCompilerPlugin(platform, dev, root, sourceMaps), rnCodegenPlugin({
159
160
  projectRoot: root
@@ -273,6 +274,7 @@ function nativeBundlePostProcessPlugin() {
273
274
  };
274
275
  }
275
276
  async function createNativeDevEngine(options) {
277
+ var _statSync;
276
278
  var {
277
279
  root,
278
280
  port,
@@ -300,7 +302,9 @@ async function createNativeDevEngine(options) {
300
302
  var bundlePromise = null;
301
303
  var resolvedHost = host === "0.0.0.0" ? "localhost" : host;
302
304
  var virtualEntry = nativeVirtualEntryPlugin(root, {
303
- dev: true
305
+ dev: true,
306
+ platform,
307
+ dynamicRoutes: true
304
308
  });
305
309
  var engineWork = Promise.resolve();
306
310
  var queueEngineWork = function (work) {
@@ -346,30 +350,21 @@ try {
346
350
  };
347
351
  var outputProcessed = Promise.resolve();
348
352
  var engine;
349
- var rebuildIfNewRoute = async function (files) {
350
- var {
351
- routeRoot,
352
- files: knownRoutes,
353
- isRouteFile
354
- } = virtualEntry.routes;
355
- var routeRootPrefix = `${normalizePath(routeRoot)}/`;
356
- if (!files.some(function (file) {
357
- var _statSync;
358
- var normalized = normalizePath(file);
359
- if (isRouteFile(normalized)) return !knownRoutes.has(normalized);
360
- return normalized.startsWith(routeRootPrefix) && ((_statSync = statSync(file, {
361
- throwIfNoEntry: false
362
- })) === null || _statSync === void 0 ? void 0 : _statSync.isDirectory()) === true;
363
- })) return false;
364
- await queueEngineWork(async function () {
365
- engine.triggerFullBuild();
366
- await engine.ensureLatestBuildOutput();
367
- await outputProcessed;
368
- });
369
- onHmrUpdate === null || onHmrUpdate === void 0 || onHmrUpdate({
370
- type: "hmr:reload"
353
+ var routeWatcher;
354
+ var rebuildIfRouteGraphChanged = function () {
355
+ return queueEngineWork(async function () {
356
+ var {
357
+ files: knownRoutes,
358
+ scanFiles,
359
+ updateFiles
360
+ } = virtualEntry.routes;
361
+ var currentRoutes = scanFiles();
362
+ if (!(currentRoutes.size !== knownRoutes.size || [...currentRoutes].some(function (route) {
363
+ return !knownRoutes.has(route);
364
+ }))) return false;
365
+ updateFiles(currentRoutes);
366
+ return true;
371
367
  });
372
- return true;
373
368
  };
374
369
  engine = await dev(inputOptions, outputOptions, {
375
370
  onOutput: async function (result) {
@@ -391,7 +386,7 @@ try {
391
386
  });
392
387
  return;
393
388
  }
394
- if (await rebuildIfNewRoute(result.changedFiles)) return;
389
+ if (await rebuildIfRouteGraphChanged()) return;
395
390
  var _iteratorNormalCompletion = true,
396
391
  _didIteratorError = false,
397
392
  _iteratorError = void 0;
@@ -466,6 +461,29 @@ try {
466
461
  }
467
462
  }
468
463
  await engine.run();
464
+ var routeWatchTarget = virtualEntry.routes.routeRoot;
465
+ while (!((_statSync = statSync(routeWatchTarget, {
466
+ throwIfNoEntry: false
467
+ })) === null || _statSync === void 0 ? void 0 : _statSync.isDirectory())) {
468
+ var parent = dirname(routeWatchTarget);
469
+ if (parent === routeWatchTarget) break;
470
+ routeWatchTarget = parent;
471
+ }
472
+ var normalizedRouteRoot = normalizePath(virtualEntry.routes.routeRoot);
473
+ routeWatcher = watch(routeWatchTarget, {
474
+ recursive: true
475
+ }, function (_eventType, file) {
476
+ if (file === null) return;
477
+ var changed = normalizePath(resolve(routeWatchTarget, file.toString()));
478
+ if (changed !== normalizedRouteRoot && !changed.startsWith(`${normalizedRouteRoot}/`)) return;
479
+ rebuildIfRouteGraphChanged().catch(function (error) {
480
+ console.error(`[vxrn] rebuilding the native route map failed`, error);
481
+ });
482
+ });
483
+ routeWatcher.on("error", function (error) {
484
+ console.error(`[vxrn] watching the native route map failed`, error);
485
+ });
486
+ await rebuildIfRouteGraphChanged();
469
487
  return {
470
488
  engine,
471
489
  async getBundle() {
@@ -500,10 +518,8 @@ try {
500
518
  return assetRegistry.resolve(pathname, hash);
501
519
  },
502
520
  async close() {
521
+ routeWatcher === null || routeWatcher === void 0 || routeWatcher.close();
503
522
  await engine.close();
504
- },
505
- async handleAddedFile(file) {
506
- await rebuildIfNewRoute([file]);
507
523
  }
508
524
  };
509
525
  }
@@ -546,7 +562,8 @@ async function buildNativeBundle(options) {
546
562
  ".js": "jsx"
547
563
  },
548
564
  plugins: [...(entryFile ? [] : [nativeVirtualEntryPlugin(root, {
549
- dev
565
+ dev,
566
+ platform
550
567
  }).plugin]), ...getNativePlugins(root, platform, viteImportGlobPlugin, dev, assetsDest, void 0, sourcemap, userPlugins), nativeBundlePostProcessPlugin()],
551
568
  output: getNativeOutputOptions(prelude, sourcemap, minify)
552
569
  })).output.find(function (o) {
@@ -562,6 +579,7 @@ async function buildNativeBundle(options) {
562
579
  var VIRTUAL_NATIVE_ENTRY = "virtual:native-entry";
563
580
  function nativeVirtualEntryPlugin(root, opts) {
564
581
  var isDev = (opts === null || opts === void 0 ? void 0 : opts.dev) !== false;
582
+ var useDynamicRouteRegistry = opts.dynamicRoutes === true;
565
583
  var resolvedId = normalizePath(resolve(root, "__virtual-native-entry.tsx"));
566
584
  var entryConfig = globalThis.__vxrnNativeEntryConfig || {};
567
585
  var routerRoot = entryConfig.routerRoot || "app";
@@ -578,8 +596,7 @@ function nativeVirtualEntryPlugin(root, opts) {
578
596
  var routeGlobs = [`./${routerRoot}/**/*.tsx`, `./${routerRoot}/**/*.ts`, `!./${routerRoot}/**/*+api.*`, `!./${routerRoot}/**/*.test.*`, `!./${routerRoot}/**/*.d.ts`, `!./${routerRoot}/**/*.server.*`, `!./${routerRoot}/**/_middleware.*`, `!./${routerRoot}/**/*.web.*`, ...(entryConfig.ignoredRouteFiles || []).map(function (pattern) {
579
597
  return `!./${routerRoot}/${pattern}`;
580
598
  })];
581
- var entryCode = `
582
- ${isDev ? `
599
+ var refreshSetup = isDev ? `
583
600
  // react-refresh/runtime MUST initialize before React loads
584
601
  import RefreshRuntime from 'react-refresh/runtime';
585
602
  RefreshRuntime.injectIntoGlobalHook(globalThis);
@@ -588,22 +605,26 @@ globalThis.$RefreshReg$ = function(type, id) {
588
605
  RefreshRuntime.register(type, id);
589
606
  };
590
607
  globalThis.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
591
- ` : ""}
608
+ ` : "";
609
+ var entryCode = function () {
610
+ return `
611
+ ${refreshSetup}
592
612
  import * as ReactNativeInitializeCore from 'react-native/Libraries/Core/InitializeCore';
593
613
  import NativeWebSocket from 'react-native/Libraries/WebSocket/WebSocket';
614
+ import DevSettings from 'react-native/Libraries/Utilities/DevSettings';
594
615
  ${setupFileImport}
616
+ ${routeImports}
595
617
  import { createApp } from 'one';
596
618
 
597
619
  void ReactNativeInitializeCore;
598
620
  globalThis.WebSocket = NativeWebSocket;
621
+ globalThis.__VXRN_RELOAD_NATIVE_DEV_BUNDLE__ = function(reason) {
622
+ DevSettings.reload(reason);
623
+ };
599
624
 
600
- var _routes = import.meta.glob(${JSON.stringify(routeGlobs)}, { exhaustive: true });
601
- // fix route keys: One expects '/${routerRoot}/...' prefix but import.meta.glob returns './${routerRoot}/...'
602
- var routes = {};
603
- Object.keys(_routes).forEach(function(key) {
604
- var normalizedKey = key.replace(/^\\.\\//, '');
605
- routes['/' + normalizedKey] = _routes[key];
606
- });
625
+ // React Native reloads a dev bundle in the existing JS runtime. Advance One's
626
+ // route-cache version so a full reload cannot reuse the previous context.
627
+ globalThis.__vxrnVersion = (globalThis.__vxrnVersion || 0) + 1;
607
628
 
608
629
  createApp({
609
630
  routes: routes,
@@ -611,7 +632,10 @@ createApp({
611
632
  flags: ${JSON.stringify(flags)},
612
633
  linking: ${JSON.stringify(linking)},
613
634
  });
635
+
636
+ ${routeHmr}
614
637
  `;
638
+ };
615
639
  var routeRoot = resolve(root, routerRoot);
616
640
  var stripDot = function (pattern) {
617
641
  return pattern.replace(/^\.\//, "");
@@ -628,11 +652,77 @@ createApp({
628
652
  var relativeToRoot = normalizePath(relative(root, file));
629
653
  return micromatch.isMatch(relativeToRoot, includeGlobs) && !micromatch.isMatch(relativeToRoot, excludeGlobs);
630
654
  };
655
+ var scanFiles = function () {
656
+ var _statSync;
657
+ var files = /* @__PURE__ */new Set();
658
+ var walkRouteRoot = function (dir) {
659
+ var _iteratorNormalCompletion = true,
660
+ _didIteratorError = false,
661
+ _iteratorError = void 0;
662
+ try {
663
+ for (var _iterator = readdirSync(dir, {
664
+ withFileTypes: true
665
+ })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
666
+ var entry = _step.value;
667
+ var child = resolve(dir, entry.name);
668
+ if (entry.isDirectory()) walkRouteRoot(child);else if (isRouteFile(child)) files.add(normalizePath(child));
669
+ }
670
+ } catch (err) {
671
+ _didIteratorError = true;
672
+ _iteratorError = err;
673
+ } finally {
674
+ try {
675
+ if (!_iteratorNormalCompletion && _iterator.return != null) _iterator.return();
676
+ } finally {
677
+ if (_didIteratorError) throw _iteratorError;
678
+ }
679
+ }
680
+ };
681
+ if ((_statSync = statSync(routeRoot, {
682
+ throwIfNoEntry: false
683
+ })) === null || _statSync === void 0 ? void 0 : _statSync.isDirectory()) walkRouteRoot(routeRoot);
684
+ return files;
685
+ };
686
+ var registrySpecifier = `./node_modules/.vxrn/native-routes-${opts.platform}.mjs`;
687
+ var registryPath = resolve(root, registrySpecifier);
631
688
  var routes = {
632
689
  routeRoot,
633
690
  files: /* @__PURE__ */new Set(),
634
- isRouteFile
691
+ isRouteFile,
692
+ scanFiles,
693
+ updateFiles(files) {
694
+ routes.files = files;
695
+ if (!useDynamicRouteRegistry) return;
696
+ var source = `export const routes = {
697
+ ${[...files].sort().map(function (file) {
698
+ var routeKey = `/${normalizePath(relative(root, file))}`;
699
+ var importPath = normalizePath(relative(dirname(registryPath), file));
700
+ if (!importPath.startsWith(".")) importPath = `./${importPath}`;
701
+ return ` ${JSON.stringify(routeKey)}: () => import(${JSON.stringify(importPath)})`;
702
+ }).join(",\n")}
703
+ }
704
+ `;
705
+ mkdirSync(dirname(registryPath), {
706
+ recursive: true
707
+ });
708
+ if (!existsSync(registryPath) || readFileSync(registryPath, "utf8") !== source) writeFileSync(registryPath, source);
709
+ }
635
710
  };
711
+ routes.updateFiles(routes.scanFiles());
712
+ var routeImports = useDynamicRouteRegistry ? `import { routes } from ${JSON.stringify(registrySpecifier)};` : `var _routes = import.meta.glob(${JSON.stringify(routeGlobs)}, { exhaustive: true });
713
+ // fix route keys: One expects '/${routerRoot}/...' prefix but import.meta.glob returns './${routerRoot}/...'
714
+ var routes = {};
715
+ Object.keys(_routes).forEach(function(key) {
716
+ var normalizedKey = key.replace(/^\\.\\//, '');
717
+ routes['/' + normalizedKey] = _routes[key];
718
+ });`;
719
+ var routeHmr = useDynamicRouteRegistry ? `if (import.meta.hot) {
720
+ import.meta.hot.accept(${JSON.stringify(registrySpecifier)}, function(next) {
721
+ if (globalThis.__VXRN_UPDATE_NATIVE_ROUTES__) {
722
+ globalThis.__VXRN_UPDATE_NATIVE_ROUTES__(next.routes);
723
+ }
724
+ });
725
+ }` : "";
636
726
  return {
637
727
  routes,
638
728
  plugin: {
@@ -641,38 +731,8 @@ createApp({
641
731
  if (id === VIRTUAL_NATIVE_ENTRY) return resolvedId;
642
732
  },
643
733
  load(id) {
644
- var _this = this;
645
- var _statSync;
646
734
  if (id !== resolvedId) return;
647
- routes.files.clear();
648
- var walkRouteRoot = function (dir) {
649
- _this.addWatchFile(dir);
650
- var _iteratorNormalCompletion = true,
651
- _didIteratorError = false,
652
- _iteratorError = void 0;
653
- try {
654
- for (var _iterator = readdirSync(dir, {
655
- withFileTypes: true
656
- })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
657
- var entry = _step.value;
658
- var child = resolve(dir, entry.name);
659
- if (entry.isDirectory()) walkRouteRoot(child);else if (isRouteFile(child)) routes.files.add(normalizePath(child));
660
- }
661
- } catch (err) {
662
- _didIteratorError = true;
663
- _iteratorError = err;
664
- } finally {
665
- try {
666
- if (!_iteratorNormalCompletion && _iterator.return != null) _iterator.return();
667
- } finally {
668
- if (_didIteratorError) throw _iteratorError;
669
- }
670
- }
671
- };
672
- if ((_statSync = statSync(routeRoot, {
673
- throwIfNoEntry: false
674
- })) === null || _statSync === void 0 ? void 0 : _statSync.isDirectory()) walkRouteRoot(routeRoot);else this.addWatchFile(dirname(routeRoot));
675
- return entryCode;
735
+ return entryCode();
676
736
  }
677
737
  }
678
738
  };
@@ -760,6 +820,20 @@ export default HMRClient`,
760
820
  }
761
821
  };
762
822
  }
823
+ function reactNativeDedupePlugin(root) {
824
+ var reactNativeRoot;
825
+ return {
826
+ name: "vxrn:react-native-dedupe",
827
+ async resolveId(source, importer) {
828
+ if (source !== "react-native" && !source.startsWith("react-native/")) return;
829
+ reactNativeRoot || (reactNativeRoot = realpathSync(dirname(resolvePath("react-native/package.json", root))));
830
+ var subpath = source === "react-native" ? "index.js" : source.slice(13);
831
+ return this.resolve(normalizePath(resolve(reactNativeRoot, subpath)), importer, {
832
+ skipSelf: true
833
+ });
834
+ }
835
+ };
836
+ }
763
837
  function cssStubPlugin() {
764
838
  return {
765
839
  name: "vxrn:css-stub",
@@ -815,8 +889,6 @@ function vxrnCompilerPlugin(platform, dev) {
815
889
  return Array.isArray(x) && x[0] === "babel-plugin-react-compiler";
816
890
  })) !== null && _ref !== void 0 ? _ref : -1;
817
891
  if (compilerPluginIndex !== -1) {
818
- var _ref1;
819
- var _babelOptions_plugins_compilerPluginIndex_;
820
892
  if (useWorklets) {
821
893
  var prepared = compiler.prepareWorkletsForReactCompiler(id, curCode, sourceMaps);
822
894
  if (prepared) {
@@ -824,14 +896,16 @@ function vxrnCompilerPlugin(platform, dev) {
824
896
  if (prepared.map) intermediateMaps.push(prepared.map);
825
897
  }
826
898
  }
827
- var compilerTarget = (_ref1 = (_babelOptions_plugins_compilerPluginIndex_ = babelOptions.plugins[compilerPluginIndex][1]) === null || _babelOptions_plugins_compilerPluginIndex_ === void 0 ? void 0 : _babelOptions_plugins_compilerPluginIndex_.target) !== null && _ref1 !== void 0 ? _ref1 : "19";
828
- var compilerOut = await compiler.transformOxcReactCompiler(id, curCode, compilerTarget, sourceMaps);
829
- if (compilerOut === null || compilerOut === void 0 ? void 0 : compilerOut.code) {
830
- curCode = compilerOut.code;
831
- if (sourceMaps && compilerOut.map) intermediateMaps.push(compilerOut.map);
899
+ var compilerPluginOptions = babelOptions.plugins[compilerPluginIndex][1] || {};
900
+ if (!(compilerPluginOptions.compiler === "babel" || process.env.ONE_REACT_COMPILER === "babel" || process.env.VXRN_REACT_COMPILER === "babel")) {
901
+ var compilerOut = await compiler.transformOxcReactCompiler(id, curCode, compilerPluginOptions, sourceMaps);
902
+ if (compilerOut === null || compilerOut === void 0 ? void 0 : compilerOut.code) {
903
+ curCode = compilerOut.code;
904
+ if (sourceMaps && compilerOut.map) intermediateMaps.push(compilerOut.map);
905
+ }
906
+ babelOptions.plugins.splice(compilerPluginIndex, 1);
907
+ if (babelOptions.plugins.length === 0 && !babelOptions.configFile && !babelOptions.babelrc) babelOptions = null;
832
908
  }
833
- babelOptions.plugins.splice(compilerPluginIndex, 1);
834
- if (babelOptions.plugins.length === 0) babelOptions = null;
835
909
  }
836
910
  if (useWorklets) {
837
911
  var workletOut = await compiler.transformWorklets(id, curCode, sourceMaps, {
@@ -846,7 +920,7 @@ function vxrnCompilerPlugin(platform, dev) {
846
920
  babelOptions.plugins = babelOptions.plugins.filter(function (entry) {
847
921
  return !isWorkletPlugin(entry);
848
922
  });
849
- if (babelOptions.plugins.length === 0) babelOptions = null;
923
+ if (babelOptions.plugins.length === 0 && !babelOptions.configFile && !babelOptions.babelrc) babelOptions = null;
850
924
  }
851
925
  }
852
926
  if (!babelOptions && !needsRefresh) {
@@ -1466,11 +1540,13 @@ class ReactNativeDevRuntime extends BaseDevRuntime {
1466
1540
  }
1467
1541
  }
1468
1542
 
1469
- reload() {
1470
- var proxy = globalThis.__turboModuleProxy
1471
- ? globalThis.__turboModuleProxy('DevSettings')
1472
- : globalThis.nativeModuleProxy && globalThis.nativeModuleProxy.DevSettings;
1473
- if (proxy && proxy.reload) proxy.reload();
1543
+ reload(reason) {
1544
+ var reloadNativeBundle = globalThis.__VXRN_RELOAD_NATIVE_DEV_BUNDLE__;
1545
+ if (typeof reloadNativeBundle === 'function') {
1546
+ reloadNativeBundle(reason);
1547
+ return;
1548
+ }
1549
+ console.error('[vxrn HMR]: DevSettings.reload is unavailable');
1474
1550
  }
1475
1551
 
1476
1552
  setup(socket) {
@@ -1492,10 +1568,10 @@ class ReactNativeDevRuntime extends BaseDevRuntime {
1492
1568
  if (message.type === 'hmr:update') {
1493
1569
  // a patch that cannot be applied in place is the reload signal
1494
1570
  if (!runtime.applyHmrUpdate(message.code, message.changedIds, message.seq)) {
1495
- runtime.reload();
1571
+ runtime.reload('native HMR update could not be applied');
1496
1572
  }
1497
1573
  } else if (message.type === 'hmr:reload') {
1498
- runtime.reload();
1574
+ runtime.reload('native route map changed');
1499
1575
  }
1500
1576
  } catch (error) {
1501
1577
  console.error('[vxrn HMR]: failed to apply update', error);