vxrn 2.13.7 → 2.13.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/cli.mjs +3 -2
  2. package/dist/cli.mjs.map +1 -1
  3. package/dist/cli.native.js +5 -2
  4. package/dist/cli.native.js.map +1 -1
  5. package/dist/config/getBaseViteConfigOnly.mjs +3 -3
  6. package/dist/config/getBaseViteConfigOnly.mjs.map +1 -1
  7. package/dist/config/getBaseViteConfigOnly.native.js +3 -3
  8. package/dist/config/getBaseViteConfigOnly.native.js.map +1 -1
  9. package/dist/config/getOptionsFilled.mjs +24 -2
  10. package/dist/config/getOptionsFilled.mjs.map +1 -1
  11. package/dist/config/getOptionsFilled.native.js +25 -2
  12. package/dist/config/getOptionsFilled.native.js.map +1 -1
  13. package/dist/config/getServerOptionsFilled.mjs +119 -1
  14. package/dist/config/getServerOptionsFilled.mjs.map +1 -1
  15. package/dist/config/getServerOptionsFilled.native.js +137 -1
  16. package/dist/config/getServerOptionsFilled.native.js.map +1 -1
  17. package/dist/exports/build.mjs +6 -9
  18. package/dist/exports/build.mjs.map +1 -1
  19. package/dist/exports/build.native.js +6 -9
  20. package/dist/exports/build.native.js.map +1 -1
  21. package/dist/exports/dev.mjs +4 -6
  22. package/dist/exports/dev.mjs.map +1 -1
  23. package/dist/exports/dev.native.js +6 -6
  24. package/dist/exports/dev.native.js.map +1 -1
  25. package/dist/exports/prebuild.mjs +4 -4
  26. package/dist/exports/prebuild.mjs.map +1 -1
  27. package/dist/exports/prebuild.native.js +4 -4
  28. package/dist/exports/prebuild.native.js.map +1 -1
  29. package/dist/exports/prebuildWithoutExpo.mjs +95 -88
  30. package/dist/exports/prebuildWithoutExpo.mjs.map +1 -1
  31. package/dist/exports/prebuildWithoutExpo.native.js +95 -88
  32. package/dist/exports/prebuildWithoutExpo.native.js.map +1 -1
  33. package/dist/plugins/autoDepOptimizePlugin.mjs +3 -3
  34. package/dist/plugins/autoDepOptimizePlugin.mjs.map +1 -1
  35. package/dist/plugins/autoDepOptimizePlugin.native.js +3 -3
  36. package/dist/plugins/autoDepOptimizePlugin.native.js.map +1 -1
  37. package/dist/plugins/reactNativeDevAssetPlugin.mjs +4 -4
  38. package/dist/plugins/reactNativeDevAssetPlugin.mjs.map +1 -1
  39. package/dist/plugins/reactNativeDevAssetPlugin.native.js +4 -4
  40. package/dist/plugins/reactNativeDevAssetPlugin.native.js.map +1 -1
  41. package/dist/rn-commands/bundle/buildBundle.mjs +18 -5
  42. package/dist/rn-commands/bundle/buildBundle.mjs.map +1 -1
  43. package/dist/rn-commands/bundle/buildBundle.native.js +18 -5
  44. package/dist/rn-commands/bundle/buildBundle.native.js.map +1 -1
  45. package/dist/user-interface/index.mjs +1 -1
  46. package/dist/user-interface/index.mjs.map +1 -1
  47. package/dist/user-interface/index.native.js +1 -1
  48. package/dist/user-interface/index.native.js.map +1 -1
  49. package/dist/utils/env-editor.mjs +198 -0
  50. package/dist/utils/env-editor.mjs.map +1 -0
  51. package/dist/utils/env-editor.native.js +266 -0
  52. package/dist/utils/env-editor.native.js.map +1 -0
  53. package/dist/utils/fs.mjs +48 -0
  54. package/dist/utils/fs.mjs.map +1 -0
  55. package/dist/utils/fs.native.js +48 -0
  56. package/dist/utils/fs.native.js.map +1 -0
  57. package/dist/utils/getVitePath.mjs +2 -2
  58. package/dist/utils/getVitePath.mjs.map +1 -1
  59. package/dist/utils/getVitePath.native.js +2 -2
  60. package/dist/utils/getVitePath.native.js.map +1 -1
  61. package/dist/utils/patches.mjs +38 -29
  62. package/dist/utils/patches.mjs.map +1 -1
  63. package/dist/utils/patches.native.js +38 -29
  64. package/dist/utils/patches.native.js.map +1 -1
  65. package/dist/utils/scanDepsToOptimize.mjs +12 -11
  66. package/dist/utils/scanDepsToOptimize.mjs.map +1 -1
  67. package/dist/utils/scanDepsToOptimize.native.js +12 -11
  68. package/dist/utils/scanDepsToOptimize.native.js.map +1 -1
  69. package/dist/utils/state.mjs +5 -5
  70. package/dist/utils/state.mjs.map +1 -1
  71. package/dist/utils/state.native.js +5 -5
  72. package/dist/utils/state.native.js.map +1 -1
  73. package/dist/utils/utils.mjs +4 -3
  74. package/dist/utils/utils.mjs.map +1 -1
  75. package/dist/utils/utils.native.js +4 -3
  76. package/dist/utils/utils.native.js.map +1 -1
  77. package/package.json +12 -18
  78. package/src/cli.ts +5 -4
  79. package/src/config/getBaseViteConfigOnly.ts +3 -3
  80. package/src/config/getOptionsFilled.ts +35 -2
  81. package/src/config/getServerOptionsFilled.test.ts +37 -0
  82. package/src/config/getServerOptionsFilled.ts +57 -1
  83. package/src/exports/build.ts +5 -12
  84. package/src/exports/clean.test.ts +1 -1
  85. package/src/exports/dev.ts +5 -6
  86. package/src/exports/prebuild.ts +4 -4
  87. package/src/exports/prebuildWithoutExpo.ts +102 -89
  88. package/src/plugins/autoDepOptimizePlugin.ts +3 -3
  89. package/src/plugins/reactNativeDevAssetPlugin.ts +4 -4
  90. package/src/rn-commands/bundle/buildBundle.ts +15 -5
  91. package/src/user-interface/index.ts +1 -1
  92. package/src/utils/env-editor.LICENSE +9 -0
  93. package/src/utils/env-editor.ts +214 -0
  94. package/src/utils/fs.ts +59 -0
  95. package/src/utils/getVitePath.ts +2 -2
  96. package/src/utils/patches.test.ts +36 -36
  97. package/src/utils/patches.ts +39 -27
  98. package/src/utils/scanDepsToOptimize.test.ts +2 -2
  99. package/src/utils/scanDepsToOptimize.ts +6 -5
  100. package/src/utils/state.ts +5 -7
  101. package/src/utils/utils.ts +5 -5
  102. package/types/config/getOptionsFilled.d.ts +9 -2
  103. package/types/config/getOptionsFilled.d.ts.map +1 -1
  104. package/types/config/getServerOptionsFilled.d.ts.map +1 -1
  105. package/types/exports/build.d.ts +1 -1
  106. package/types/exports/build.d.ts.map +1 -1
  107. package/types/exports/dev.d.ts.map +1 -1
  108. package/types/exports/prebuildWithoutExpo.d.ts.map +1 -1
  109. package/types/rn-commands/bundle/buildBundle.d.ts.map +1 -1
  110. package/types/user-interface/index.d.ts.map +1 -1
  111. package/types/utils/env-editor.d.ts +9 -0
  112. package/types/utils/env-editor.d.ts.map +1 -0
  113. package/types/utils/fs.d.ts +9 -0
  114. package/types/utils/fs.d.ts.map +1 -0
  115. package/types/utils/patches.d.ts.map +1 -1
  116. package/types/utils/scanDepsToOptimize.d.ts.map +1 -1
  117. package/types/utils/state.d.ts.map +1 -1
  118. package/types/utils/utils.d.ts +2 -2
  119. package/types/utils/utils.d.ts.map +1 -1
@@ -1,5 +1,18 @@
1
1
  import { execFileSync } from 'node:child_process'
2
2
  import { createHash } from 'node:crypto'
3
+ import {
4
+ copyFileSync,
5
+ existsSync,
6
+ lstatSync,
7
+ mkdirSync,
8
+ readdirSync,
9
+ readFileSync,
10
+ realpathSync,
11
+ rmSync,
12
+ statSync,
13
+ symlinkSync,
14
+ writeFileSync,
15
+ } from 'node:fs'
3
16
  import module from 'node:module'
4
17
  import path from 'node:path'
5
18
  import { pathToFileURL } from 'node:url'
@@ -13,8 +26,8 @@ import {
13
26
  type NativeAppManifest,
14
27
  type PlistValue,
15
28
  } from '@vxrn/utils/nativeAppManifest'
16
- import FSExtra from 'fs-extra'
17
29
  import sharp from 'sharp'
30
+ import { readJSONSync } from '../utils/fs'
18
31
  import { swiftPackageDirectories } from '../utils/swiftPackageId'
19
32
 
20
33
  type NativeProjectPatches = {
@@ -298,7 +311,7 @@ ${imports.join('\n')}
298
311
  }
299
312
 
300
313
  function generateOneBridgingHeader(dest: string, app: NativeAppManifest): void {
301
- FSExtra.writeFileSync(
314
+ writeFileSync(
302
315
  path.join(dest, app.name, ONE_BRIDGING_HEADER_NAME),
303
316
  renderOneBridgingHeader(app)
304
317
  )
@@ -488,11 +501,11 @@ function copyAppResources({
488
501
  }
489
502
  for (const [file, target] of copies) {
490
503
  const source = path.resolve(root, file)
491
- if (!FSExtra.existsSync(source)) {
504
+ if (!existsSync(source)) {
492
505
  throw new Error(`[vxrn] native.app names ${file}, which does not exist`)
493
506
  }
494
- FSExtra.mkdirSync(path.dirname(target), { recursive: true })
495
- FSExtra.copyFileSync(source, target)
507
+ mkdirSync(path.dirname(target), { recursive: true })
508
+ copyFileSync(source, target)
496
509
  }
497
510
  }
498
511
 
@@ -801,7 +814,7 @@ function generateSceneDelegate(args: {
801
814
  }): void {
802
815
  const { dest, platform, app } = args
803
816
  if (platform !== 'ios') return
804
- FSExtra.writeFileSync(
817
+ writeFileSync(
805
818
  path.join(dest, app.name, 'SceneDelegate.swift'),
806
819
  renderSceneDelegateSwift(app.name)
807
820
  )
@@ -809,7 +822,7 @@ function generateSceneDelegate(args: {
809
822
  // widgets the app gets its own file when it has any entitlement.
810
823
  const entitlements = appEntitlements(app)
811
824
  if (Object.keys(entitlements).length && !app.ios?.widgets) {
812
- FSExtra.writeFileSync(
825
+ writeFileSync(
813
826
  path.join(dest, app.name, `${app.name}.entitlements`),
814
827
  renderEntitlements(entitlements)
815
828
  )
@@ -818,7 +831,7 @@ function generateSceneDelegate(args: {
818
831
 
819
832
  function generateIosAppIntents(dest: string, platform: 'ios' | 'android', app: NativeAppManifest): void {
820
833
  if (platform !== 'ios' || !app.ios?.appIntents) return
821
- FSExtra.writeFileSync(
834
+ writeFileSync(
822
835
  path.join(dest, app.name, 'OneAppIntents.swift'),
823
836
  renderIosAppIntentsSwift(app.ios.appIntents.actions)
824
837
  )
@@ -829,17 +842,17 @@ function generateIosWidgets(dest: string, app: NativeAppManifest): void {
829
842
  if (!widgets) return
830
843
  const appDir = path.join(dest, app.name)
831
844
  const extensionDir = path.join(dest, 'OneWidgets')
832
- FSExtra.mkdirSync(extensionDir, { recursive: true })
845
+ mkdirSync(extensionDir, { recursive: true })
833
846
  const entitlements = `<?xml version="1.0" encoding="UTF-8"?>
834
847
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
835
848
  <plist version="1.0"><dict><key>com.apple.security.application-groups</key><array><string>${escapeXml(widgets.appGroup)}</string></array></dict></plist>
836
849
  `
837
- FSExtra.writeFileSync(
850
+ writeFileSync(
838
851
  path.join(appDir, 'OneAppWidgets.entitlements'),
839
852
  renderEntitlements(appEntitlements(app))
840
853
  )
841
- FSExtra.writeFileSync(path.join(extensionDir, 'OneWidgets.entitlements'), entitlements)
842
- FSExtra.writeFileSync(
854
+ writeFileSync(path.join(extensionDir, 'OneWidgets.entitlements'), entitlements)
855
+ writeFileSync(
843
856
  path.join(extensionDir, 'WidgetInfo.plist'),
844
857
  `<?xml version="1.0" encoding="UTF-8"?>
845
858
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -857,7 +870,7 @@ function generateIosWidgets(dest: string, app: NativeAppManifest): void {
857
870
  </dict></plist>
858
871
  `
859
872
  )
860
- FSExtra.writeFileSync(
873
+ writeFileSync(
861
874
  path.join(appDir, 'OneWidgetContract.swift'),
862
875
  `import Foundation
863
876
  import ActivityKit
@@ -885,7 +898,7 @@ enum OneWidgetContract {
885
898
  }
886
899
  `
887
900
  )
888
- FSExtra.writeFileSync(
901
+ writeFileSync(
889
902
  path.join(extensionDir, 'OneWidget.swift'),
890
903
  `import SwiftUI
891
904
  import WidgetKit
@@ -1176,7 +1189,7 @@ struct OneWidgetsBundle: WidgetBundle {
1176
1189
  }
1177
1190
  `
1178
1191
  )
1179
- FSExtra.writeFileSync(
1192
+ writeFileSync(
1180
1193
  path.join(appDir, 'OneWidgetsBridge.m'),
1181
1194
  `#import <React/RCTBridgeModule.h>
1182
1195
  #import <React/RCTEventEmitter.h>
@@ -1193,7 +1206,7 @@ RCT_EXTERN_METHOD(pushToken:(NSString *)identifier resolver:(RCTPromiseResolveBl
1193
1206
  @end
1194
1207
  `
1195
1208
  )
1196
- FSExtra.writeFileSync(
1209
+ writeFileSync(
1197
1210
  path.join(appDir, 'OneWidgetsBridge.swift'),
1198
1211
  `import Foundation
1199
1212
  import React
@@ -1387,7 +1400,7 @@ async function writeAppearanceIcon(args: {
1387
1400
  const variantSource = (variant: { source?: string } | undefined) => {
1388
1401
  if (!variant?.source) return source
1389
1402
  const resolved = path.resolve(root, variant.source)
1390
- if (!FSExtra.existsSync(resolved)) {
1403
+ if (!existsSync(resolved)) {
1391
1404
  throw new Error(`[vxrn] native.app icon appearance source does not exist: ${resolved}`)
1392
1405
  }
1393
1406
  return resolved
@@ -1421,7 +1434,7 @@ async function writeAppearanceIcon(args: {
1421
1434
  )
1422
1435
  images.push(entry('icon-1024-tinted.png', 'tinted'))
1423
1436
  }
1424
- FSExtra.writeFileSync(
1437
+ writeFileSync(
1425
1438
  path.join(iconDir, 'Contents.json'),
1426
1439
  `${JSON.stringify({ images, info: { author: 'xcode', version: 1 } }, null, 2)}\n`
1427
1440
  )
@@ -1441,14 +1454,14 @@ async function generateAppIcons(args: {
1441
1454
  const template: {
1442
1455
  images: Array<{ idiom: string; scale: string; size: string; filename?: string }>
1443
1456
  info: { author: string; version: number }
1444
- } = JSON.parse(FSExtra.readFileSync(path.join(assetsDir, 'AppIcon.appiconset', 'Contents.json'), 'utf8'))
1457
+ } = JSON.parse(readFileSync(path.join(assetsDir, 'AppIcon.appiconset', 'Contents.json'), 'utf8'))
1445
1458
  const icons: Array<[string, NativeAppIcon]> = [
1446
1459
  ['AppIcon', app.icon],
1447
1460
  ...Object.entries(app.alternateIcons ?? {}),
1448
1461
  ]
1449
1462
  for (const [name, icon] of icons) {
1450
1463
  const source = path.resolve(root, icon.source)
1451
- if (!FSExtra.existsSync(source)) {
1464
+ if (!existsSync(source)) {
1452
1465
  throw new Error(`[vxrn] native.app icon source does not exist: ${source}`)
1453
1466
  }
1454
1467
  const metadata = await sharp(source).metadata()
@@ -1456,7 +1469,7 @@ async function generateAppIcons(args: {
1456
1469
  throw new Error(`[vxrn] native.app icon source must be a square image at least 1024px wide: ${source}`)
1457
1470
  }
1458
1471
  const iconDir = path.join(assetsDir, `${name}.appiconset`)
1459
- FSExtra.mkdirSync(iconDir, { recursive: true })
1472
+ mkdirSync(iconDir, { recursive: true })
1460
1473
  if (icon.dark || icon.tinted) {
1461
1474
  await writeAppearanceIcon({ root, iconDir, icon, source })
1462
1475
  continue
@@ -1483,13 +1496,13 @@ async function generateAppIcons(args: {
1483
1496
  .png()
1484
1497
  .toFile(path.join(iconDir, filename))
1485
1498
  }
1486
- FSExtra.writeFileSync(path.join(iconDir, 'Contents.json'), `${JSON.stringify(contents, null, 2)}\n`)
1499
+ writeFileSync(path.join(iconDir, 'Contents.json'), `${JSON.stringify(contents, null, 2)}\n`)
1487
1500
  }
1488
1501
  return
1489
1502
  }
1490
1503
 
1491
1504
  const source = path.resolve(root, app.icon.source)
1492
- if (!FSExtra.existsSync(source)) {
1505
+ if (!existsSync(source)) {
1493
1506
  throw new Error(`[vxrn] native.app.icon source does not exist: ${source}`)
1494
1507
  }
1495
1508
  const metadata = await sharp(source).metadata()
@@ -1504,7 +1517,7 @@ async function generateAppIcons(args: {
1504
1517
  Object.entries(app.alternateIcons ?? {}).map(
1505
1518
  async ([name, icon]): Promise<[string, NativeAppIcon, string]> => {
1506
1519
  const alternateSource = path.resolve(root, icon.source)
1507
- if (!FSExtra.existsSync(alternateSource)) {
1520
+ if (!existsSync(alternateSource)) {
1508
1521
  throw new Error(`[vxrn] native.app icon source does not exist: ${alternateSource}`)
1509
1522
  }
1510
1523
  const alternate = await sharp(alternateSource).metadata()
@@ -1597,8 +1610,8 @@ function generateAndroidIconForwarder(dest: string, app: NativeAppManifest): voi
1597
1610
  ...packageName.split('.'),
1598
1611
  'AppIconLauncherActivity.kt'
1599
1612
  )
1600
- FSExtra.mkdirSync(path.dirname(file), { recursive: true })
1601
- FSExtra.writeFileSync(
1613
+ mkdirSync(path.dirname(file), { recursive: true })
1614
+ writeFileSync(
1602
1615
  file,
1603
1616
  `package ${packageName}
1604
1617
 
@@ -1646,19 +1659,19 @@ async function generateAppIconPreviews(args: {
1646
1659
  const resources = appIconPreviewResources(name)
1647
1660
  if (platform === 'android') {
1648
1661
  const dir = path.join(dest, 'app', 'src', 'main', 'res', 'drawable-nodpi')
1649
- FSExtra.mkdirSync(dir, { recursive: true })
1662
+ mkdirSync(dir, { recursive: true })
1650
1663
  await preview(3).toFile(path.join(dir, `${resources.android}.png`))
1651
1664
  continue
1652
1665
  }
1653
1666
  const dir = path.join(dest, app.name, 'Images.xcassets', `${resources.ios}.imageset`)
1654
- FSExtra.mkdirSync(dir, { recursive: true })
1667
+ mkdirSync(dir, { recursive: true })
1655
1668
  const images: Array<Record<string, string>> = []
1656
1669
  for (const scale of [1, 2, 3]) {
1657
1670
  const filename = `preview@${scale}x.png`
1658
1671
  await preview(scale).toFile(path.join(dir, filename))
1659
1672
  images.push({ filename, idiom: 'universal', scale: `${scale}x` })
1660
1673
  }
1661
- FSExtra.writeFileSync(
1674
+ writeFileSync(
1662
1675
  path.join(dir, 'Contents.json'),
1663
1676
  `${JSON.stringify({ images, info: { author: 'xcode', version: 1 } }, null, 2)}\n`
1664
1677
  )
@@ -1687,7 +1700,7 @@ async function generateAdaptiveIcon(args: {
1687
1700
  for (const [layer, file] of Object.entries(layers)) {
1688
1701
  if (!file) continue
1689
1702
  const source = path.resolve(root, file)
1690
- if (!FSExtra.existsSync(source)) {
1703
+ if (!existsSync(source)) {
1691
1704
  throw new Error(`[vxrn] native.app.android.adaptiveIcon.${layer} does not exist: ${source}`)
1692
1705
  }
1693
1706
  for (const [density, multiplier] of Object.entries(ANDROID_DENSITIES)) {
@@ -1700,7 +1713,7 @@ async function generateAdaptiveIcon(args: {
1700
1713
  }
1701
1714
  }
1702
1715
  if (!adaptiveIcon.background) {
1703
- FSExtra.writeFileSync(
1716
+ writeFileSync(
1704
1717
  path.join(res, 'values', 'ic_launcher_background.xml'),
1705
1718
  `<?xml version="1.0" encoding="utf-8"?>
1706
1719
  <resources>
@@ -1716,9 +1729,9 @@ async function generateAdaptiveIcon(args: {
1716
1729
  ${adaptiveIcon.monochrome ? ' <monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>\n' : ''}</adaptive-icon>
1717
1730
  `
1718
1731
  const anydpi = path.join(res, 'mipmap-anydpi-v26')
1719
- FSExtra.mkdirSync(anydpi, { recursive: true })
1732
+ mkdirSync(anydpi, { recursive: true })
1720
1733
  for (const filename of ['ic_launcher.xml', 'ic_launcher_round.xml']) {
1721
- FSExtra.writeFileSync(path.join(anydpi, filename), adaptiveXml)
1734
+ writeFileSync(path.join(anydpi, filename), adaptiveXml)
1722
1735
  }
1723
1736
  }
1724
1737
 
@@ -1767,8 +1780,8 @@ function generateAccentColor(args: { dest: string; app: NativeAppManifest }): vo
1767
1780
  const accent = args.app.ios?.accentColor
1768
1781
  if (!accent) return
1769
1782
  const colorDir = path.join(args.dest, args.app.name, 'Images.xcassets', 'AccentColor.colorset')
1770
- FSExtra.mkdirSync(colorDir, { recursive: true })
1771
- FSExtra.writeFileSync(
1783
+ mkdirSync(colorDir, { recursive: true })
1784
+ writeFileSync(
1772
1785
  path.join(colorDir, 'Contents.json'),
1773
1786
  xcodeColorSet(accent.light, accent.dark)
1774
1787
  )
@@ -1787,7 +1800,7 @@ async function generateSplashScreen(args: {
1787
1800
  const cover = app.splash.resizeMode === 'cover'
1788
1801
  const prepareArtwork = async (sourcePath: string, backgroundColor: string) => {
1789
1802
  const source = path.resolve(root, sourcePath)
1790
- if (!FSExtra.existsSync(source)) {
1803
+ if (!existsSync(source)) {
1791
1804
  throw new Error(`[vxrn] native.app.splash source does not exist: ${source}`)
1792
1805
  }
1793
1806
  // a vector source rasterizes at the density its largest use needs: the
@@ -1822,7 +1835,7 @@ async function generateSplashScreen(args: {
1822
1835
  // launch surface scales it (aspect-fill on ios, fill on android).
1823
1836
  const readBackground = (sourcePath: string) => {
1824
1837
  const source = path.resolve(root, sourcePath)
1825
- if (!FSExtra.existsSync(source)) {
1838
+ if (!existsSync(source)) {
1826
1839
  throw new Error(`[vxrn] native.app.splash backgroundImage does not exist: ${source}`)
1827
1840
  }
1828
1841
  return sharp(source).rotate().png().toBuffer({ resolveWithObject: true })
@@ -1841,7 +1854,7 @@ async function generateSplashScreen(args: {
1841
1854
  pointWidth: number | undefined
1842
1855
  ) => {
1843
1856
  const dir = path.join(assets, `${name}.imageset`)
1844
- FSExtra.mkdirSync(dir, { recursive: true })
1857
+ mkdirSync(dir, { recursive: true })
1845
1858
  const scales = pointWidth === undefined ? [1] : [1, 2, 3]
1846
1859
  const images: Array<Record<string, unknown>> = []
1847
1860
  for (const [variant, suffix, appearances] of [
@@ -1866,7 +1879,7 @@ async function generateSplashScreen(args: {
1866
1879
  })
1867
1880
  }
1868
1881
  }
1869
- FSExtra.writeFileSync(
1882
+ writeFileSync(
1870
1883
  path.join(dir, 'Contents.json'),
1871
1884
  `${JSON.stringify({ images, info: { author: 'xcode', version: 1 } }, null, 2)}\n`
1872
1885
  )
@@ -1883,13 +1896,13 @@ async function generateSplashScreen(args: {
1883
1896
  }
1884
1897
  // the launch background is a named color so a dark launch gets its own.
1885
1898
  const colorDir = path.join(assets, 'SplashBackground.colorset')
1886
- FSExtra.mkdirSync(colorDir, { recursive: true })
1887
- FSExtra.writeFileSync(
1899
+ mkdirSync(colorDir, { recursive: true })
1900
+ writeFileSync(
1888
1901
  path.join(colorDir, 'Contents.json'),
1889
1902
  xcodeColorSet(app.splash.backgroundColor, dark?.backgroundColor)
1890
1903
  )
1891
1904
  const { red, green, blue } = srgb(app.splash.backgroundColor)
1892
- FSExtra.writeFileSync(
1905
+ writeFileSync(
1893
1906
  path.join(appDir, 'LaunchScreen.storyboard'),
1894
1907
  `<?xml version="1.0" encoding="UTF-8"?>
1895
1908
  <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="launch-controller">
@@ -1974,7 +1987,7 @@ ${
1974
1987
  .png()
1975
1988
  .toBuffer()
1976
1989
  const drawableDensity = path.join(mainRes, `${drawablePrefix}-${density}`)
1977
- FSExtra.mkdirSync(drawableDensity, { recursive: true })
1990
+ mkdirSync(drawableDensity, { recursive: true })
1978
1991
  await sharp({
1979
1992
  create: {
1980
1993
  width: canvasSize,
@@ -2007,18 +2020,18 @@ ${
2007
2020
  : undefined
2008
2021
  if (background) {
2009
2022
  const nodpi = path.join(mainRes, 'drawable-nodpi')
2010
- FSExtra.mkdirSync(nodpi, { recursive: true })
2011
- FSExtra.writeFileSync(path.join(nodpi, 'splash_background.png'), background.data)
2023
+ mkdirSync(nodpi, { recursive: true })
2024
+ writeFileSync(path.join(nodpi, 'splash_background.png'), background.data)
2012
2025
  if (darkBackground) {
2013
2026
  const nightNodpi = path.join(mainRes, 'drawable-night-nodpi')
2014
- FSExtra.mkdirSync(nightNodpi, { recursive: true })
2015
- FSExtra.writeFileSync(
2027
+ mkdirSync(nightNodpi, { recursive: true })
2028
+ writeFileSync(
2016
2029
  path.join(nightNodpi, 'splash_background.png'),
2017
2030
  darkBackground
2018
2031
  )
2019
2032
  }
2020
2033
  }
2021
- FSExtra.writeFileSync(
2034
+ writeFileSync(
2022
2035
  path.join(drawable, 'launch_screen.xml'),
2023
2036
  `<?xml version="1.0" encoding="utf-8"?>
2024
2037
  <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
@@ -2036,7 +2049,7 @@ ${
2036
2049
  </layer-list>
2037
2050
  `
2038
2051
  )
2039
- FSExtra.writeFileSync(
2052
+ writeFileSync(
2040
2053
  path.join(mainRes, 'values', 'colors.xml'),
2041
2054
  `<?xml version="1.0" encoding="utf-8"?>
2042
2055
  <resources>
@@ -2045,8 +2058,8 @@ ${
2045
2058
  `
2046
2059
  )
2047
2060
  if (dark) {
2048
- FSExtra.mkdirSync(path.join(mainRes, 'values-night'), { recursive: true })
2049
- FSExtra.writeFileSync(
2061
+ mkdirSync(path.join(mainRes, 'values-night'), { recursive: true })
2062
+ writeFileSync(
2050
2063
  path.join(mainRes, 'values-night', 'colors.xml'),
2051
2064
  `<?xml version="1.0" encoding="utf-8"?>
2052
2065
  <resources>
@@ -2056,19 +2069,19 @@ ${
2056
2069
  )
2057
2070
  }
2058
2071
  const stylesPath = path.join(mainRes, 'values', 'styles.xml')
2059
- const styles = FSExtra.readFileSync(stylesPath, 'utf8').replace(
2072
+ const styles = readFileSync(stylesPath, 'utf8').replace(
2060
2073
  ' <!-- Customize your theme here. -->',
2061
2074
  ' <item name="android:windowBackground">@drawable/launch_screen</item>'
2062
2075
  )
2063
- FSExtra.writeFileSync(stylesPath, styles)
2076
+ writeFileSync(stylesPath, styles)
2064
2077
  const stylesV31 = path.join(mainRes, 'values-v31')
2065
- FSExtra.mkdirSync(stylesV31, { recursive: true })
2078
+ mkdirSync(stylesV31, { recursive: true })
2066
2079
  // a values-v31 AppTheme replaces the base one on API 31+, so it is the base
2067
2080
  // theme (parent included) plus the system splash items, never a bare style.
2068
2081
  if (!styles.includes('</style>')) {
2069
2082
  throw new Error('[vxrn] prebuild template styles.xml lost its AppTheme </style> anchor')
2070
2083
  }
2071
- FSExtra.writeFileSync(
2084
+ writeFileSync(
2072
2085
  path.join(stylesV31, 'styles.xml'),
2073
2086
  styles.replace(
2074
2087
  '</style>',
@@ -2901,17 +2914,17 @@ export const generateForPlatform = async (
2901
2914
  const nitroWebImage = platform === 'ios' && nativeProjectPatches.hasNitroWebImage(root)
2902
2915
 
2903
2916
  // owned output: regenerate from the manifest so reruns reproduce bytes.
2904
- FSExtra.removeSync(dest)
2917
+ rmSync(dest, { recursive: true, force: true })
2905
2918
 
2906
2919
  for (const absoluteSrc of files) {
2907
2920
  const relativeFilePath = path.relative(src, absoluteSrc)
2908
- const stat = FSExtra.lstatSync(absoluteSrc)
2921
+ const stat = lstatSync(absoluteSrc)
2909
2922
  if (stat.isDirectory()) continue
2910
2923
 
2911
2924
  const extension = path.extname(absoluteSrc)
2912
2925
  const raw = ['.png', '.jar', '.keystore'].includes(extension)
2913
2926
  ? null
2914
- : FSExtra.readFileSync(absoluteSrc, 'utf8')
2927
+ : readFileSync(absoluteSrc, 'utf8')
2915
2928
  const { destRelativePath, content } = renderPrebuildFile({
2916
2929
  relativePath: relativeFilePath,
2917
2930
  content: raw,
@@ -2920,15 +2933,15 @@ export const generateForPlatform = async (
2920
2933
  nitroWebImage,
2921
2934
  })
2922
2935
  const destPath = path.resolve(dest, destRelativePath)
2923
- FSExtra.mkdirSync(path.dirname(destPath), { recursive: true })
2936
+ mkdirSync(path.dirname(destPath), { recursive: true })
2924
2937
 
2925
2938
  console.info('copying', '"' + absoluteSrc + '"', 'to', '"' + destPath + '"')
2926
2939
 
2927
2940
  if (content === null) {
2928
- FSExtra.copyFileSync(absoluteSrc, destPath)
2941
+ copyFileSync(absoluteSrc, destPath)
2929
2942
  continue
2930
2943
  }
2931
- FSExtra.writeFileSync(destPath, content, {
2944
+ writeFileSync(destPath, content, {
2932
2945
  encoding: 'utf8',
2933
2946
  mode: stat.mode,
2934
2947
  })
@@ -2963,14 +2976,14 @@ const KOTLIN_IMPORT_ARTIFACTS = [
2963
2976
 
2964
2977
  function kotlinSourceImports(dir: string): Set<string> {
2965
2978
  const imports = new Set<string>()
2966
- if (!FSExtra.existsSync(dir)) return imports
2979
+ if (!existsSync(dir)) return imports
2967
2980
  const visit = (entry: string) => {
2968
- if (FSExtra.statSync(entry).isDirectory()) {
2969
- for (const child of FSExtra.readdirSync(entry)) visit(path.join(entry, child))
2981
+ if (statSync(entry).isDirectory()) {
2982
+ for (const child of readdirSync(entry)) visit(path.join(entry, child))
2970
2983
  return
2971
2984
  }
2972
2985
  if (!entry.endsWith('.kt')) return
2973
- for (const line of FSExtra.readFileSync(entry, 'utf8').split('\n')) {
2986
+ for (const line of readFileSync(entry, 'utf8').split('\n')) {
2974
2987
  const match = /^\s*import\s+([A-Za-z0-9_.]+)/.exec(line)
2975
2988
  if (match) imports.add(match[1])
2976
2989
  }
@@ -2981,8 +2994,8 @@ function kotlinSourceImports(dir: string): Set<string> {
2981
2994
 
2982
2995
  export function enableAppComposeIntegration(dest: string) {
2983
2996
  const rootBuildGradlePath = path.join(dest, 'build.gradle')
2984
- if (FSExtra.existsSync(rootBuildGradlePath)) {
2985
- let content = FSExtra.readFileSync(rootBuildGradlePath, 'utf8')
2997
+ if (existsSync(rootBuildGradlePath)) {
2998
+ let content = readFileSync(rootBuildGradlePath, 'utf8')
2986
2999
  const composePluginClasspath =
2987
3000
  ' classpath("org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:$kotlinVersion")'
2988
3001
  if (!content.includes('org.jetbrains.kotlin.plugin.compose')) {
@@ -2990,13 +3003,13 @@ export function enableAppComposeIntegration(dest: string) {
2990
3003
  ? 'classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")'
2991
3004
  : 'classpath "org.jetbrains.kotlin:kotlin-gradle-plugin"'
2992
3005
  content = insertAfterLine(content, anchor, composePluginClasspath)
2993
- FSExtra.writeFileSync(rootBuildGradlePath, content, 'utf8')
3006
+ writeFileSync(rootBuildGradlePath, content, 'utf8')
2994
3007
  }
2995
3008
  }
2996
3009
 
2997
3010
  const appBuildGradlePath = path.join(dest, 'app/build.gradle')
2998
- if (FSExtra.existsSync(appBuildGradlePath)) {
2999
- let content = FSExtra.readFileSync(appBuildGradlePath, 'utf8')
3011
+ if (existsSync(appBuildGradlePath)) {
3012
+ let content = readFileSync(appBuildGradlePath, 'utf8')
3000
3013
  if (!content.includes('org.jetbrains.kotlin.plugin.compose')) {
3001
3014
  const pluginAnchor = content.includes('apply plugin: "org.jetbrains.kotlin.android"')
3002
3015
  ? 'apply plugin: "org.jetbrains.kotlin.android"'
@@ -3054,7 +3067,7 @@ export function enableAppComposeIntegration(dest: string) {
3054
3067
  ].join('\n')
3055
3068
  )
3056
3069
  }
3057
- FSExtra.writeFileSync(appBuildGradlePath, content, 'utf8')
3070
+ writeFileSync(appBuildGradlePath, content, 'utf8')
3058
3071
  }
3059
3072
  }
3060
3073
 
@@ -3065,8 +3078,8 @@ export async function generateKotlinSources({ root, dest }: { root: string; dest
3065
3078
  // breaks :app:compileDebugKotlin when two preserved copies declare one class.
3066
3079
  const skip = new Set(['node_modules', 'ios', 'android', 'dist', 'types', 'build', 'tests', '__tests__', 'scripts', 'evidence'])
3067
3080
  const sources: string[] = []
3068
- const manifest = FSExtra.existsSync(path.join(root, 'package.json'))
3069
- ? FSExtra.readJsonSync(path.join(root, 'package.json'))
3081
+ const manifest = existsSync(path.join(root, 'package.json'))
3082
+ ? readJSONSync(path.join(root, 'package.json'))
3070
3083
  : {}
3071
3084
  const workspacePatterns: string[] = Array.isArray(manifest.workspaces)
3072
3085
  ? manifest.workspaces
@@ -3079,8 +3092,8 @@ export async function generateKotlinSources({ root, dest }: { root: string; dest
3079
3092
  const collect = (dir: string) => {
3080
3093
  // declared workspace packages belong to this build; other nested packages
3081
3094
  // own their sources and fixtures.
3082
- if (dir !== root && FSExtra.existsSync(path.join(dir, 'package.json')) && !workspaceRoots.has(dir)) return
3083
- for (const entry of FSExtra.readdirSync(dir, { withFileTypes: true })) {
3095
+ if (dir !== root && existsSync(path.join(dir, 'package.json')) && !workspaceRoots.has(dir)) return
3096
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
3084
3097
  if (entry.name.startsWith('.') || skip.has(entry.name)) continue
3085
3098
  const source = path.join(dir, entry.name)
3086
3099
  if (entry.isDirectory()) collect(source)
@@ -3091,7 +3104,7 @@ export async function generateKotlinSources({ root, dest }: { root: string; dest
3091
3104
  // the generator owns this directory: rebuild it so a moved or deleted source
3092
3105
  // cannot leave a stale copy that redeclares a live class.
3093
3106
  const output = path.join(dest, 'app/src/main/java/one/source')
3094
- FSExtra.removeSync(output)
3107
+ rmSync(output, { recursive: true, force: true })
3095
3108
  if (sources.length === 0) return
3096
3109
  const { kotlinSourceId, renderKotlinSourceGlue, writeNativeSourceDeclaration } = await import(
3097
3110
  '../utils/nativeSourceContract'
@@ -3100,12 +3113,12 @@ export async function generateKotlinSources({ root, dest }: { root: string; dest
3100
3113
  for (const source of sources) {
3101
3114
  const id = kotlinSourceId(root, source)
3102
3115
  const target = path.join(output, id)
3103
- FSExtra.mkdirSync(target, { recursive: true })
3104
- FSExtra.copyFileSync(source, path.join(target, path.basename(source)))
3116
+ mkdirSync(target, { recursive: true })
3117
+ copyFileSync(source, path.join(target, path.basename(source)))
3105
3118
  const contract = writeNativeSourceDeclaration(source)
3106
3119
  if (contract.views.length > 0) hasViews = true
3107
3120
  if (contract.modules.length > 0 || contract.views.length > 0) {
3108
- FSExtra.writeFileSync(
3121
+ writeFileSync(
3109
3122
  path.join(target, `OneNativeSource_${id}.kt`),
3110
3123
  renderKotlinSourceGlue(id, contract).source
3111
3124
  )
@@ -3131,11 +3144,11 @@ async function generateSwiftPackages({ root, dest }: { root: string; dest: strin
3131
3144
  const podDir = path.join(dest, 'OneSwiftPackages', id)
3132
3145
  const manifest = swiftPodManifest(
3133
3146
  path.join(packageDir, 'Package.swift'),
3134
- FSExtra.readFileSync(path.join(packageDir, 'Package.swift'), 'utf8')
3147
+ readFileSync(path.join(packageDir, 'Package.swift'), 'utf8')
3135
3148
  )
3136
3149
  const sources: string[] = []
3137
3150
  const collect = (dir: string) => {
3138
- for (const entry of FSExtra.readdirSync(dir, { withFileTypes: true })) {
3151
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
3139
3152
  // a package at the app root holds the generated native projects too
3140
3153
  if (entry.name.startsWith('.') || skip.has(entry.name)) continue
3141
3154
  const full = path.join(dir, entry.name)
@@ -3155,16 +3168,16 @@ async function generateSwiftPackages({ root, dest }: { root: string; dest: strin
3155
3168
  // tree with real directories and link each file.
3156
3169
  for (const source of sources) {
3157
3170
  const link = path.join(podDir, 'Sources', path.relative(packageDir, source))
3158
- FSExtra.mkdirSync(path.dirname(link), { recursive: true })
3159
- FSExtra.symlinkSync(FSExtra.realpathSync(source), link)
3171
+ mkdirSync(path.dirname(link), { recursive: true })
3172
+ symlinkSync(realpathSync(source), link)
3160
3173
  }
3161
3174
  if (artifacts.glue) {
3162
- FSExtra.writeFileSync(
3175
+ writeFileSync(
3163
3176
  path.join(podDir, 'Sources', 'OneNativeSource.generated.swift'),
3164
3177
  artifacts.glue
3165
3178
  )
3166
3179
  }
3167
- FSExtra.writeFileSync(
3180
+ writeFileSync(
3168
3181
  path.join(podDir, `${id}.podspec`),
3169
3182
  `Pod::Spec.new do |s|
3170
3183
  s.name = '${id}'
@@ -3183,7 +3196,7 @@ async function generateSwiftPackages({ root, dest }: { root: string; dest: strin
3183
3196
  end
3184
3197
  `
3185
3198
  )
3186
- FSExtra.writeFileSync(
3199
+ writeFileSync(
3187
3200
  path.join(podDir, 'Register.m'),
3188
3201
  hasView ? `#import <Foundation/Foundation.h>
3189
3202
 
@@ -3237,12 +3250,12 @@ export function applyAndroidDependencyPatches(args: {
3237
3250
  'MainActivity.kt'
3238
3251
  )
3239
3252
  const rendered = nativeProjectPatches.holdLaunchScreenInMainActivity(
3240
- nativeProjectPatches.addReactNativeScreensFix(FSExtra.readFileSync(activityPath, 'utf8'))
3253
+ nativeProjectPatches.addReactNativeScreensFix(readFileSync(activityPath, 'utf8'))
3241
3254
  )
3242
3255
  if (!rendered.includes('RNScreensFragmentFactory')) {
3243
3256
  throw new Error('[vxrn] failed to apply the react-native-screens activity patch')
3244
3257
  }
3245
- FSExtra.writeFileSync(activityPath, rendered)
3258
+ writeFileSync(activityPath, rendered)
3246
3259
  }
3247
3260
 
3248
3261
  // use the community cli's final configuration so project-owned dependency
@@ -3270,7 +3283,7 @@ export async function getNativeDependencyInventory(
3270
3283
  let version = 'unknown'
3271
3284
  try {
3272
3285
  version =
3273
- JSON.parse(FSExtra.readFileSync(path.join(depRoot, 'package.json'), 'utf8'))
3286
+ JSON.parse(readFileSync(path.join(depRoot, 'package.json'), 'utf8'))
3274
3287
  .version ?? 'unknown'
3275
3288
  } catch {}
3276
3289
  const platforms = Object.entries(dependency.platforms)
@@ -1,6 +1,6 @@
1
1
  import { createDebugger } from '@vxrn/debug'
2
- import FSExtra from 'fs-extra'
3
2
  import path from 'node:path'
3
+ import { outputJSON, readJSON } from '../utils/fs'
4
4
  import { createFilter, type Plugin } from 'vite'
5
5
  import type { AutoDepOptimizationOptions } from '../types'
6
6
  import {
@@ -141,7 +141,7 @@ export async function findDepsToOptimize({
141
141
  const {
142
142
  lockFileHash: cachedLockFileHash,
143
143
  depsToPreBundleForSsr: cachedDepsToPreBundle,
144
- } = await FSExtra.readJSON(cacheFilePath)
144
+ } = await readJSON(cacheFilePath)
145
145
 
146
146
  if (
147
147
  lockFileHash === cachedLockFileHash &&
@@ -167,7 +167,7 @@ export async function findDepsToOptimize({
167
167
  }
168
168
 
169
169
  if (!noCache) {
170
- void FSExtra.outputJSON(cacheFilePath, {
170
+ void outputJSON(cacheFilePath, {
171
171
  lockFileHash,
172
172
  depsToPreBundleForSsr: value,
173
173
  })
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path'
2
- import FSExtra from 'fs-extra'
2
+ import { copyFile, mkdir, readFile } from 'node:fs/promises'
3
3
  import { getMimeType } from 'hono/utils/mime'
4
4
 
5
5
  import type { Plugin, ResolvedConfig } from 'vite'
@@ -90,8 +90,8 @@ export function reactNativeDevAssetPlugin(
90
90
  ASSET_DEST_DIR,
91
91
  assetData.relativeFileSystemLocation
92
92
  )
93
- await FSExtra.ensureDir(assetsDestDir)
94
- await FSExtra.copyFile(
93
+ await mkdir(assetsDestDir, { recursive: true })
94
+ await copyFile(
95
95
  id,
96
96
  path.join(assetsDestDir, `${assetData.name}.${assetData.type}`)
97
97
  )
@@ -137,7 +137,7 @@ export default asset;
137
137
  './' + pathname.slice(`/${DEV_ASSET_DEST_PATH}/`.length).replace(/\.*$/, '') // './src/assets/one-ball.png'
138
138
 
139
139
  try {
140
- const asset = await FSExtra.readFile(assetPath)
140
+ const asset = await readFile(assetPath)
141
141
 
142
142
  res.setHeader(
143
143
  'content-type',