@tamagui/static 2.0.0-rc.3 → 2.0.0-rc.31

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 (141) hide show
  1. package/dist/checkDeps.cjs +164 -31
  2. package/dist/exports.cjs +3 -0
  3. package/dist/extractor/bundle.cjs +72 -35
  4. package/dist/extractor/bundleConfig.cjs +219 -35
  5. package/dist/extractor/createExtractor.cjs +170 -28
  6. package/dist/extractor/detectModuleFormat.cjs +49 -0
  7. package/dist/extractor/esbuildTsconfigPaths.cjs +3 -1
  8. package/dist/extractor/extractToClassNames.cjs +7 -5
  9. package/dist/extractor/extractToNative.cjs +7 -8
  10. package/dist/extractor/loadTamagui.cjs +1 -1
  11. package/dist/getPragmaOptions.cjs +7 -3
  12. package/dist/registerRequire.cjs +23 -14
  13. package/package.json +26 -22
  14. package/src/checkDeps.ts +305 -68
  15. package/src/exports.ts +1 -0
  16. package/src/extractor/bundle.ts +140 -37
  17. package/src/extractor/bundleConfig.ts +435 -61
  18. package/src/extractor/createExtractor.ts +261 -41
  19. package/src/extractor/detectModuleFormat.ts +42 -0
  20. package/src/extractor/esbuildTsconfigPaths.ts +6 -1
  21. package/src/extractor/extractToClassNames.ts +15 -9
  22. package/src/extractor/extractToNative.ts +32 -25
  23. package/src/extractor/loadTamagui.ts +2 -2
  24. package/src/getPragmaOptions.ts +6 -1
  25. package/src/registerRequire.ts +40 -8
  26. package/types/checkDeps.d.ts.map +1 -1
  27. package/types/exports.d.ts +1 -0
  28. package/types/exports.d.ts.map +1 -1
  29. package/types/extractor/bundle.d.ts +83 -1
  30. package/types/extractor/bundle.d.ts.map +1 -1
  31. package/types/extractor/bundleConfig.d.ts +15 -2
  32. package/types/extractor/bundleConfig.d.ts.map +1 -1
  33. package/types/extractor/createExtractor.d.ts.map +1 -1
  34. package/types/extractor/detectModuleFormat.d.ts +5 -0
  35. package/types/extractor/detectModuleFormat.d.ts.map +1 -0
  36. package/types/extractor/esbuildTsconfigPaths.d.ts +8 -0
  37. package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -1
  38. package/types/extractor/extractToClassNames.d.ts.map +1 -1
  39. package/types/extractor/extractToNative.d.ts.map +1 -1
  40. package/types/getPragmaOptions.d.ts.map +1 -1
  41. package/types/registerRequire.d.ts.map +1 -1
  42. package/dist/check-dep-versions.js +0 -389
  43. package/dist/check-dep-versions.js.map +0 -6
  44. package/dist/checkDeps.js +0 -60
  45. package/dist/checkDeps.js.map +0 -6
  46. package/dist/constants.js +0 -34
  47. package/dist/constants.js.map +0 -6
  48. package/dist/exports.js +0 -34
  49. package/dist/exports.js.map +0 -6
  50. package/dist/extractor/accessSafe.js +0 -47
  51. package/dist/extractor/accessSafe.js.map +0 -6
  52. package/dist/extractor/babelParse.js +0 -59
  53. package/dist/extractor/babelParse.js.map +0 -6
  54. package/dist/extractor/buildClassName.js +0 -72
  55. package/dist/extractor/buildClassName.js.map +0 -6
  56. package/dist/extractor/bundle.js +0 -135
  57. package/dist/extractor/bundle.js.map +0 -6
  58. package/dist/extractor/bundleConfig.js +0 -352
  59. package/dist/extractor/bundleConfig.js.map +0 -6
  60. package/dist/extractor/concatClassName.js +0 -69
  61. package/dist/extractor/concatClassName.js.map +0 -6
  62. package/dist/extractor/createEvaluator.js +0 -66
  63. package/dist/extractor/createEvaluator.js.map +0 -6
  64. package/dist/extractor/createExtractor.js +0 -1215
  65. package/dist/extractor/createExtractor.js.map +0 -6
  66. package/dist/extractor/createLogger.js +0 -32
  67. package/dist/extractor/createLogger.js.map +0 -6
  68. package/dist/extractor/ensureImportingConcat.js +0 -50
  69. package/dist/extractor/ensureImportingConcat.js.map +0 -6
  70. package/dist/extractor/errors.js +0 -22
  71. package/dist/extractor/errors.js.map +0 -6
  72. package/dist/extractor/esbuildAliasPlugin.js +0 -36
  73. package/dist/extractor/esbuildAliasPlugin.js.map +0 -6
  74. package/dist/extractor/esbuildTsconfigPaths.js +0 -79
  75. package/dist/extractor/esbuildTsconfigPaths.js.map +0 -6
  76. package/dist/extractor/evaluateAstNode.js +0 -99
  77. package/dist/extractor/evaluateAstNode.js.map +0 -6
  78. package/dist/extractor/extractHelpers.js +0 -108
  79. package/dist/extractor/extractHelpers.js.map +0 -6
  80. package/dist/extractor/extractMediaStyle.js +0 -123
  81. package/dist/extractor/extractMediaStyle.js.map +0 -6
  82. package/dist/extractor/extractToClassNames.js +0 -351
  83. package/dist/extractor/extractToClassNames.js.map +0 -6
  84. package/dist/extractor/extractToNative.js +0 -286
  85. package/dist/extractor/extractToNative.js.map +0 -6
  86. package/dist/extractor/findTopmostFunction.js +0 -32
  87. package/dist/extractor/findTopmostFunction.js.map +0 -6
  88. package/dist/extractor/generatedUid.js +0 -42
  89. package/dist/extractor/generatedUid.js.map +0 -6
  90. package/dist/extractor/getPrefixLogs.js +0 -24
  91. package/dist/extractor/getPrefixLogs.js.map +0 -6
  92. package/dist/extractor/getPropValueFromAttributes.js +0 -65
  93. package/dist/extractor/getPropValueFromAttributes.js.map +0 -6
  94. package/dist/extractor/getSourceModule.js +0 -62
  95. package/dist/extractor/getSourceModule.js.map +0 -6
  96. package/dist/extractor/getStaticBindingsForScope.js +0 -145
  97. package/dist/extractor/getStaticBindingsForScope.js.map +0 -6
  98. package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.js +0 -32
  99. package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.js.map +0 -6
  100. package/dist/extractor/hoistClassNames.js +0 -63
  101. package/dist/extractor/hoistClassNames.js.map +0 -6
  102. package/dist/extractor/literalToAst.js +0 -90
  103. package/dist/extractor/literalToAst.js.map +0 -6
  104. package/dist/extractor/loadFile.js +0 -14
  105. package/dist/extractor/loadFile.js.map +0 -6
  106. package/dist/extractor/loadTamagui.js +0 -306
  107. package/dist/extractor/loadTamagui.js.map +0 -6
  108. package/dist/extractor/logLines.js +0 -30
  109. package/dist/extractor/logLines.js.map +0 -6
  110. package/dist/extractor/normalizeTernaries.js +0 -61
  111. package/dist/extractor/normalizeTernaries.js.map +0 -6
  112. package/dist/extractor/propsToFontFamilyCache.js +0 -33
  113. package/dist/extractor/propsToFontFamilyCache.js.map +0 -6
  114. package/dist/extractor/regenerateConfig.js +0 -123
  115. package/dist/extractor/regenerateConfig.js.map +0 -6
  116. package/dist/extractor/removeUnusedHooks.js +0 -72
  117. package/dist/extractor/removeUnusedHooks.js.map +0 -6
  118. package/dist/extractor/timer.js +0 -38
  119. package/dist/extractor/timer.js.map +0 -6
  120. package/dist/extractor/validHTMLAttributes.js +0 -72
  121. package/dist/extractor/validHTMLAttributes.js.map +0 -6
  122. package/dist/extractor/watchTamaguiConfig.js +0 -57
  123. package/dist/extractor/watchTamaguiConfig.js.map +0 -6
  124. package/dist/getPragmaOptions.js +0 -46
  125. package/dist/getPragmaOptions.js.map +0 -6
  126. package/dist/helpers/memoize.js +0 -33
  127. package/dist/helpers/memoize.js.map +0 -6
  128. package/dist/helpers/requireTamaguiCore.js +0 -30
  129. package/dist/helpers/requireTamaguiCore.js.map +0 -6
  130. package/dist/index.js +0 -30
  131. package/dist/index.js.map +0 -6
  132. package/dist/registerRequire.js +0 -100
  133. package/dist/registerRequire.js.map +0 -6
  134. package/dist/server.js +0 -58
  135. package/dist/server.js.map +0 -6
  136. package/dist/setup.js +0 -1
  137. package/dist/setup.js.map +0 -6
  138. package/dist/types.js +0 -14
  139. package/dist/types.js.map +0 -6
  140. package/dist/worker.js +0 -72
  141. package/dist/worker.js.map +0 -6
@@ -1,15 +1,13 @@
1
1
  import generate from '@babel/generator'
2
2
  import traverse from '@babel/traverse'
3
3
  import * as t from '@babel/types'
4
- import { existsSync, readFileSync } from 'node:fs'
4
+ import { createHash } from 'node:crypto'
5
+ import { existsSync, readFileSync, unlinkSync } from 'node:fs'
5
6
  import { basename, dirname, extname, join, relative, sep } from 'node:path'
7
+ import { pathToFileURL } from 'node:url'
6
8
  // @ts-ignore why
7
9
  import { Color, colorLog } from '@tamagui/cli-color'
8
- import {
9
- createTamagui,
10
- type StaticConfig,
11
- type TamaguiInternalConfig,
12
- } from '@tamagui/web'
10
+ import { type StaticConfig, type TamaguiInternalConfig } from '@tamagui/web'
13
11
  import esbuild from 'esbuild'
14
12
  import * as FS from 'fs-extra'
15
13
  import { readFile } from 'node:fs/promises'
@@ -19,6 +17,72 @@ import { babelParse } from './babelParse'
19
17
  import { esbuildLoaderConfig, esbundleTamaguiConfig } from './bundle'
20
18
  import { getTamaguiConfigPathFromOptionsConfig } from './getTamaguiConfigPathFromOptionsConfig'
21
19
  import { requireTamaguiCore } from '../helpers/requireTamaguiCore'
20
+ import { detectModuleFormat } from './detectModuleFormat'
21
+
22
+ // track temp files for cleanup on exit
23
+ const activeTempFiles = new Set<string>()
24
+
25
+ function getDynamicEvalOutfile(name: string, format: 'esm' | 'cjs', contents: string) {
26
+ const ext = format === 'esm' ? 'mjs' : 'cjs'
27
+ const hash = createHash('sha1')
28
+ .update(name)
29
+ .update('\0')
30
+ .update(format)
31
+ .update('\0')
32
+ .update(contents)
33
+ .digest('hex')
34
+ .slice(0, 10)
35
+ return join(process.cwd(), '.tamagui', `dynamic-eval-${hash}-${basename(name)}.${ext}`)
36
+ }
37
+
38
+ function getEsbuildStdinLoader(filePath: string): esbuild.Loader {
39
+ if (filePath.endsWith('.tsx')) return 'tsx'
40
+ if (filePath.endsWith('.ts')) return 'ts'
41
+ if (filePath.endsWith('.jsx')) return 'jsx'
42
+ return 'js'
43
+ }
44
+
45
+ function resolvePackageEntry(packageName: string, format: 'esm' | 'cjs') {
46
+ if (format === 'cjs') {
47
+ return require.resolve(packageName)
48
+ }
49
+
50
+ const packageJsonPath = require.resolve(`${packageName}/package.json`)
51
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
52
+ const packageRoot = dirname(packageJsonPath)
53
+ const exportEntry = packageJson.exports?.['.']
54
+
55
+ const esmEntry =
56
+ exportEntry?.import ||
57
+ exportEntry?.module ||
58
+ exportEntry?.browser ||
59
+ packageJson.module
60
+
61
+ if (typeof esmEntry === 'string') {
62
+ return join(packageRoot, esmEntry)
63
+ }
64
+
65
+ return require.resolve(packageName)
66
+ }
67
+
68
+ function cleanupTempFiles() {
69
+ for (const f of activeTempFiles) {
70
+ try {
71
+ unlinkSync(f)
72
+ } catch {}
73
+ }
74
+ activeTempFiles.clear()
75
+ }
76
+
77
+ process.on('exit', cleanupTempFiles)
78
+ process.on('SIGINT', () => {
79
+ cleanupTempFiles()
80
+ process.exit()
81
+ })
82
+ process.on('SIGTERM', () => {
83
+ cleanupTempFiles()
84
+ process.exit()
85
+ })
22
86
 
23
87
  type NameToPaths = {
24
88
  [key: string]: Set<string>
@@ -55,12 +119,95 @@ const esbuildExtraOptions = {
55
119
  },
56
120
  }
57
121
 
58
- export const esbuildOptions = {
59
- target: 'es2018',
122
+ // plugin to handle ESM-only features when bundling to CJS
123
+ const handleEsmFeaturesPlugin: esbuild.Plugin = {
124
+ name: 'handle-esm-features',
125
+ setup(build) {
126
+ // only apply transforms for CJS output - ESM supports these natively
127
+ const isCjs = build.initialOptions.format === 'cjs' || !build.initialOptions.format
128
+
129
+ build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs)$/ }, (args) => {
130
+ // skip if ESM output - import.meta and top-level await work natively
131
+ if (!isCjs) {
132
+ return null
133
+ }
134
+
135
+ // skip most node_modules
136
+ if (args.path.includes('node_modules') && !args.path.includes('@tamagui')) {
137
+ return null
138
+ }
139
+
140
+ let contents = readFileSync(args.path, 'utf8')
141
+ let modified = false
142
+
143
+ // transform import.meta.env -> process.env (Vite-style env vars)
144
+ if (contents.includes('import.meta.env')) {
145
+ contents = contents.replace(/import\.meta\.env/g, 'process.env')
146
+ modified = true
147
+ }
148
+
149
+ // transform import.meta.url -> "" (not needed for static extraction)
150
+ if (contents.includes('import.meta.url')) {
151
+ contents = contents.replace(/import\.meta\.url/g, '""')
152
+ modified = true
153
+ }
154
+
155
+ // transform import.meta.main -> false
156
+ if (contents.includes('import.meta.main')) {
157
+ contents = contents.replace(/import\.meta\.main/g, 'false')
158
+ modified = true
159
+ }
160
+
161
+ // stub files with top-level await - they're typically runtime-only
162
+ if (
163
+ /^\s*(?:const|let|var|export)\s+[^=]*=\s*await\b/m.test(contents) ||
164
+ /^await\s/m.test(contents)
165
+ ) {
166
+ if (process.env.DEBUG?.startsWith('tamagui')) {
167
+ console.info(`[tamagui] stubbing file with top-level await: ${args.path}`)
168
+ }
169
+ return {
170
+ contents: `// stubbed - contains top-level await\nmodule.exports = {}`,
171
+ loader: 'js',
172
+ }
173
+ }
174
+
175
+ if (modified) {
176
+ return {
177
+ contents,
178
+ loader: args.path.endsWith('.tsx')
179
+ ? 'tsx'
180
+ : args.path.endsWith('.ts')
181
+ ? 'ts'
182
+ : args.path.endsWith('.jsx')
183
+ ? 'jsx'
184
+ : 'js',
185
+ }
186
+ }
187
+
188
+ return null
189
+ })
190
+ },
191
+ }
192
+
193
+ // base options for transformSync (no plugins)
194
+ const esbuildTransformOptions = {
195
+ target: 'es2022',
60
196
  format: 'cjs',
61
197
  jsx: 'automatic',
62
198
  platform: 'node',
63
199
  ...esbuildExtraOptions,
200
+ } satisfies esbuild.TransformOptions
201
+
202
+ // options for buildSync - NO plugins (buildSync doesn't support plugins)
203
+ export const esbuildOptions = {
204
+ ...esbuildTransformOptions,
205
+ } satisfies esbuild.BuildOptions
206
+
207
+ // options for async build (with plugins)
208
+ export const esbuildOptionsWithPlugins = {
209
+ ...esbuildTransformOptions,
210
+ plugins: [handleEsmFeaturesPlugin],
64
211
  } satisfies esbuild.BuildOptions
65
212
 
66
213
  export type BundledConfig = Exclude<Awaited<ReturnType<typeof bundleConfig>>, undefined>
@@ -122,17 +269,31 @@ export async function bundleConfig(props: TamaguiOptions) {
122
269
  ? getTamaguiConfigPathFromOptionsConfig(props.config)
123
270
  : ''
124
271
  const tmpDir = join(process.cwd(), '.tamagui')
125
- const configOutPath = join(tmpDir, `tamagui.config.cjs`)
272
+ // detect module format from config entry point
273
+ const configFormat = configEntry ? detectModuleFormat(configEntry) : 'cjs'
274
+ const configExt = configFormat === 'esm' ? '.mjs' : '.cjs'
275
+ const configOutPath = join(tmpDir, `tamagui.config${configExt}`)
126
276
  const baseComponents = (props.components || []).filter((x) => x !== '@tamagui/core')
127
- const componentOutPaths = baseComponents.map((componentModule) =>
128
- join(
277
+ // detect format per component module
278
+ const componentFormats: Array<'esm' | 'cjs'> = baseComponents.map((mod) => {
279
+ try {
280
+ const pkgJson = require.resolve(mod + '/package.json')
281
+ const pkg = JSON.parse(readFileSync(pkgJson, 'utf-8'))
282
+ return pkg.type === 'module' ? 'esm' : 'cjs'
283
+ } catch {
284
+ return 'cjs'
285
+ }
286
+ })
287
+ const componentOutPaths = baseComponents.map((componentModule, i) => {
288
+ const ext = componentFormats[i] === 'esm' ? '.mjs' : '.cjs'
289
+ return join(
129
290
  tmpDir,
130
291
  `${componentModule
131
292
  .split(sep)
132
293
  .join('-')
133
- .replace(/[^a-z0-9]+/gi, '')}-components.config.cjs`
294
+ .replace(/[^a-z0-9]+/gi, '')}-components.config${ext}`
134
295
  )
135
- )
296
+ })
136
297
 
137
298
  if (
138
299
  process.env.NODE_ENV === 'development' &&
@@ -141,7 +302,29 @@ export async function bundleConfig(props: TamaguiOptions) {
141
302
  console.info(`Building config entry`, configEntry)
142
303
  }
143
304
 
144
- if (!props.disableInitialBuild) {
305
+ // check if ALL output files (config + components) already exist and are recent
306
+ // (built by another worker) - this prevents duplicate builds across worker threads
307
+ // we must check ALL files, not just the config, to avoid a race where another
308
+ // worker has written the config but not yet finished writing component files
309
+ let shouldBuild = !props.disableInitialBuild
310
+ if (shouldBuild && props.config) {
311
+ const allOutFiles = [configOutPath, ...componentOutPaths]
312
+ try {
313
+ const stats = await Promise.all(
314
+ allOutFiles.map((f) => FS.stat(f).catch(() => null))
315
+ )
316
+ const allExistAndRecent = stats.every(
317
+ (s) => s !== null && Date.now() - s.mtimeMs < 3000
318
+ )
319
+ if (allExistAndRecent) {
320
+ shouldBuild = false
321
+ }
322
+ } catch {
323
+ // something went wrong checking files, just build
324
+ }
325
+ }
326
+
327
+ if (shouldBuild) {
145
328
  // build them to node-compat versions
146
329
  try {
147
330
  await FS.ensureDir(tmpDir)
@@ -158,7 +341,8 @@ export async function bundleConfig(props: TamaguiOptions) {
158
341
  entryPoints: [configEntry],
159
342
  external,
160
343
  outfile: configOutPath,
161
- target: 'node20',
344
+ target: 'node24',
345
+ format: configFormat,
162
346
  ...esbuildExtraOptions,
163
347
  },
164
348
  props.platform || 'web'
@@ -171,7 +355,8 @@ export async function bundleConfig(props: TamaguiOptions) {
171
355
  resolvePlatformSpecificEntries: true,
172
356
  external,
173
357
  outfile: componentOutPaths[i],
174
- target: 'node20',
358
+ target: 'node24',
359
+ format: componentFormats[i],
175
360
  ...esbuildExtraOptions,
176
361
  },
177
362
  props.platform || 'web'
@@ -201,25 +386,32 @@ export async function bundleConfig(props: TamaguiOptions) {
201
386
  }
202
387
  }
203
388
 
204
- let out
205
- const { unregister } = registerRequire(props.platform || 'web')
206
- try {
207
- if (hasBundledOnce) {
208
- // this did cause mini-css-extract plugin to freak out
209
- // clear cache to get new files
210
- for (const key in require.cache) {
211
- // avoid clearing core/web it seems to break things
212
- if (!/(core|web)[/\\]dist/.test(key)) {
213
- delete require.cache[key]
214
- }
389
+ // clear specific output file caches so we pick up the fresh (or newly discovered) build
390
+ // only clear the built output files - not all require.cache entries, since that breaks
391
+ // external requires like @tamagui/config/v3 that are externalized in the bundled CJS
392
+ if (hasBundledOnce) {
393
+ try {
394
+ delete require.cache[require.resolve(configOutPath)]
395
+ } catch {
396
+ // file may not exist yet
397
+ }
398
+ for (const p of componentOutPaths) {
399
+ try {
400
+ delete require.cache[require.resolve(p)]
401
+ } catch {
402
+ // file may not exist yet
215
403
  }
216
- } else {
217
- hasBundledOnce = true
218
404
  }
405
+ } else {
406
+ hasBundledOnce = true
407
+ }
219
408
 
409
+ let out: any
410
+ if (configFormat === 'esm') {
411
+ // use file:// URL for proper ESM resolution
412
+ out = await import(pathToFileURL(configOutPath).href)
413
+ } else {
220
414
  out = require(configOutPath)
221
- } finally {
222
- unregister()
223
415
  }
224
416
 
225
417
  // try and find .config, even if on .default
@@ -232,6 +424,13 @@ export async function bundleConfig(props: TamaguiOptions) {
232
424
  throw new Error(`No config: ${config}`)
233
425
  }
234
426
 
427
+ // check for ProxyWorm - indicates a module loading error
428
+ if (config._isProxyWorm) {
429
+ throw new Error(
430
+ `Got a proxied config - likely a module loading error. Set DEBUG=tamagui for details.`
431
+ )
432
+ }
433
+
235
434
  loadedConfig = config
236
435
 
237
436
  if (!config.parsed) {
@@ -244,7 +443,7 @@ export async function bundleConfig(props: TamaguiOptions) {
244
443
  await writeTamaguiCSS(props.outputCSS, config)
245
444
  }
246
445
 
247
- let components = loadComponents({
446
+ let components = await loadComponents({
248
447
  ...props,
249
448
  components: componentOutPaths,
250
449
  })
@@ -322,14 +521,20 @@ export async function writeTamaguiCSS(outputCSS: string, config: TamaguiInternal
322
521
  }
323
522
  }
324
523
 
325
- export function loadComponents(props: TamaguiOptions, forceExports = false) {
326
- const coreComponents = getCoreComponents(props)
327
- const otherComponents = loadComponentsInner(props, forceExports)
524
+ export async function loadComponents(props: TamaguiOptions, forceExports = false) {
525
+ const coreComponents = getCoreComponentsSync(props)
526
+ const otherComponents = await loadComponentsInner(props, forceExports)
328
527
  return [...coreComponents, ...(otherComponents || [])]
329
528
  }
330
529
 
331
- function getCoreComponents(props: TamaguiOptions) {
332
- const loaded = loadComponentsInner({
530
+ export function loadComponentsSync(props: TamaguiOptions, forceExports = false) {
531
+ const coreComponents = getCoreComponentsSync(props)
532
+ const otherComponents = loadComponentsInnerSync(props, forceExports)
533
+ return [...coreComponents, ...(otherComponents || [])]
534
+ }
535
+
536
+ function getCoreComponentsSync(props: TamaguiOptions) {
537
+ const loaded = loadComponentsInnerSync({
333
538
  ...props,
334
539
  components: ['@tamagui/core'],
335
540
  })
@@ -347,13 +552,172 @@ function getCoreComponents(props: TamaguiOptions) {
347
552
  ]
348
553
  }
349
554
 
350
- export function loadComponentsInner(
555
+ export async function loadComponentsInner(
556
+ props: TamaguiOptions,
557
+ forceExports = false
558
+ ): Promise<null | LoadedComponents[]> {
559
+ const componentsModules = props.components || []
560
+
561
+ const key = componentsModules.join('\0')
562
+
563
+ if (!forceExports && cacheComponents[key]) {
564
+ return cacheComponents[key]
565
+ }
566
+
567
+ const { unregister } = registerRequire(props.platform || 'web', {
568
+ proxyWormImports: forceExports,
569
+ })
570
+
571
+ try {
572
+ const results: LoadedComponents[] = []
573
+
574
+ for (const name of componentsModules) {
575
+ const extension = extname(name)
576
+ const isLocal = Boolean(extension)
577
+ const isDynamic = isLocal && forceExports
578
+ const format = isLocal ? detectModuleFormat(name) : ('cjs' as const)
579
+
580
+ const fileContents = isDynamic ? readFileSync(name, 'utf-8') : ''
581
+ let loadModule = name
582
+ let writtenContents = fileContents
583
+ let didBabel = false
584
+
585
+ const attemptLoad = async ({ forceExports = false } = {}) => {
586
+ if (isDynamic) {
587
+ writtenContents = forceExports
588
+ ? transformAddExports(babelParse(esbuildit(fileContents, 'modern'), name))
589
+ : fileContents
590
+ loadModule = getDynamicEvalOutfile(name, format, writtenContents)
591
+
592
+ FS.ensureDirSync(dirname(loadModule))
593
+ activeTempFiles.add(loadModule)
594
+
595
+ await esbuild.build({
596
+ ...esbuildOptionsWithPlugins,
597
+ format,
598
+ outfile: loadModule,
599
+ stdin: {
600
+ contents: writtenContents,
601
+ resolveDir: dirname(name),
602
+ sourcefile: name,
603
+ loader: getEsbuildStdinLoader(name),
604
+ },
605
+ alias: {
606
+ 'react-native': resolvePackageEntry(
607
+ '@tamagui/react-native-web-lite',
608
+ format
609
+ ),
610
+ '@tamagui/react-native-web-lite': resolvePackageEntry(
611
+ '@tamagui/react-native-web-lite',
612
+ format
613
+ ),
614
+ '@tamagui/react-native-web-internals': resolvePackageEntry(
615
+ '@tamagui/react-native-web-internals',
616
+ format
617
+ ),
618
+ },
619
+ bundle: true,
620
+ packages: 'external',
621
+ allowOverwrite: true,
622
+ sourcemap: false,
623
+ loader: esbuildLoaderConfig,
624
+ })
625
+ }
626
+
627
+ if (process.env.DEBUG === 'tamagui') {
628
+ console.info(`loadModule`, loadModule, format)
629
+ }
630
+
631
+ let moduleResult: any
632
+ if (format === 'esm') {
633
+ // use file:// URL for proper ESM resolution
634
+ moduleResult = await import(pathToFileURL(loadModule).href)
635
+ } else {
636
+ moduleResult = require(loadModule)
637
+ }
638
+
639
+ if (!forceExports) {
640
+ setRequireResult(name, moduleResult)
641
+ }
642
+
643
+ const nameToInfo = getComponentStaticConfigByName(
644
+ name,
645
+ interopDefaultExport(moduleResult)
646
+ )
647
+
648
+ return {
649
+ moduleName: name,
650
+ nameToInfo,
651
+ }
652
+ }
653
+
654
+ const dispose = () => {
655
+ if (isDynamic) {
656
+ FS.removeSync(loadModule)
657
+ activeTempFiles.delete(loadModule)
658
+ }
659
+ }
660
+
661
+ let loaded: LoadedComponents | LoadedComponents[] | undefined
662
+
663
+ try {
664
+ loaded = await attemptLoad({ forceExports: true })
665
+ didBabel = true
666
+ } catch (err) {
667
+ console.info('babel err', err, writtenContents)
668
+ writtenContents = fileContents
669
+ if (process.env.DEBUG?.startsWith('tamagui')) {
670
+ console.info(`Error parsing babel likely`, err)
671
+ }
672
+
673
+ try {
674
+ loaded = await attemptLoad({ forceExports: false })
675
+ } catch (err2) {
676
+ if (process.env.TAMAGUI_ENABLE_WARN_DYNAMIC_LOAD) {
677
+ console.info(
678
+ `\nTamagui attempted but failed to dynamically optimize components in:\n ${name}\n`
679
+ )
680
+ console.info(err2)
681
+ console.info(
682
+ `At: ${loadModule}`,
683
+ `\ndidBabel: ${didBabel}`,
684
+ `\nIn:`,
685
+ writtenContents,
686
+ `\nisDynamic: `,
687
+ isDynamic
688
+ )
689
+ }
690
+ loaded = []
691
+ }
692
+ } finally {
693
+ dispose()
694
+ }
695
+
696
+ if (Array.isArray(loaded)) {
697
+ results.push(...loaded)
698
+ } else if (loaded) {
699
+ results.push(loaded)
700
+ }
701
+ }
702
+
703
+ cacheComponents[key] = results
704
+ return results
705
+ } catch (err: any) {
706
+ console.info(`Tamagui error bundling components`, err.message, err.stack)
707
+ return null
708
+ } finally {
709
+ unregister()
710
+ }
711
+ }
712
+
713
+ // sync version - uses cjs format for buildSync (no plugin support)
714
+ export function loadComponentsInnerSync(
351
715
  props: TamaguiOptions,
352
716
  forceExports = false
353
717
  ): null | LoadedComponents[] {
354
718
  const componentsModules = props.components || []
355
719
 
356
- const key = componentsModules.join('')
720
+ const key = componentsModules.join('\0')
357
721
 
358
722
  if (!forceExports && cacheComponents[key]) {
359
723
  return cacheComponents[key]
@@ -370,32 +734,46 @@ export function loadComponentsInner(
370
734
  const isDynamic = isLocal && forceExports
371
735
 
372
736
  const fileContents = isDynamic ? readFileSync(name, 'utf-8') : ''
373
- const loadModule = isDynamic
374
- ? join(dirname(name), `.tamagui-dynamic-eval-${basename(name)}.tsx`)
375
- : name
737
+ let loadModule = name
376
738
  let writtenContents = fileContents
377
739
  let didBabel = false
378
740
 
379
741
  function attemptLoad({ forceExports = false } = {}) {
380
- // need to write to tsx to enable reading it properly (:/ esbuild-register)
381
742
  if (isDynamic) {
382
743
  writtenContents = forceExports
383
744
  ? transformAddExports(babelParse(esbuildit(fileContents, 'modern'), name))
384
745
  : fileContents
746
+ loadModule = getDynamicEvalOutfile(name, 'cjs', writtenContents)
385
747
 
386
- FS.writeFileSync(loadModule, writtenContents)
748
+ FS.ensureDirSync(dirname(loadModule))
749
+ activeTempFiles.add(loadModule)
387
750
 
388
751
  esbuild.buildSync({
389
752
  ...esbuildOptions,
390
- entryPoints: [loadModule],
391
753
  outfile: loadModule,
754
+ stdin: {
755
+ contents: writtenContents,
756
+ resolveDir: dirname(name),
757
+ sourcefile: name,
758
+ loader: getEsbuildStdinLoader(name),
759
+ },
392
760
  alias: {
393
- 'react-native': require.resolve('@tamagui/react-native-web-lite'),
761
+ 'react-native': resolvePackageEntry(
762
+ '@tamagui/react-native-web-lite',
763
+ 'esm'
764
+ ),
765
+ '@tamagui/react-native-web-lite': resolvePackageEntry(
766
+ '@tamagui/react-native-web-lite',
767
+ 'esm'
768
+ ),
769
+ '@tamagui/react-native-web-internals': resolvePackageEntry(
770
+ '@tamagui/react-native-web-internals',
771
+ 'esm'
772
+ ),
394
773
  },
395
774
  bundle: true,
396
775
  packages: 'external',
397
776
  allowOverwrite: true,
398
- // logLevel: 'silent',
399
777
  sourcemap: false,
400
778
  loader: esbuildLoaderConfig,
401
779
  })
@@ -423,18 +801,18 @@ export function loadComponentsInner(
423
801
  }
424
802
 
425
803
  const dispose = () => {
426
- isDynamic && FS.removeSync(loadModule)
804
+ if (isDynamic) {
805
+ FS.removeSync(loadModule)
806
+ activeTempFiles.delete(loadModule)
807
+ }
427
808
  }
428
809
 
429
810
  try {
430
- const res = attemptLoad({
431
- forceExports: true,
432
- })
811
+ const res = attemptLoad({ forceExports: true })
433
812
  didBabel = true
434
813
  return res
435
814
  } catch (err) {
436
815
  console.info('babel err', err, writtenContents)
437
- // ok
438
816
  writtenContents = fileContents
439
817
  if (process.env.DEBUG?.startsWith('tamagui')) {
440
818
  console.info(`Error parsing babel likely`, err)
@@ -444,16 +822,12 @@ export function loadComponentsInner(
444
822
  }
445
823
 
446
824
  try {
447
- return attemptLoad({
448
- forceExports: false,
449
- })
825
+ return attemptLoad({ forceExports: false })
450
826
  } catch (err) {
451
827
  if (process.env.TAMAGUI_ENABLE_WARN_DYNAMIC_LOAD) {
452
- console.info(`
453
-
454
- Tamagui attempted but failed to dynamically optimize components in:
455
- ${name}
456
- `)
828
+ console.info(
829
+ `\nTamagui attempted but failed to dynamically optimize components in:\n ${name}\n`
830
+ )
457
831
  console.info(err)
458
832
  console.info(
459
833
  `At: ${loadModule}`,
@@ -481,7 +855,7 @@ Tamagui attempted but failed to dynamically optimize components in:
481
855
 
482
856
  const esbuildit = (src: string, target?: 'modern') => {
483
857
  return esbuild.transformSync(src, {
484
- ...esbuildOptions,
858
+ ...esbuildTransformOptions,
485
859
  ...(target === 'modern' && {
486
860
  target: 'es2022',
487
861
  jsx: 'automatic',