vxrn 0.1.22 → 0.1.24

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.
@@ -39,11 +39,13 @@ import { clientInjectionsPlugin } from '../plugins/clientInjectPlugin'
39
39
  import { reactNativeCommonJsPlugin } from '../plugins/reactNativeCommonJsPlugin'
40
40
  import type { VXRNConfig } from '../types'
41
41
  import { getBaseViteConfig } from '../utils/getBaseViteConfig'
42
- import { getOptionsFilled } from '../utils/getOptionsFilled'
42
+ import { getOptionsFilled, type VXRNConfigFilled } from '../utils/getOptionsFilled'
43
43
  import { getVitePath } from '../utils/getVitePath'
44
44
  import { checkPatches } from '../utils/patches'
45
45
  import { createExpoServer } from '../vendor/createExpoServer'
46
46
 
47
+ const depsToOptimize = ['react', 'react-dom', '@react-native/normalize-color']
48
+
47
49
  export const resolveFile = (path: string) => {
48
50
  try {
49
51
  return importMetaResolve(path, import.meta.url).replace('file://', '')
@@ -85,9 +87,6 @@ export const dev = async (optionsIn: VXRNConfig) => {
85
87
  // TODO move somewhere
86
88
  bindKeypressInput()
87
89
 
88
- // used for normalizing hot reloads
89
- let entryRoot = ''
90
-
91
90
  checkPatches(options).catch((err) => {
92
91
  console.error(`\n 🥺 couldn't patch`, err)
93
92
  })
@@ -122,7 +121,6 @@ export const dev = async (optionsIn: VXRNConfig) => {
122
121
  const templateFile = resolveFile('vxrn/react-native-template.js')
123
122
 
124
123
  // react native port (it scans 19000 +5)
125
- const hotUpdatedCJSFiles = new Map<string, string>()
126
124
  const jsxRuntime = {
127
125
  // alias: 'virtual:react-jsx',
128
126
  alias: prebuilds.reactJSX,
@@ -212,146 +210,13 @@ export const dev = async (optionsIn: VXRNConfig) => {
212
210
  },
213
211
  } as const
214
212
 
215
- const depsToOptimize = ['react', 'react-dom', '@react-native/normalize-color']
216
-
217
- const reactNativeHMRPlugin = {
218
- name: 'client-transform',
219
-
220
- async handleHotUpdate({ read, modules, file }) {
221
- try {
222
- if (!isWithin(root, file)) {
223
- return
224
- }
225
-
226
- const [module] = modules
227
- if (!module) return
228
-
229
- const id = module?.url || file.replace(root, '')
230
-
231
- const code = await read()
232
-
233
- // got a weird pre compiled file on startup
234
- if (code.startsWith(`'use strict';`)) return
235
-
236
- if (!code) {
237
- return
238
- }
239
-
240
- let source = code
241
-
242
- // we have to remove jsx before we can parse imports...
243
- source = (await transformForBuild(id, source))?.code || ''
244
-
245
- const importsMap = {}
246
-
247
- // parse imports of modules into ids:
248
- // eg `import x from '@tamagui/core'` => `import x from '/me/node_modules/@tamagui/core/index.js'`
249
- const [imports] = parse(source)
250
-
251
- let accumulatedSliceOffset = 0
252
-
253
- for (const specifier of imports) {
254
- const { n: importName, s: start } = specifier
255
-
256
- if (importName) {
257
- const id = await getVitePath(entryRoot, file, importName)
258
- if (!id) {
259
- console.warn('???')
260
- continue
261
- }
262
-
263
- importsMap[id] = id.replace(/^(\.\.\/)+/, '')
264
-
265
- // replace module name with id for hmr
266
- const len = importName.length
267
- const extraLen = id.length - len
268
- source =
269
- source.slice(0, start + accumulatedSliceOffset) +
270
- id +
271
- source.slice(start + accumulatedSliceOffset + len)
272
- accumulatedSliceOffset += extraLen
273
- }
274
- }
275
-
276
- // then we have to convert to commonjs..
277
- source =
278
- (
279
- await swcTransform(id, source, {
280
- mode: 'serve-cjs',
281
- })
282
- )?.code || ''
283
-
284
- if (!source) {
285
- throw '❌ no source'
286
- }
287
-
288
- importsMap['currentPath'] = id
289
-
290
- const hotUpdateSource = `exports = ((exports) => {
291
- const require = createRequire(${JSON.stringify(importsMap, null, 2)})
292
- ${source
293
- .replace(`import.meta.hot.accept(() => {})`, ``)
294
- // replace import.meta.glob with empty array in hot reloads
295
- .replaceAll(/import.meta.glob\(.*\)/gi, `globalThis['__importMetaGlobbed'] || {}`)};
296
- return exports })({})`
297
-
298
- if (process.env.DEBUG) {
299
- console.info(`Sending hot update`, hotUpdateSource)
300
- }
301
-
302
- hotUpdatedCJSFiles.set(id, hotUpdateSource)
303
- } catch (err) {
304
- console.error(`Error processing hmr update:`, err)
305
- }
306
- },
307
- }
308
-
309
- let serverConfig: UserConfig = mergeConfig(
310
- getBaseViteConfig({
311
- mode: 'development',
312
- }),
313
- {
314
- root,
315
- clearScreen: false,
316
- plugins: [
317
- reactNativeHMRPlugin,
318
-
319
- clientBundleTreeShakePlugin({}),
320
- ],
321
- optimizeDeps: {
322
- include: depsToOptimize,
323
- exclude: Object.values(virtualModules).map((v) => v.alias),
324
- force: true,
325
- esbuildOptions: {
326
- resolveExtensions: extensions,
327
- },
328
- },
329
- server: {
330
- hmr: {
331
- path: '/__vxrnhmr',
332
- },
333
- cors: true,
334
- host,
335
- },
336
- } satisfies UserConfig
337
- ) satisfies InlineConfig
338
-
339
- if (options.webConfig) {
340
- serverConfig = mergeConfig(serverConfig, options.webConfig) as any
341
- }
213
+ const { serverConfig, hotUpdateCache } = await getViteServerConfig(options)
214
+ const viteServer = await createServer(serverConfig)
342
215
 
343
216
  // first resolve config so we can pass into client plugin, then add client plugin:
344
217
  const resolvedConfig = await resolveConfig(serverConfig, 'serve')
345
-
346
218
  const viteRNClientPlugin = clientInjectionsPlugin(resolvedConfig)
347
219
 
348
- serverConfig = {
349
- ...serverConfig,
350
- plugins: [...serverConfig.plugins!],
351
- }
352
-
353
- const viteServer = await createServer(serverConfig)
354
-
355
220
  // this fakes vite into thinking its loading files, so it hmrs in native mode despite not requesting
356
221
  viteServer.watcher.addListener('change', async (path) => {
357
222
  const id = path.replace(process.cwd(), '')
@@ -391,7 +256,7 @@ export const dev = async (optionsIn: VXRNConfig) => {
391
256
  defineEventHandler((e) => {
392
257
  const query = getQuery(e)
393
258
  if (typeof query.file === 'string') {
394
- const source = hotUpdatedCJSFiles.get(query.file)
259
+ const source = hotUpdateCache.get(query.file)
395
260
  return new Response(source, {
396
261
  headers: {
397
262
  'content-type': 'text/javascript',
@@ -878,3 +743,146 @@ function isWithin(outer: string, inner: string) {
878
743
  const rel = relative(outer, inner)
879
744
  return !rel.startsWith('../') && rel !== '..'
880
745
  }
746
+
747
+ // used for normalizing hot reloads
748
+ let entryRoot = ''
749
+
750
+ export async function getViteServerConfig({ root, host, webConfig, cacheDir }: VXRNConfigFilled) {
751
+ const hotUpdateCache = new Map<string, string>()
752
+
753
+ const reactNativeHMRPlugin = {
754
+ name: 'client-transform',
755
+
756
+ async handleHotUpdate({ read, modules, file }) {
757
+ try {
758
+ if (!isWithin(root, file)) {
759
+ return
760
+ }
761
+
762
+ const [module] = modules
763
+ if (!module) return
764
+
765
+ const id = module?.url || file.replace(root, '')
766
+
767
+ const code = await read()
768
+
769
+ // got a weird pre compiled file on startup
770
+ if (code.startsWith(`'use strict';`)) return
771
+
772
+ if (!code) {
773
+ return
774
+ }
775
+
776
+ let source = code
777
+
778
+ // we have to remove jsx before we can parse imports...
779
+ source = (await transformForBuild(id, source))?.code || ''
780
+
781
+ const importsMap = {}
782
+
783
+ // parse imports of modules into ids:
784
+ // eg `import x from '@tamagui/core'` => `import x from '/me/node_modules/@tamagui/core/index.js'`
785
+ const [imports] = parse(source)
786
+
787
+ let accumulatedSliceOffset = 0
788
+
789
+ for (const specifier of imports) {
790
+ const { n: importName, s: start } = specifier
791
+
792
+ if (importName) {
793
+ const id = await getVitePath(entryRoot, file, importName)
794
+ if (!id) {
795
+ console.warn('???')
796
+ continue
797
+ }
798
+
799
+ importsMap[id] = id.replace(/^(\.\.\/)+/, '')
800
+
801
+ // replace module name with id for hmr
802
+ const len = importName.length
803
+ const extraLen = id.length - len
804
+ source =
805
+ source.slice(0, start + accumulatedSliceOffset) +
806
+ id +
807
+ source.slice(start + accumulatedSliceOffset + len)
808
+ accumulatedSliceOffset += extraLen
809
+ }
810
+ }
811
+
812
+ // then we have to convert to commonjs..
813
+ source =
814
+ (
815
+ await swcTransform(id, source, {
816
+ mode: 'serve-cjs',
817
+ })
818
+ )?.code || ''
819
+
820
+ if (!source) {
821
+ throw '❌ no source'
822
+ }
823
+
824
+ importsMap['currentPath'] = id
825
+
826
+ const hotUpdateSource = `exports = ((exports) => {
827
+ const require = createRequire(${JSON.stringify(importsMap, null, 2)})
828
+ ${source
829
+ .replace(`import.meta.hot.accept(() => {})`, ``)
830
+ // replace import.meta.glob with empty array in hot reloads
831
+ .replaceAll(/import.meta.glob\(.*\)/gi, `globalThis['__importMetaGlobbed'] || {}`)};
832
+ return exports })({})`
833
+
834
+ if (process.env.DEBUG) {
835
+ console.info(`Sending hot update`, hotUpdateSource)
836
+ }
837
+
838
+ hotUpdateCache.set(id, hotUpdateSource)
839
+ } catch (err) {
840
+ console.error(`Error processing hmr update:`, err)
841
+ }
842
+ },
843
+ }
844
+
845
+ let serverConfig: UserConfig = mergeConfig(
846
+ getBaseViteConfig({
847
+ mode: 'development',
848
+ }),
849
+ {
850
+ root,
851
+ clearScreen: false,
852
+ plugins: [
853
+ reactNativeHMRPlugin,
854
+
855
+ clientBundleTreeShakePlugin({}),
856
+ ],
857
+ optimizeDeps: {
858
+ include: depsToOptimize,
859
+ exclude: [`${cacheDir}/*`],
860
+ force: true,
861
+ esbuildOptions: {
862
+ resolveExtensions: extensions,
863
+ },
864
+ },
865
+ server: {
866
+ hmr: {
867
+ path: '/__vxrnhmr',
868
+ },
869
+ cors: true,
870
+ host,
871
+ },
872
+ } satisfies UserConfig
873
+ ) satisfies InlineConfig
874
+
875
+ if (webConfig) {
876
+ serverConfig = mergeConfig(serverConfig, webConfig) as any
877
+ }
878
+
879
+ serverConfig = {
880
+ ...serverConfig,
881
+ plugins: [...serverConfig.plugins!],
882
+ }
883
+
884
+ return {
885
+ serverConfig,
886
+ hotUpdateCache,
887
+ }
888
+ }
@@ -6,7 +6,9 @@ export async function readVXRNConfig(): Promise<VXRNConfig> {
6
6
  if (!(await FSExtra.pathExists('vxrn.config.ts'))) {
7
7
  return {}
8
8
  }
9
- const requireFile = jiti(process.cwd())
9
+ const requireFile = jiti(process.cwd(), {
10
+ esmResolve: true,
11
+ })
10
12
  const userConfig = requireFile('./vxrn.config.ts')
11
13
  return userConfig?.default ?? {}
12
14
  }
@@ -1,5 +1,7 @@
1
1
  /// <reference types="node" />
2
+ import { type UserConfig } from 'vite';
2
3
  import type { VXRNConfig } from '../types';
4
+ import { type VXRNConfigFilled } from '../utils/getOptionsFilled';
3
5
  export declare const resolveFile: (path: string) => string;
4
6
  export declare const dev: (optionsIn: VXRNConfig) => Promise<{
5
7
  server: import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
@@ -10,4 +12,8 @@ export declare const dev: (optionsIn: VXRNConfig) => Promise<{
10
12
  stop: () => Promise<void>;
11
13
  }>;
12
14
  export declare function bindKeypressInput(): void;
15
+ export declare function getViteServerConfig({ root, host, webConfig, cacheDir }: VXRNConfigFilled): Promise<{
16
+ serverConfig: UserConfig;
17
+ hotUpdateCache: Map<string, string>;
18
+ }>;
13
19
  //# sourceMappingURL=dev.d.ts.map