vxrn 1.12.8 → 1.13.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.
Files changed (208) hide show
  1. package/dist/config/getAdditionalViteConfig.mjs +1 -4
  2. package/dist/config/getAdditionalViteConfig.mjs.map +1 -1
  3. package/dist/config/getAdditionalViteConfig.native.js +1 -4
  4. package/dist/config/getAdditionalViteConfig.native.js.map +1 -1
  5. package/dist/config/getReactNativePlugins.mjs +1 -5
  6. package/dist/config/getReactNativePlugins.mjs.map +1 -1
  7. package/dist/config/getReactNativePlugins.native.js +1 -5
  8. package/dist/config/getReactNativePlugins.native.js.map +1 -1
  9. package/dist/exports/build.mjs +5 -0
  10. package/dist/exports/build.mjs.map +1 -1
  11. package/dist/exports/build.native.js +5 -0
  12. package/dist/exports/build.native.js.map +1 -1
  13. package/dist/exports/createServer.mjs +30 -25
  14. package/dist/exports/createServer.mjs.map +1 -1
  15. package/dist/exports/createServer.native.js +6 -3
  16. package/dist/exports/createServer.native.js.map +1 -1
  17. package/dist/exports/prebuild.mjs +25 -1
  18. package/dist/exports/prebuild.mjs.map +1 -1
  19. package/dist/exports/prebuild.native.js +30 -1
  20. package/dist/exports/prebuild.native.js.map +1 -1
  21. package/dist/exports/serve.mjs +2 -2
  22. package/dist/exports/serve.mjs.map +1 -1
  23. package/dist/exports/serve.native.js +2 -2
  24. package/dist/exports/serve.native.js.map +1 -1
  25. package/dist/exports/serveStaticAssets.mjs +43 -11
  26. package/dist/exports/serveStaticAssets.mjs.map +1 -1
  27. package/dist/exports/serveStaticAssets.native.js +69 -6
  28. package/dist/exports/serveStaticAssets.native.js.map +1 -1
  29. package/dist/index.js +1 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +1 -2
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/index.native.js +1 -2
  34. package/dist/index.native.js.map +1 -1
  35. package/dist/patches/builtInDepPatches.mjs +14 -0
  36. package/dist/patches/builtInDepPatches.mjs.map +1 -1
  37. package/dist/patches/builtInDepPatches.native.js +14 -0
  38. package/dist/patches/builtInDepPatches.native.js.map +1 -1
  39. package/dist/plugins/clientInjectPlugin.mjs +2 -62
  40. package/dist/plugins/clientInjectPlugin.mjs.map +1 -1
  41. package/dist/plugins/clientInjectPlugin.native.js +2 -75
  42. package/dist/plugins/clientInjectPlugin.native.js.map +1 -1
  43. package/dist/plugins/reactNativeDevAssetPlugin.mjs +1 -3
  44. package/dist/plugins/reactNativeDevAssetPlugin.mjs.map +1 -1
  45. package/dist/plugins/reactNativeDevAssetPlugin.native.js +1 -3
  46. package/dist/plugins/reactNativeDevAssetPlugin.native.js.map +1 -1
  47. package/dist/plugins/reactNativeDevServer.mjs +55 -77
  48. package/dist/plugins/reactNativeDevServer.mjs.map +1 -1
  49. package/dist/plugins/reactNativeDevServer.native.js +73 -84
  50. package/dist/plugins/reactNativeDevServer.native.js.map +1 -1
  51. package/dist/plugins/serverExtensions.test.mjs +12 -6
  52. package/dist/plugins/serverExtensions.test.mjs.map +1 -1
  53. package/dist/plugins/serverExtensions.test.native.js +12 -6
  54. package/dist/plugins/serverExtensions.test.native.js.map +1 -1
  55. package/dist/rn-commands/bundle/buildBundle.mjs +11 -35
  56. package/dist/rn-commands/bundle/buildBundle.mjs.map +1 -1
  57. package/dist/rn-commands/bundle/buildBundle.native.js +9 -36
  58. package/dist/rn-commands/bundle/buildBundle.native.js.map +1 -1
  59. package/dist/runtime/hmr-client.mjs +125 -0
  60. package/dist/runtime/hmr-client.mjs.map +1 -0
  61. package/dist/runtime/hmr-client.native.js +197 -0
  62. package/dist/runtime/hmr-client.native.js.map +1 -0
  63. package/dist/runtime/hmr-runtime.mjs +162 -0
  64. package/dist/runtime/hmr-runtime.mjs.map +1 -0
  65. package/dist/runtime/hmr-runtime.native.js +348 -0
  66. package/dist/runtime/hmr-runtime.native.js.map +1 -0
  67. package/dist/runtime/hmr-types.mjs +2 -0
  68. package/dist/runtime/hmr-types.mjs.map +1 -0
  69. package/dist/runtime/hmr-types.native.js +2 -0
  70. package/dist/runtime/hmr-types.native.js.map +1 -0
  71. package/dist/runtime/native-prelude.mjs +97 -0
  72. package/dist/runtime/native-prelude.mjs.map +1 -0
  73. package/dist/runtime/native-prelude.native.js +97 -0
  74. package/dist/runtime/native-prelude.native.js.map +1 -0
  75. package/dist/runtime/react-refresh-utils.mjs +19 -0
  76. package/dist/runtime/react-refresh-utils.mjs.map +1 -0
  77. package/dist/runtime/react-refresh-utils.native.js +24 -0
  78. package/dist/runtime/react-refresh-utils.native.js.map +1 -0
  79. package/dist/utils/createNativeDevEngine.mjs +661 -0
  80. package/dist/utils/createNativeDevEngine.mjs.map +1 -0
  81. package/dist/utils/createNativeDevEngine.native.js +702 -0
  82. package/dist/utils/createNativeDevEngine.native.js.map +1 -0
  83. package/dist/utils/patches.mjs +6 -2
  84. package/dist/utils/patches.mjs.map +1 -1
  85. package/dist/utils/patches.native.js +6 -2
  86. package/dist/utils/patches.native.js.map +1 -1
  87. package/dist/utils/scanDepsToOptimize.mjs +4 -3
  88. package/dist/utils/scanDepsToOptimize.mjs.map +1 -1
  89. package/dist/utils/scanDepsToOptimize.native.js +4 -3
  90. package/dist/utils/scanDepsToOptimize.native.js.map +1 -1
  91. package/expo-plugin.cjs +122 -0
  92. package/package.json +15 -19
  93. package/src/config/getAdditionalViteConfig.ts +1 -3
  94. package/src/config/getReactNativePlugins.ts +0 -6
  95. package/src/exports/build.ts +5 -0
  96. package/src/exports/createServer.ts +7 -2
  97. package/src/exports/prebuild.ts +45 -0
  98. package/src/exports/serve.ts +2 -1
  99. package/src/exports/serveStaticAssets.ts +67 -4
  100. package/src/index.ts +0 -2
  101. package/src/patches/builtInDepPatches.ts +29 -0
  102. package/src/plugins/clientInjectPlugin.ts +2 -109
  103. package/src/plugins/reactNativeDevAssetPlugin.ts +0 -21
  104. package/src/plugins/reactNativeDevServer.ts +57 -84
  105. package/src/plugins/serverExtensions.test.ts +6 -8
  106. package/src/rn-commands/bundle/buildBundle.ts +9 -62
  107. package/src/runtime/hmr-client.ts +215 -0
  108. package/src/runtime/hmr-runtime.ts +276 -0
  109. package/src/runtime/hmr-types.ts +84 -0
  110. package/src/runtime/native-prelude.ts +110 -0
  111. package/src/runtime/react-refresh-utils.ts +36 -0
  112. package/src/types.ts +22 -4
  113. package/src/utils/createNativeDevEngine.ts +942 -0
  114. package/src/utils/patches.ts +36 -18
  115. package/src/utils/scanDepsToOptimize.ts +2 -3
  116. package/types/config/getAdditionalViteConfig.d.ts.map +1 -1
  117. package/types/config/getOptionsFilled.d.ts +2 -18
  118. package/types/config/getOptionsFilled.d.ts.map +1 -1
  119. package/types/config/getReactNativePlugins.d.ts.map +1 -1
  120. package/types/exports/build.d.ts +1 -9
  121. package/types/exports/build.d.ts.map +1 -1
  122. package/types/exports/createServer.d.ts.map +1 -1
  123. package/types/exports/prebuild.d.ts.map +1 -1
  124. package/types/exports/serve.d.ts +2 -1
  125. package/types/exports/serve.d.ts.map +1 -1
  126. package/types/exports/serveStaticAssets.d.ts +12 -1
  127. package/types/exports/serveStaticAssets.d.ts.map +1 -1
  128. package/types/index.d.ts +0 -1
  129. package/types/index.d.ts.map +1 -1
  130. package/types/patches/builtInDepPatches.d.ts.map +1 -1
  131. package/types/plugins/clientInjectPlugin.d.ts +1 -7
  132. package/types/plugins/clientInjectPlugin.d.ts.map +1 -1
  133. package/types/plugins/reactNativeDevAssetPlugin.d.ts.map +1 -1
  134. package/types/plugins/reactNativeDevServer.d.ts.map +1 -1
  135. package/types/rn-commands/bundle/buildBundle.d.ts.map +1 -1
  136. package/types/runtime/hmr-client.d.ts +40 -0
  137. package/types/runtime/hmr-client.d.ts.map +1 -0
  138. package/types/runtime/hmr-runtime.d.ts +69 -0
  139. package/types/runtime/hmr-runtime.d.ts.map +1 -0
  140. package/types/runtime/hmr-types.d.ts +76 -0
  141. package/types/runtime/hmr-types.d.ts.map +1 -0
  142. package/types/runtime/native-prelude.d.ts +11 -0
  143. package/types/runtime/native-prelude.d.ts.map +1 -0
  144. package/types/runtime/react-refresh-utils.d.ts +3 -0
  145. package/types/runtime/react-refresh-utils.d.ts.map +1 -0
  146. package/types/types.d.ts +15 -1
  147. package/types/types.d.ts.map +1 -1
  148. package/types/utils/createNativeDevEngine.d.ts +42 -0
  149. package/types/utils/createNativeDevEngine.d.ts.map +1 -0
  150. package/types/utils/patches.d.ts.map +1 -1
  151. package/types/utils/scanDepsToOptimize.d.ts.map +1 -1
  152. package/dist/config/getReactNativeBuildConfig.mjs +0 -200
  153. package/dist/config/getReactNativeBuildConfig.mjs.map +0 -1
  154. package/dist/config/getReactNativeBuildConfig.native.js +0 -204
  155. package/dist/config/getReactNativeBuildConfig.native.js.map +0 -1
  156. package/dist/plugins/reactNativeHMRPlugin.mjs +0 -120
  157. package/dist/plugins/reactNativeHMRPlugin.mjs.map +0 -1
  158. package/dist/plugins/reactNativeHMRPlugin.native.js +0 -151
  159. package/dist/plugins/reactNativeHMRPlugin.native.js.map +0 -1
  160. package/dist/utils/filterPluginsForNative.mjs +0 -27
  161. package/dist/utils/filterPluginsForNative.mjs.map +0 -1
  162. package/dist/utils/filterPluginsForNative.native.js +0 -33
  163. package/dist/utils/filterPluginsForNative.native.js.map +0 -1
  164. package/dist/utils/getReactNativeBundle.mjs +0 -104
  165. package/dist/utils/getReactNativeBundle.mjs.map +0 -1
  166. package/dist/utils/getReactNativeBundle.native.js +0 -135
  167. package/dist/utils/getReactNativeBundle.native.js.map +0 -1
  168. package/dist/utils/hotUpdateCache.mjs +0 -3
  169. package/dist/utils/hotUpdateCache.mjs.map +0 -1
  170. package/dist/utils/hotUpdateCache.native.js +0 -3
  171. package/dist/utils/hotUpdateCache.native.js.map +0 -1
  172. package/dist/utils/isBuildingNativeBundle.mjs +0 -6
  173. package/dist/utils/isBuildingNativeBundle.mjs.map +0 -1
  174. package/dist/utils/isBuildingNativeBundle.native.js +0 -7
  175. package/dist/utils/isBuildingNativeBundle.native.js.map +0 -1
  176. package/dist/utils/swapPrebuiltReactModules.mjs +0 -168
  177. package/dist/utils/swapPrebuiltReactModules.mjs.map +0 -1
  178. package/dist/utils/swapPrebuiltReactModules.native.js +0 -181
  179. package/dist/utils/swapPrebuiltReactModules.native.js.map +0 -1
  180. package/dist/worker.mjs +0 -55
  181. package/dist/worker.mjs.map +0 -1
  182. package/dist/worker.native.js +0 -55
  183. package/dist/worker.native.js.map +0 -1
  184. package/react-native-template.js +0 -375
  185. package/src/config/getReactNativeBuildConfig.ts +0 -349
  186. package/src/plugins/reactNativeHMRPlugin.ts +0 -237
  187. package/src/utils/filterPluginsForNative.ts +0 -55
  188. package/src/utils/getReactNativeBundle.ts +0 -243
  189. package/src/utils/hotUpdateCache.ts +0 -1
  190. package/src/utils/isBuildingNativeBundle.ts +0 -7
  191. package/src/utils/swapPrebuiltReactModules.ts +0 -341
  192. package/src/worker.ts +0 -90
  193. package/types/config/getReactNativeBuildConfig.d.ts +0 -72
  194. package/types/config/getReactNativeBuildConfig.d.ts.map +0 -1
  195. package/types/plugins/reactNativeHMRPlugin.d.ts +0 -10
  196. package/types/plugins/reactNativeHMRPlugin.d.ts.map +0 -1
  197. package/types/utils/filterPluginsForNative.d.ts +0 -8
  198. package/types/utils/filterPluginsForNative.d.ts.map +0 -1
  199. package/types/utils/getReactNativeBundle.d.ts +0 -12
  200. package/types/utils/getReactNativeBundle.d.ts.map +0 -1
  201. package/types/utils/hotUpdateCache.d.ts +0 -2
  202. package/types/utils/hotUpdateCache.d.ts.map +0 -1
  203. package/types/utils/isBuildingNativeBundle.d.ts +0 -3
  204. package/types/utils/isBuildingNativeBundle.d.ts.map +0 -1
  205. package/types/utils/swapPrebuiltReactModules.d.ts +0 -9
  206. package/types/utils/swapPrebuiltReactModules.d.ts.map +0 -1
  207. package/types/worker.d.ts +0 -13
  208. package/types/worker.d.ts.map +0 -1
@@ -1,243 +0,0 @@
1
- import { readFile } from 'node:fs/promises'
2
- import { dirname, relative } from 'node:path'
3
- import { createBuilder } from 'vite'
4
- // import { buildEnvironment } from './fork/vite/build'
5
- import { resolvePath } from '@vxrn/resolve'
6
- import type { VXRNOptionsFilled } from '../config/getOptionsFilled'
7
- import { getReactNativeBuildConfig } from '../config/getReactNativeBuildConfig'
8
- import { filterPluginsForNative } from './filterPluginsForNative'
9
- import { getCacheDir } from './getCacheDir'
10
- import {
11
- isBuildingNativeBundle,
12
- setIsBuildingNativeBundle,
13
- } from './isBuildingNativeBundle'
14
- import { prebuildReactNativeModules } from './swapPrebuiltReactModules'
15
-
16
- // used for normalizing hot reloads
17
- export let entryRoot = ''
18
-
19
- let cachedReactNativeBundles: Record<string, string | undefined> = {}
20
-
21
- export function clearCachedBundle() {
22
- cachedReactNativeBundles = {}
23
- }
24
-
25
- type InternalProps = { mode?: 'dev' | 'prod'; assetsDest?: string; useCache?: boolean }
26
-
27
- export async function getReactNativeBundle(
28
- options: Pick<VXRNOptionsFilled, 'root'> &
29
- Partial<Pick<VXRNOptionsFilled, 'cacheDir'>> &
30
- Parameters<typeof getReactNativeBuildConfig>[0],
31
- platform: 'ios' | 'android',
32
- internal: InternalProps = {
33
- mode: 'dev',
34
- useCache: true,
35
- }
36
- ) {
37
- entryRoot = options.root
38
-
39
- const cached = cachedReactNativeBundles[platform]
40
- if (cached && !process.env.VXRN_DISABLE_CACHE) {
41
- return cached
42
- }
43
-
44
- await prebuildReactNativeModules(options.cacheDir || getCacheDir(options.root), {
45
- // TODO: a better way to pass the mode (dev/prod) to PrebuiltReactModules
46
- mode: internal.mode,
47
- })
48
-
49
- if (isBuildingNativeBundle) {
50
- const res = await isBuildingNativeBundle
51
- return res
52
- }
53
-
54
- let done
55
- setIsBuildingNativeBundle(
56
- new Promise((res) => {
57
- done = res
58
- })
59
- )
60
-
61
- // build app
62
- const nativeBuildConfig = await getReactNativeBuildConfig(options, internal, platform)
63
-
64
- nativeBuildConfig.plugins = filterPluginsForNative(nativeBuildConfig.plugins, {
65
- isNative: true,
66
- })
67
-
68
- // instrument plugins:
69
- const buildStats: Record<string, number> = {}
70
- if (process.env.ONE_DEBUG_BUILD_PERF) {
71
- nativeBuildConfig.plugins = nativeBuildConfig.plugins.map((plugin) => {
72
- return new Proxy(plugin, {
73
- get(target, key) {
74
- const value = Reflect.get(target, key)
75
- // wrap with instrumentation
76
- if (typeof value === 'function') {
77
- return function (this, ...args) {
78
- const name = `${plugin.name}:${key as any}`
79
- const start = performance.now()
80
- const logEnd = () => {
81
- buildStats[name] ||= 0
82
- buildStats[name] += performance.now() - start
83
- }
84
- const out = value.call(this, ...args)
85
- if (out instanceof Promise) {
86
- return out
87
- .then((val) => {
88
- logEnd()
89
- return val
90
- })
91
- .catch((err) => {
92
- logEnd()
93
- throw err
94
- })
95
- }
96
- logEnd()
97
- return out
98
- }
99
- }
100
- return value
101
- },
102
- })
103
- })
104
- }
105
-
106
- const builder = await createBuilder(nativeBuildConfig)
107
-
108
- const environment = builder.environments[platform]
109
-
110
- // We are using a forked version of the Vite internal function `buildEnvironment` (which is what `builder.build` calls) that will return the Rollup cache object with the build output, and also with some performance improvements.
111
- // disabled due to differences in vite 6 stable upgrade
112
-
113
- const buildOutput = await builder.build(environment)
114
-
115
- if (process.env.ONE_DEBUG_BUILD_PERF) {
116
- console.info(JSON.stringify(buildStats, null, 2))
117
- }
118
-
119
- if (!('output' in buildOutput)) {
120
- throw `❌`
121
- }
122
-
123
- let appCode = buildOutput.output
124
- // entry last
125
- .sort((a, b) => (a['isEntry'] ? 1 : a['fileName'].localeCompare(b['fileName']) + -2))
126
- .map((outputModule) => {
127
- const id = outputModule.fileName.replace(/.*node_modules\//, '')
128
-
129
- if (outputModule.type == 'chunk') {
130
- const importsMap = {}
131
- for (const imp of outputModule.imports) {
132
- const relativePath = relative(dirname(id), imp)
133
- importsMap[relativePath[0] === '.' ? relativePath : './' + relativePath] =
134
- imp.replace(/.*node_modules\//, '')
135
- }
136
-
137
- let code = outputModule.code
138
-
139
- // A hacky way to exclude node-fetch from the bundle.
140
- //
141
- // Some part of Supabase SDK will import node-fetch statically (https://github.com/supabase/supabase-js/blob/v2.45.1/src/lib/fetch.ts#L2), or dynamically (https://github.com/supabase/auth-js/blob/8222ee198a0ab10570e8b4c31ffb2aeafef86392/src/lib/helpers.ts#L99), causing the node-fetch to be included in the bundle, and while imported statically it will throw a runtime error when running on React Native.
142
- if (outputModule.facadeModuleId?.includes('@supabase/node-fetch')) {
143
- // This should be safe since the imported '@supabase/node-fetch' will not actually be used in Supabase SDK as there's already a global `fetch` in React Native.
144
- code = ''
145
- }
146
-
147
- if (id.startsWith('.vxrn/react-native')) {
148
- // Turn eager imports of RN back into dynamic lazy imports.
149
- // We needed them eager so rollup won't be unhappy with missing exports, but now we need them lazy again to match the original RN behavior, which may avoid some issues. Such as:
150
- // * react-native v0.76 with: Codegen didn't run for RNCSafeAreaView. This will be an error in the future. Make sure you are using @react-native/babel-preset when building your JavaScript code.
151
- code = code
152
- .replace(
153
- // Step 1: Replace the whole `exports` block which contains `exports.REACT_NATIVE_ESM_MANUAL_EXPORTS_` with `module.exports = RN;`
154
- /(^exports.+$\s)*(^exports\.REACT_NATIVE_ESM_MANUAL_EXPORTS_.+$\s)(^exports.+$\s)*/m,
155
- 'module.exports = RN;'
156
- )
157
- .replace(
158
- // Step 2: Remove the variable assignment lines between the ESM_MANUAL_EXPORTS markers
159
- // (inside __esmMin block). Must use `= "` anchor to avoid matching the __exportAll
160
- // object keys which use `: () =>` syntax.
161
- /^\tREACT_NATIVE_ESM_MANUAL_EXPORTS_START = "[\s\S]*?REACT_NATIVE_ESM_MANUAL_EXPORTS_END = ".*$/m,
162
- ''
163
- )
164
- }
165
-
166
- return `
167
- // id: ${id}
168
- // name: ${outputModule.name}
169
- // facadeModuleId: ${outputModule.facadeModuleId}
170
- // fileName: ${outputModule.fileName}
171
- ___vxrnAbsoluteToRelative___["${outputModule.facadeModuleId}"] = "${id}"
172
- ___modules___["${id}"] = ((exports, module) => {
173
- const require = createRequire("${id}", ${JSON.stringify(importsMap, null, 2)})
174
-
175
- ${code}
176
- })
177
-
178
- ${
179
- outputModule.isEntry
180
- ? `
181
- // run entry
182
- const __require = createRequire(":root:", {})
183
- globalThis.ReactNative = __require("react-native")
184
- globalThis.React = __require("react")
185
- __require("${id}")
186
- `
187
- : ''
188
- }
189
- `
190
- }
191
- })
192
- .join('\n')
193
-
194
- if (!appCode) {
195
- throw `❌`
196
- }
197
-
198
- appCode = appCode
199
- // TEMP FIX for router tamagui thing since expo router 3 upgrade
200
- .replaceAll('dist/esm/index.mjs"', 'dist/esm/index.js"')
201
-
202
- const template = (await getReactNativeTemplate(internal.mode || 'dev')).replaceAll(
203
- '__VXRN_PLATFORM__',
204
- `"${platform}"`
205
- )
206
-
207
- const out = template + appCode
208
-
209
- cachedReactNativeBundles[platform] = out
210
- done(out)
211
- setIsBuildingNativeBundle(null)
212
-
213
- return out
214
- }
215
-
216
- /**
217
- * Get `react-native-template.js` with some `process.env.*` replaced with static values.
218
- */
219
- async function getReactNativeTemplate(mode: 'dev' | 'prod') {
220
- const templateFile = resolvePath('vxrn/react-native-template.js')
221
- let template = await readFile(templateFile, 'utf-8')
222
-
223
- template = template.replace(/process\.env\.__DEV__/g, mode === 'dev' ? 'true' : 'false')
224
-
225
- if (mode === 'prod') {
226
- // `process` might not available in release runtime
227
- template = template.replace(/process\.env\.DEBUG/g, 'undefined')
228
-
229
- // In production mode, the prebuilt modules have `.production` in their filenames
230
- template = template.replaceAll(
231
- '.vxrn/react-jsx-runtime.js',
232
- '.vxrn/react-jsx-runtime.production.js'
233
- )
234
- template = template.replaceAll('.vxrn/react.js', '.vxrn/react.production.js')
235
- // react-native already has platform in filename, need to add .production before platform
236
- template = template.replace(
237
- /\.vxrn\/react-native\.(\$\{__VXRN_PLATFORM__\.toLowerCase\(\)\})\.js/g,
238
- '.vxrn/react-native.production.$1.js'
239
- )
240
- }
241
-
242
- return template
243
- }
@@ -1 +0,0 @@
1
- export const hotUpdateCache = new Map<string, string>()
@@ -1,7 +0,0 @@
1
- // sorry for the mess, exploring before abstracting
2
-
3
- export let isBuildingNativeBundle: Promise<string> | null = null
4
-
5
- export function setIsBuildingNativeBundle(val: Promise<string> | null = null) {
6
- isBuildingNativeBundle = val
7
- }
@@ -1,341 +0,0 @@
1
- import { buildReact, buildReactJSX, buildReactNative } from '@vxrn/react-native-prebuilt'
2
- import { resolvePath } from '@vxrn/resolve'
3
- import FSExtra from 'fs-extra'
4
- import { readFile } from 'node:fs/promises'
5
- import { join } from 'node:path'
6
- import type { Plugin } from 'vite'
7
- import { isNativeEnvironment } from './environmentUtils'
8
-
9
- // Lock to prevent concurrent prebuilds which cause race conditions
10
- let prebuildPromise: Promise<void> | null = null
11
-
12
- // we should just detect or whitelist and use flow to convert instead of this but i did a
13
- // few things to the prebuilts to make them work, we may need to account for
14
-
15
- const getPrebuilds = (cacheDir: string, mode) => ({
16
- reactJSX: join(cacheDir, `react-jsx-runtime${mode === 'prod' ? '.production' : ''}.js`),
17
- react: join(cacheDir, `react${mode === 'prod' ? '.production' : ''}.js`),
18
- reactNativeIos: join(
19
- cacheDir,
20
- `react-native${mode === 'prod' ? '.production' : ''}.ios.js`
21
- ),
22
- reactNativeAndroid: join(
23
- cacheDir,
24
- `react-native${mode === 'prod' ? '.production' : ''}.android.js`
25
- ),
26
- })
27
-
28
- const allExist = async (paths: string[]) => {
29
- return (await Promise.all(paths.map((p) => FSExtra.pathExists(p)))).every(Boolean)
30
- }
31
-
32
- export async function prebuildReactNativeModules(
33
- cacheDir: string,
34
- internal: { mode?: 'dev' | 'prod' } = { mode: 'dev' }
35
- ) {
36
- // If a prebuild is already in progress, wait for it and return
37
- if (prebuildPromise) {
38
- await prebuildPromise
39
- return
40
- }
41
-
42
- const prebuilds = getPrebuilds(cacheDir, internal.mode)
43
-
44
- // Set lock immediately before any async operation to prevent race conditions
45
- let resolveLock: () => void
46
- prebuildPromise = new Promise((resolve) => {
47
- resolveLock = resolve
48
- })
49
-
50
- try {
51
- if (
52
- internal.mode !== 'prod' && // Do not use cached prebuilds while building for production, since the performance gain is little (build time is already slower anyway) and can avoid potential issues.
53
- (await allExist(Object.values(prebuilds)))
54
- ) {
55
- return
56
- }
57
-
58
- if (internal.mode !== 'prod') {
59
- console.info('\n ❶ Pre-building react-native (one time cost)...\n')
60
- } else {
61
- console.info('\n ❶ Pre-building react-native for production...\n')
62
- }
63
-
64
- /** Some build option overrides depending on the mode (dev/prod). */
65
- const buildOptions =
66
- internal.mode === 'prod'
67
- ? {
68
- define: {
69
- __DEV__: 'false',
70
- 'process.env.NODE_ENV': `"production"`,
71
- },
72
- }
73
- : {}
74
-
75
- let enableExperimentalReactNativeWithReact19Support = false
76
- const reactPackageJsonPath = resolvePath('react/package.json')
77
- const reactPackageJsonContents = await readFile(reactPackageJsonPath, 'utf8')
78
- const reactPackageJson = JSON.parse(reactPackageJsonContents)
79
- const reactNativePackageJsonPath = resolvePath('react/package.json')
80
- const reactNativePackageJsonContents = await readFile(
81
- reactNativePackageJsonPath,
82
- 'utf8'
83
- )
84
- const reactNativePackageJson = JSON.parse(reactNativePackageJsonContents)
85
-
86
- const reactVersion = reactPackageJson?.version
87
- const reactNativeVersion = reactNativePackageJson?.version
88
- if (reactVersion?.startsWith('19') && Number.parseFloat(reactNativeVersion) < 0.78) {
89
- console.info(
90
- `🧪 React ${reactVersion} detected. Enabling experimental React 19 support for React Native.`
91
- )
92
- enableExperimentalReactNativeWithReact19Support = true
93
- }
94
-
95
- await Promise.all([
96
- buildReactNative(
97
- {
98
- entryPoints: [resolvePath('react-native')],
99
- outfile: prebuilds.reactNativeIos,
100
- ...buildOptions,
101
- },
102
- { platform: 'ios', enableExperimentalReactNativeWithReact19Support }
103
- ).catch((err) => {
104
- console.error(`Error pre-building react-native for iOS`)
105
- throw err
106
- }),
107
- buildReactNative(
108
- {
109
- entryPoints: [resolvePath('react-native')],
110
- outfile: prebuilds.reactNativeAndroid,
111
- ...buildOptions,
112
- },
113
- { platform: 'android', enableExperimentalReactNativeWithReact19Support }
114
- ).catch((err) => {
115
- console.error(`Error pre-building react-native for Android`)
116
- throw err
117
- }),
118
- buildReact({
119
- entryPoints: [resolvePath('react')],
120
- outfile: prebuilds.react,
121
- ...buildOptions,
122
- }).catch((err) => {
123
- console.error(`Error pre-building react`)
124
- throw err
125
- }),
126
- buildReactJSX({
127
- entryPoints: [
128
- internal.mode === 'dev'
129
- ? resolvePath('react/jsx-dev-runtime')
130
- : resolvePath('react/jsx-runtime'),
131
- ],
132
- outfile: prebuilds.reactJSX,
133
- ...buildOptions,
134
- }).catch((err) => {
135
- console.error(`Error pre-building react/jsx-runtime`)
136
- throw err
137
- }),
138
- ])
139
- } finally {
140
- // Release the lock so other callers can proceed
141
- resolveLock!()
142
- prebuildPromise = null
143
- }
144
- }
145
-
146
- export async function swapPrebuiltReactModules(
147
- cacheDir: string,
148
- internal: { mode: 'dev' | 'prod'; platform: 'ios' | 'android' }
149
- ): Promise<Plugin> {
150
- let prebuilds = getPrebuilds(cacheDir, internal.mode)
151
-
152
- let cached: null | Record<
153
- | 'react-native'
154
- | 'react'
155
- | 'react/jsx-runtime'
156
- | 'react/jsx-dev-runtime'
157
- | 'react/jsx-runtime',
158
- {
159
- alias: string
160
- contents: string
161
- }
162
- > = null
163
-
164
- const rnPrebuilt = (() => {
165
- switch (internal.platform) {
166
- case 'ios':
167
- return prebuilds.reactNativeIos
168
- case 'android':
169
- return prebuilds.reactNativeAndroid
170
- default:
171
- throw new Error(`Unsupported platform: ${internal.platform}`)
172
- }
173
- })()
174
-
175
- const getVirtualModules = async () => {
176
- if (cached) return cached
177
-
178
- const jsxRuntime = {
179
- alias: prebuilds.reactJSX,
180
- contents: await readFile(prebuilds.reactJSX, 'utf-8'),
181
- } as const
182
-
183
- cached = {
184
- 'react-native': {
185
- alias: rnPrebuilt,
186
- contents: await readFile(rnPrebuilt, 'utf-8'),
187
- },
188
- react: {
189
- alias: prebuilds.react,
190
- contents: await readFile(prebuilds.react, 'utf-8'),
191
- },
192
- 'react/jsx-runtime': jsxRuntime,
193
- 'react/jsx-dev-runtime': jsxRuntime,
194
- } as const
195
-
196
- return cached
197
- }
198
-
199
- const virtualModules = await getVirtualModules()
200
-
201
- const cachedIdToContents = Object.keys(virtualModules).reduce((acc, key) => {
202
- const cur = virtualModules[key]
203
- acc[cur.alias] = cur.contents
204
- return acc
205
- }, {})
206
-
207
- return {
208
- name: `swap-react-native`,
209
- enforce: 'pre',
210
-
211
- async resolveId(id, _importer, options) {
212
- // Skip during Vite's dependency optimization scan
213
- // @see https://github.com/remix-run/remix/discussions/8917
214
- // @ts-expect-error - scan is not in Vite's types but exists at runtime
215
- if (options?.scan) return
216
-
217
- if (!isNativeEnvironment(this.environment)) {
218
- return
219
- }
220
-
221
- if (id === 'react-native-web') {
222
- return rnPrebuilt
223
- }
224
-
225
- if (id.startsWith('react-native/')) {
226
- if (id === 'react-native/package.json') {
227
- return
228
- }
229
- return `virtual:rn-internals:${id}`
230
- }
231
-
232
- // We might have aliased `react-native` to `react-native-web` (see `'react-native': 'react-native-web'` in `utils/getBaseViteConfig.ts`) so we need to handle that case too.
233
- if (
234
- id.startsWith('react-native-web/Libraries') ||
235
- id.includes('react-native-web/dist/cjs/index.js/Libraries') // Possible after switched to CJS (Tamagui 1.112.3)
236
- ) {
237
- return `virtual:rn-internals:${id.replace(/^.*react-native-web(\/dist\/cjs\/index.js)?/, 'react-native')}`
238
- }
239
-
240
- for (const targetId in virtualModules) {
241
- if (id === targetId || id.includes(`/node_modules/${targetId}/`)) {
242
- const info = virtualModules[targetId]
243
- return info.alias
244
- }
245
- }
246
- },
247
-
248
- async load(id) {
249
- if (id.startsWith('virtual:rn-internals')) {
250
- const idOut = id.replace('virtual:rn-internals:', '')
251
-
252
- let out = ''
253
-
254
- if (id.includes('ReactFabric')) {
255
- // A workaround for some internal modules being loaded when they shouldn't be.
256
- // See: https://github.com/onejs/one/pull/283#issuecomment-2527356510
257
- out += `const ___val = __cachedModules["${idOut}"] /* This module shouldn't be loaded if not already been loaded internally. */`
258
- } else {
259
- // Normal case, this will dynamically load the module if not already loaded.
260
- out += `const ___val = __RN_INTERNAL_MODULE_REQUIRES_MAP__["${idOut}"]()`
261
- }
262
-
263
- out += '\n'
264
-
265
- out += `
266
- const ___defaultVal = ___val ? ___val.default || ___val : ___val
267
- export default ___defaultVal
268
- `
269
-
270
- out += getReactNativeInternalModuleExports(idOut)
271
- .map(
272
- (exportName) =>
273
- `export const ${exportName} = ___val.${exportName} || ___defaultVal.${exportName}`
274
- )
275
- .join('\n')
276
-
277
- out += `
278
- // allow importing named exports of internals:
279
- if (___defaultVal && typeof ___defaultVal === 'object') {
280
- Object.keys(___defaultVal).forEach(key => {
281
- if (key !== 'default') {
282
- exports[key] = ___defaultVal[key]
283
- }
284
- })
285
- }
286
- `
287
-
288
- return out
289
- }
290
-
291
- if (id in cachedIdToContents) {
292
- return cachedIdToContents[id]
293
- }
294
- },
295
- } satisfies Plugin
296
- }
297
-
298
- /**
299
- * Given a React Native internal module path, return the list of export names that are exported from the module, excluding the default export.
300
- */
301
- function getReactNativeInternalModuleExports(
302
- /**
303
- * Example: `react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry`.
304
- */
305
- modulePath: string
306
- ): string[] {
307
- return KNOWN_REACT_NATIVE_INTERNAL_MODULE_EXPORTS[modulePath] || []
308
- }
309
-
310
- /**
311
- * TODO: We can use `es-module-lexer` to parse from source code instead of hardcoding these.
312
- * Keywords: `"..." is not exported by "virtual:rn-internals:react-native/..."`
313
- */
314
- const KNOWN_REACT_NATIVE_INTERNAL_MODULE_EXPORTS = {
315
- 'react-native/Libraries/NativeComponent/NativeComponentRegistry': [
316
- 'setRuntimeConfigProvider',
317
- 'get',
318
- 'getWithFallback_DEPRECATED',
319
- 'unstable_hasStaticViewConfig',
320
- ],
321
- 'react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry': [
322
- 'customBubblingEventTypes',
323
- 'customDirectEventTypes',
324
- 'register',
325
- 'get',
326
- ],
327
- 'react-native/Libraries/Pressability/PressabilityDebug': [
328
- 'PressabilityDebugView',
329
- 'isEnabled',
330
- 'setEnabled',
331
- ],
332
- 'react-native/Libraries/Utilities/PolyfillFunctions': [
333
- 'polyfillObjectProperty',
334
- 'polyfillGlobal',
335
- ],
336
- 'react-native/Libraries/Image/resolveAssetSource': [
337
- 'pickScale',
338
- 'setCustomSourceTransformer',
339
- 'addCustomSourceTransformer',
340
- ],
341
- }
package/src/worker.ts DELETED
@@ -1,90 +0,0 @@
1
- import { parentPort, isMainThread, Worker } from 'node:worker_threads'
2
- import type { VXRNOptionsFilled } from './config/getOptionsFilled'
3
- import { loadEnv } from './exports/loadEnv'
4
- import { getReactNativeBundle } from './utils/getReactNativeBundle'
5
- import { resolvePath } from '@vxrn/resolve'
6
- import {
7
- type ConfigSubset,
8
- getResolvedConfig,
9
- setResolvedConfig,
10
- } from './plugins/getResolvedConfigSubset'
11
-
12
- type WorkerCommands = {
13
- name: 'bundle-react-native'
14
- arg: {
15
- options: Pick<VXRNOptionsFilled, 'root'> &
16
- Partial<Pick<VXRNOptionsFilled, 'cacheDir'>> &
17
- Parameters<typeof getReactNativeBundle>[0]
18
- platform: 'ios' | 'android'
19
- }
20
- returns: string
21
- }
22
-
23
- const workerPath = resolvePath('vxrn/worker')
24
-
25
- let worker: Worker
26
-
27
- export function runOnWorker<Command extends WorkerCommands>(
28
- name: Command['name'],
29
- arg: Command['arg']
30
- ): Promise<Command['returns']> {
31
- console.info(`RUN`, name)
32
-
33
- worker ||= new Worker(workerPath, {
34
- stdout: true,
35
- stderr: true,
36
- })
37
-
38
- return new Promise((resolve, reject) => {
39
- worker.postMessage({ name, arg, _resolvedConfig: getResolvedConfig() })
40
-
41
- worker.on('message', (message: any) => {
42
- if (message.result) {
43
- resolve(message.result)
44
- } else if (message.error) {
45
- reject(new Error(message.error))
46
- }
47
- })
48
-
49
- worker.on('error', (error) => {
50
- reject(error)
51
- })
52
-
53
- worker.on('exit', (code) => {
54
- if (code !== 0) {
55
- reject(new Error(`Worker stopped with exit code ${code}`))
56
- }
57
- })
58
- })
59
- }
60
-
61
- process.on('exit', () => {
62
- worker?.terminate()
63
- })
64
-
65
- if (!isMainThread && parentPort) {
66
- parentPort.on(
67
- 'message',
68
- async (message: WorkerCommands & { _resolvedConfig: ConfigSubset }) => {
69
- if (message._resolvedConfig) {
70
- setResolvedConfig(message._resolvedConfig)
71
- }
72
-
73
- switch (message.name) {
74
- case 'bundle-react-native': {
75
- const { options, platform } = message.arg
76
-
77
- try {
78
- loadEnv('development')
79
- const bundle = await getReactNativeBundle(options, platform, { mode: 'dev' })
80
- parentPort!.postMessage({ result: bundle })
81
- } catch (error: any) {
82
- parentPort!.postMessage({ error: error.message })
83
- }
84
-
85
- break
86
- }
87
- }
88
- }
89
- )
90
- }