@tamagui/static 2.0.0-rc.8 → 2.0.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 (186) hide show
  1. package/dist/check-dep-versions.cjs +201 -96
  2. package/dist/checkDeps.cjs +250 -46
  3. package/dist/constants.cjs +32 -30
  4. package/dist/exports.cjs +20 -13
  5. package/dist/extractor/accessSafe.cjs +25 -23
  6. package/dist/extractor/babelParse.cjs +30 -28
  7. package/dist/extractor/buildClassName.cjs +59 -35
  8. package/dist/extractor/bundle.cjs +187 -101
  9. package/dist/extractor/bundleConfig.cjs +568 -168
  10. package/dist/extractor/concatClassName.cjs +73 -32
  11. package/dist/extractor/createEvaluator.cjs +54 -41
  12. package/dist/extractor/createExtractor.cjs +1405 -574
  13. package/dist/extractor/createLogger.cjs +30 -25
  14. package/dist/extractor/detectModuleFormat.cjs +55 -0
  15. package/dist/extractor/ensureImportingConcat.cjs +31 -25
  16. package/dist/extractor/errors.cjs +12 -10
  17. package/dist/extractor/esbuildAliasPlugin.cjs +28 -16
  18. package/dist/extractor/esbuildTsconfigPaths.cjs +60 -36
  19. package/dist/extractor/evaluateAstNode.cjs +104 -59
  20. package/dist/extractor/extractHelpers.cjs +130 -67
  21. package/dist/extractor/extractMediaStyle.cjs +110 -69
  22. package/dist/extractor/extractToClassNames.cjs +337 -229
  23. package/dist/extractor/extractToNative.cjs +248 -154
  24. package/dist/extractor/findTopmostFunction.cjs +22 -13
  25. package/dist/extractor/generatedUid.cjs +39 -28
  26. package/dist/extractor/getPrefixLogs.cjs +12 -10
  27. package/dist/extractor/getPropValueFromAttributes.cjs +52 -34
  28. package/dist/extractor/getSourceModule.cjs +73 -37
  29. package/dist/extractor/getStaticBindingsForScope.cjs +131 -68
  30. package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.cjs +20 -14
  31. package/dist/extractor/hasTopLevelAwait.cjs +62 -0
  32. package/dist/extractor/hoistClassNames.cjs +46 -32
  33. package/dist/extractor/literalToAst.cjs +67 -42
  34. package/dist/extractor/loadFile.cjs +9 -3
  35. package/dist/extractor/loadTamagui.cjs +151 -105
  36. package/dist/extractor/logLines.cjs +27 -19
  37. package/dist/extractor/normalizeTernaries.cjs +66 -44
  38. package/dist/extractor/propsToFontFamilyCache.cjs +15 -11
  39. package/dist/extractor/regenerateConfig.cjs +109 -81
  40. package/dist/extractor/removeUnusedHooks.cjs +73 -41
  41. package/dist/extractor/timer.cjs +23 -14
  42. package/dist/extractor/validHTMLAttributes.cjs +61 -59
  43. package/dist/extractor/watchTamaguiConfig.cjs +35 -23
  44. package/dist/getPragmaOptions.cjs +34 -19
  45. package/dist/helpers/memoize.cjs +24 -16
  46. package/dist/helpers/requireTamaguiCore.cjs +22 -15
  47. package/dist/index.cjs +26 -24
  48. package/dist/registerRequire.cjs +168 -65
  49. package/dist/server.cjs +35 -28
  50. package/dist/types.cjs +7 -5
  51. package/dist/worker.cjs +62 -40
  52. package/package.json +27 -24
  53. package/src/checkDeps.ts +305 -68
  54. package/src/exports.ts +2 -0
  55. package/src/extractor/babelParse.ts +1 -0
  56. package/src/extractor/bundle.ts +172 -40
  57. package/src/extractor/bundleConfig.ts +459 -65
  58. package/src/extractor/concatClassName.ts +37 -20
  59. package/src/extractor/createExtractor.ts +300 -30
  60. package/src/extractor/detectModuleFormat.ts +42 -0
  61. package/src/extractor/esbuildTsconfigPaths.ts +6 -1
  62. package/src/extractor/extractToClassNames.ts +15 -9
  63. package/src/extractor/extractToNative.ts +66 -33
  64. package/src/extractor/hasTopLevelAwait.ts +28 -0
  65. package/src/extractor/loadTamagui.ts +5 -4
  66. package/src/registerRequire.ts +102 -9
  67. package/types/checkDeps.d.ts.map +1 -1
  68. package/types/exports.d.ts +2 -0
  69. package/types/exports.d.ts.map +1 -1
  70. package/types/extractor/babelParse.d.ts.map +1 -1
  71. package/types/extractor/bundle.d.ts +83 -1
  72. package/types/extractor/bundle.d.ts.map +1 -1
  73. package/types/extractor/bundleConfig.d.ts +15 -2
  74. package/types/extractor/bundleConfig.d.ts.map +1 -1
  75. package/types/extractor/createExtractor.d.ts.map +1 -1
  76. package/types/extractor/detectModuleFormat.d.ts +5 -0
  77. package/types/extractor/detectModuleFormat.d.ts.map +1 -0
  78. package/types/extractor/esbuildTsconfigPaths.d.ts +8 -0
  79. package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -1
  80. package/types/extractor/extractToClassNames.d.ts.map +1 -1
  81. package/types/extractor/extractToNative.d.ts.map +1 -1
  82. package/types/extractor/hasTopLevelAwait.d.ts +2 -0
  83. package/types/extractor/hasTopLevelAwait.d.ts.map +1 -0
  84. package/types/extractor/loadTamagui.d.ts +1 -1
  85. package/types/extractor/loadTamagui.d.ts.map +1 -1
  86. package/types/registerRequire.d.ts.map +1 -1
  87. package/dist/check-dep-versions.js +0 -389
  88. package/dist/check-dep-versions.js.map +0 -6
  89. package/dist/checkDeps.js +0 -60
  90. package/dist/checkDeps.js.map +0 -6
  91. package/dist/constants.js +0 -34
  92. package/dist/constants.js.map +0 -6
  93. package/dist/exports.js +0 -34
  94. package/dist/exports.js.map +0 -6
  95. package/dist/extractor/accessSafe.js +0 -47
  96. package/dist/extractor/accessSafe.js.map +0 -6
  97. package/dist/extractor/babelParse.js +0 -59
  98. package/dist/extractor/babelParse.js.map +0 -6
  99. package/dist/extractor/buildClassName.js +0 -72
  100. package/dist/extractor/buildClassName.js.map +0 -6
  101. package/dist/extractor/bundle.js +0 -135
  102. package/dist/extractor/bundle.js.map +0 -6
  103. package/dist/extractor/bundleConfig.js +0 -352
  104. package/dist/extractor/bundleConfig.js.map +0 -6
  105. package/dist/extractor/concatClassName.js +0 -69
  106. package/dist/extractor/concatClassName.js.map +0 -6
  107. package/dist/extractor/createEvaluator.js +0 -66
  108. package/dist/extractor/createEvaluator.js.map +0 -6
  109. package/dist/extractor/createExtractor.js +0 -1212
  110. package/dist/extractor/createExtractor.js.map +0 -6
  111. package/dist/extractor/createLogger.js +0 -32
  112. package/dist/extractor/createLogger.js.map +0 -6
  113. package/dist/extractor/ensureImportingConcat.js +0 -50
  114. package/dist/extractor/ensureImportingConcat.js.map +0 -6
  115. package/dist/extractor/errors.js +0 -22
  116. package/dist/extractor/errors.js.map +0 -6
  117. package/dist/extractor/esbuildAliasPlugin.js +0 -36
  118. package/dist/extractor/esbuildAliasPlugin.js.map +0 -6
  119. package/dist/extractor/esbuildTsconfigPaths.js +0 -79
  120. package/dist/extractor/esbuildTsconfigPaths.js.map +0 -6
  121. package/dist/extractor/evaluateAstNode.js +0 -99
  122. package/dist/extractor/evaluateAstNode.js.map +0 -6
  123. package/dist/extractor/extractHelpers.js +0 -108
  124. package/dist/extractor/extractHelpers.js.map +0 -6
  125. package/dist/extractor/extractMediaStyle.js +0 -123
  126. package/dist/extractor/extractMediaStyle.js.map +0 -6
  127. package/dist/extractor/extractToClassNames.js +0 -351
  128. package/dist/extractor/extractToClassNames.js.map +0 -6
  129. package/dist/extractor/extractToNative.js +0 -286
  130. package/dist/extractor/extractToNative.js.map +0 -6
  131. package/dist/extractor/findTopmostFunction.js +0 -32
  132. package/dist/extractor/findTopmostFunction.js.map +0 -6
  133. package/dist/extractor/generatedUid.js +0 -42
  134. package/dist/extractor/generatedUid.js.map +0 -6
  135. package/dist/extractor/getPrefixLogs.js +0 -24
  136. package/dist/extractor/getPrefixLogs.js.map +0 -6
  137. package/dist/extractor/getPropValueFromAttributes.js +0 -65
  138. package/dist/extractor/getPropValueFromAttributes.js.map +0 -6
  139. package/dist/extractor/getSourceModule.js +0 -62
  140. package/dist/extractor/getSourceModule.js.map +0 -6
  141. package/dist/extractor/getStaticBindingsForScope.js +0 -145
  142. package/dist/extractor/getStaticBindingsForScope.js.map +0 -6
  143. package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.js +0 -32
  144. package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.js.map +0 -6
  145. package/dist/extractor/hoistClassNames.js +0 -63
  146. package/dist/extractor/hoistClassNames.js.map +0 -6
  147. package/dist/extractor/literalToAst.js +0 -90
  148. package/dist/extractor/literalToAst.js.map +0 -6
  149. package/dist/extractor/loadFile.js +0 -14
  150. package/dist/extractor/loadFile.js.map +0 -6
  151. package/dist/extractor/loadTamagui.js +0 -306
  152. package/dist/extractor/loadTamagui.js.map +0 -6
  153. package/dist/extractor/logLines.js +0 -30
  154. package/dist/extractor/logLines.js.map +0 -6
  155. package/dist/extractor/normalizeTernaries.js +0 -61
  156. package/dist/extractor/normalizeTernaries.js.map +0 -6
  157. package/dist/extractor/propsToFontFamilyCache.js +0 -33
  158. package/dist/extractor/propsToFontFamilyCache.js.map +0 -6
  159. package/dist/extractor/regenerateConfig.js +0 -123
  160. package/dist/extractor/regenerateConfig.js.map +0 -6
  161. package/dist/extractor/removeUnusedHooks.js +0 -72
  162. package/dist/extractor/removeUnusedHooks.js.map +0 -6
  163. package/dist/extractor/timer.js +0 -38
  164. package/dist/extractor/timer.js.map +0 -6
  165. package/dist/extractor/validHTMLAttributes.js +0 -72
  166. package/dist/extractor/validHTMLAttributes.js.map +0 -6
  167. package/dist/extractor/watchTamaguiConfig.js +0 -57
  168. package/dist/extractor/watchTamaguiConfig.js.map +0 -6
  169. package/dist/getPragmaOptions.js +0 -50
  170. package/dist/getPragmaOptions.js.map +0 -6
  171. package/dist/helpers/memoize.js +0 -33
  172. package/dist/helpers/memoize.js.map +0 -6
  173. package/dist/helpers/requireTamaguiCore.js +0 -30
  174. package/dist/helpers/requireTamaguiCore.js.map +0 -6
  175. package/dist/index.js +0 -30
  176. package/dist/index.js.map +0 -6
  177. package/dist/registerRequire.js +0 -100
  178. package/dist/registerRequire.js.map +0 -6
  179. package/dist/server.js +0 -58
  180. package/dist/server.js.map +0 -6
  181. package/dist/setup.js +0 -1
  182. package/dist/setup.js.map +0 -6
  183. package/dist/types.js +0 -14
  184. package/dist/types.js.map +0 -6
  185. package/dist/worker.js +0 -72
  186. package/dist/worker.js.map +0 -6
@@ -1,8 +1,10 @@
1
- import { basename, dirname, join } from 'node:path'
1
+ import { readFileSync } from 'node:fs'
2
2
  import esbuild from 'esbuild'
3
3
  import * as FS from 'fs-extra'
4
4
  import type { TamaguiPlatform } from '../types'
5
+ import { detectModuleFormat } from './detectModuleFormat'
5
6
  import { esbuildAliasPlugin } from './esbuildAliasPlugin'
7
+ import { hasTopLevelAwait } from './hasTopLevelAwait'
6
8
  import { resolveWebOrNativeSpecificEntry } from './loadTamagui'
7
9
  import { TsconfigPathsPlugin } from './esbuildTsconfigPaths'
8
10
 
@@ -51,7 +53,12 @@ type Props = Omit<Partial<esbuild.BuildOptions>, 'entryPoints'> & {
51
53
  }
52
54
 
53
55
  function getESBuildConfig(
54
- { entryPoints, resolvePlatformSpecificEntries, ...options }: Props,
56
+ {
57
+ entryPoints,
58
+ resolvePlatformSpecificEntries,
59
+ define: callerDefine,
60
+ ...options
61
+ }: Props,
55
62
  platform: TamaguiPlatform,
56
63
  aliases?: Record<string, string>
57
64
  ) {
@@ -61,19 +68,55 @@ function getESBuildConfig(
61
68
 
62
69
  const resolvedEntryPoints = !resolvePlatformSpecificEntries
63
70
  ? entryPoints
64
- : entryPoints.map(resolveWebOrNativeSpecificEntry)
71
+ : entryPoints.map((entry) => resolveWebOrNativeSpecificEntry(entry, platform))
72
+
73
+ // detect format from entry points if not explicitly provided by caller
74
+ const detectedFormat = options.format || detectEntryFormat(resolvedEntryPoints[0])
75
+
76
+ // inline platform env vars for the bundled config + components.
77
+ // the bundled output runs in node afterward (CSS extraction time), at which
78
+ // point process.env reflects whatever the build tool's parent process had —
79
+ // not necessarily the platform we're bundling for. inlining via esbuild's
80
+ // define makes the bundle self-consistent regardless of host env, which
81
+ // matters most for vite/vxrn (which doesn't set TAMAGUI_TARGET globally
82
+ // because the same plugin handles native too) and for any code in the bundle
83
+ // graph that reads EXPO_OS (expo-modules-core's Platform.OS, etc.).
84
+ const platformDefines: Record<string, string> =
85
+ platform === 'web'
86
+ ? {
87
+ 'process.env.TAMAGUI_TARGET': '"web"',
88
+ 'process.env.EXPO_OS': '"web"',
89
+ }
90
+ : {
91
+ 'process.env.TAMAGUI_TARGET': '"native"',
92
+ // EXPO_OS doesn't have a useful "native" value (it's ios/android),
93
+ // so leave it alone here and let the consumer set it if needed.
94
+ }
65
95
 
66
96
  const res: esbuild.BuildOptions = {
67
97
  bundle: true,
68
98
  entryPoints: resolvedEntryPoints,
69
- format: 'cjs',
70
- target: 'node20',
99
+ format: detectedFormat,
100
+ define: {
101
+ ...platformDefines,
102
+ ...callerDefine,
103
+ },
104
+ // for ESM: prefer "module" field for resolution, add require() shim for bundled CJS deps
105
+ ...(detectedFormat === 'esm'
106
+ ? {
107
+ mainFields: ['module', 'main'],
108
+ banner: {
109
+ js: 'import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);',
110
+ },
111
+ }
112
+ : {}),
113
+ target: 'node24',
71
114
  jsx: 'transform',
72
115
  jsxFactory: 'react',
73
116
  allowOverwrite: true,
74
117
  keepNames: true,
75
118
  resolveExtensions: [
76
- ...(process.env.TAMAGUI_TARGET === 'web'
119
+ ...(platform === 'web'
77
120
  ? ['.web.tsx', '.web.ts', '.web.jsx', '.web.js']
78
121
  : ['.native.tsx', '.native.ts', '.native.jsx', '.native.js']),
79
122
  '.tsx',
@@ -92,38 +135,125 @@ function getESBuildConfig(
92
135
  plugins: [
93
136
  TsconfigPathsPlugin(),
94
137
 
138
+ // handle ESM-only features that can't be used with CJS output
139
+ {
140
+ name: 'handle-esm-features',
141
+ setup(build) {
142
+ // only apply transforms for CJS output - ESM supports these natively
143
+ const isCjs =
144
+ build.initialOptions.format === 'cjs' || !build.initialOptions.format
145
+
146
+ build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs)$/ }, (args) => {
147
+ // skip if ESM output - import.meta and top-level await work natively
148
+ if (!isCjs) {
149
+ return null
150
+ }
151
+
152
+ // skip most node_modules
153
+ if (args.path.includes('node_modules') && !args.path.includes('@tamagui')) {
154
+ return null
155
+ }
156
+
157
+ let contents = readFileSync(args.path, 'utf8')
158
+ let modified = false
159
+
160
+ // transform import.meta.env -> process.env (Vite-style env vars)
161
+ if (contents.includes('import.meta.env')) {
162
+ contents = contents.replace(/import\.meta\.env/g, 'process.env')
163
+ modified = true
164
+ }
165
+
166
+ // transform import.meta.url -> "" (not needed for static extraction)
167
+ if (contents.includes('import.meta.url')) {
168
+ contents = contents.replace(/import\.meta\.url/g, '""')
169
+ modified = true
170
+ }
171
+
172
+ // transform import.meta.main -> false
173
+ if (contents.includes('import.meta.main')) {
174
+ contents = contents.replace(/import\.meta\.main/g, 'false')
175
+ modified = true
176
+ }
177
+
178
+ // stub files with top-level await - they're typically runtime-only
179
+ if (hasTopLevelAwait(contents, args.path)) {
180
+ if (process.env.DEBUG?.startsWith('tamagui')) {
181
+ console.info(`[tamagui] stubbing file with top-level await: ${args.path}`)
182
+ }
183
+ return {
184
+ // Keep this as an ESM-shaped stub so esbuild doesn't inline a
185
+ // top-level `module.exports = {}` into the parent bundle.
186
+ contents: `// stubbed - contains top-level await\nexport default {}`,
187
+ loader: 'js',
188
+ }
189
+ }
190
+
191
+ if (modified) {
192
+ return {
193
+ contents,
194
+ loader: args.path.endsWith('.tsx')
195
+ ? 'tsx'
196
+ : args.path.endsWith('.ts')
197
+ ? 'ts'
198
+ : args.path.endsWith('.jsx')
199
+ ? 'jsx'
200
+ : 'js',
201
+ }
202
+ }
203
+
204
+ return null
205
+ })
206
+ },
207
+ },
208
+
95
209
  {
96
210
  name: 'external',
97
211
  setup(build) {
98
- build.onResolve({ filter: /@tamagui\/core/ }, (args) => {
212
+ const proxyWormPath = require.resolve('@tamagui/proxy-worm')
213
+
214
+ // only externalize @tamagui/core and @tamagui/web - these are provided at runtime
215
+ // other @tamagui/* packages (like @tamagui/config/v3) must be bundled in to avoid
216
+ // ESM race conditions when multiple threads require() them concurrently
217
+ build.onResolve({ filter: /^@tamagui\/(core|web)$/ }, (args) => {
218
+ if (args.kind === 'entry-point') {
219
+ return null
220
+ }
99
221
  return {
100
- path: platform === 'native' ? '@tamagui/core/native' : '@tamagui/core',
222
+ path: platform === 'native' ? '@tamagui/core/native' : args.path,
101
223
  external: true,
102
224
  }
103
225
  })
104
- build.onResolve({ filter: /react-native\/package.json$/ }, (args) => {
226
+
227
+ build.onResolve({ filter: /react-native\/package.json$/ }, () => {
105
228
  return {
106
229
  path: 'react-native/package.json',
107
230
  external: true,
108
231
  }
109
232
  })
110
- build.onResolve({ filter: /@tamagui\/web/ }, (args) => {
233
+
234
+ build.onResolve({ filter: /^(react-native|react-native\/.*)$/ }, () => {
111
235
  return {
112
- path: platform === 'native' ? '@tamagui/core/native' : '@tamagui/core',
236
+ path: '@tamagui/react-native-web-lite',
113
237
  external: true,
114
238
  }
115
239
  })
116
240
 
117
- build.onResolve({ filter: /^(react-native|react-native\/.*)$/ }, (args) => {
241
+ build.onResolve({ filter: /^react-native-reanimated(?:\/.*)?$/ }, () => {
118
242
  return {
119
- path: '@tamagui/react-native-web-lite',
120
- external: true,
243
+ path: proxyWormPath,
244
+ }
245
+ })
246
+
247
+ build.onResolve({ filter: /^react-native-worklets(?:\/.*)?$/ }, () => {
248
+ return {
249
+ path: proxyWormPath,
121
250
  }
122
251
  })
123
252
 
124
- build.onResolve({ filter: /react-native-reanimated/ }, (args) => {
253
+ // externalize animation libraries - not needed for static extraction
254
+ build.onResolve({ filter: /^(framer-motion|motion)/ }, (args) => {
125
255
  return {
126
- path: 'react-native-reanimated',
256
+ path: args.path,
127
257
  external: true,
128
258
  }
129
259
  })
@@ -139,36 +269,38 @@ function getESBuildConfig(
139
269
  return res
140
270
  }
141
271
 
272
+ function detectEntryFormat(entryPoint: string): esbuild.BuildOptions['format'] {
273
+ // file path - detect from file/package.json
274
+ if (entryPoint.startsWith('/') || entryPoint.startsWith('.')) {
275
+ return detectModuleFormat(entryPoint)
276
+ }
277
+ // bare module specifier - check package.json type field
278
+ try {
279
+ const pkgJsonPath = require.resolve(entryPoint + '/package.json')
280
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'))
281
+ return pkg.type === 'module' ? 'esm' : 'cjs'
282
+ } catch {
283
+ return 'cjs'
284
+ }
285
+ }
286
+
142
287
  export async function esbundleTamaguiConfig(
143
288
  props: Props,
144
289
  platform: TamaguiPlatform,
145
290
  aliases?: Record<string, string>
146
291
  ) {
147
- await asyncLock(props)
148
292
  const config = getESBuildConfig(props, platform, aliases)
149
- return await esbuild.build(config)
150
- }
151
293
 
152
- // until i do fancier things w plugins:
153
- async function asyncLock(props: Props) {
154
- const lockFile = join(dirname(props.outfile), basename(props.outfile, '.lock'))
155
- const lockStat = await FS.stat(lockFile).catch(() => {
156
- /* ok */
294
+ // build to memory first, then write atomically (temp file + rename)
295
+ // to prevent other threads from reading partially-written files
296
+ const tmpFile = props.outfile + '.tmp.' + process.pid
297
+ const result = await esbuild.build({
298
+ ...config,
299
+ outfile: tmpFile,
157
300
  })
158
- const lockedMsAgo = !lockStat
159
- ? Number.POSITIVE_INFINITY
160
- : new Date().getTime() - new Date(lockStat.mtime).getTime()
161
- if (lockedMsAgo < 500) {
162
- if (process.env.DEBUG?.startsWith('tamagui')) {
163
- console.info(`Waiting for existing build`, props.entryPoints)
164
- }
165
- let tries = 5
166
- while (tries--) {
167
- if (await FS.pathExists(props.outfile)) {
168
- return
169
- }
170
- await new Promise((res) => setTimeout(res, 50))
171
- }
172
- }
173
- void FS.writeFile(lockFile, '')
301
+
302
+ // atomic rename prevents other threads from reading partial files
303
+ await FS.rename(tmpFile, props.outfile)
304
+
305
+ return result
174
306
  }