@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.
- package/dist/check-dep-versions.cjs +201 -96
- package/dist/checkDeps.cjs +250 -46
- package/dist/constants.cjs +32 -30
- package/dist/exports.cjs +20 -13
- package/dist/extractor/accessSafe.cjs +25 -23
- package/dist/extractor/babelParse.cjs +30 -28
- package/dist/extractor/buildClassName.cjs +59 -35
- package/dist/extractor/bundle.cjs +187 -101
- package/dist/extractor/bundleConfig.cjs +568 -168
- package/dist/extractor/concatClassName.cjs +73 -32
- package/dist/extractor/createEvaluator.cjs +54 -41
- package/dist/extractor/createExtractor.cjs +1405 -574
- package/dist/extractor/createLogger.cjs +30 -25
- package/dist/extractor/detectModuleFormat.cjs +55 -0
- package/dist/extractor/ensureImportingConcat.cjs +31 -25
- package/dist/extractor/errors.cjs +12 -10
- package/dist/extractor/esbuildAliasPlugin.cjs +28 -16
- package/dist/extractor/esbuildTsconfigPaths.cjs +60 -36
- package/dist/extractor/evaluateAstNode.cjs +104 -59
- package/dist/extractor/extractHelpers.cjs +130 -67
- package/dist/extractor/extractMediaStyle.cjs +110 -69
- package/dist/extractor/extractToClassNames.cjs +337 -229
- package/dist/extractor/extractToNative.cjs +248 -154
- package/dist/extractor/findTopmostFunction.cjs +22 -13
- package/dist/extractor/generatedUid.cjs +39 -28
- package/dist/extractor/getPrefixLogs.cjs +12 -10
- package/dist/extractor/getPropValueFromAttributes.cjs +52 -34
- package/dist/extractor/getSourceModule.cjs +73 -37
- package/dist/extractor/getStaticBindingsForScope.cjs +131 -68
- package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.cjs +20 -14
- package/dist/extractor/hasTopLevelAwait.cjs +62 -0
- package/dist/extractor/hoistClassNames.cjs +46 -32
- package/dist/extractor/literalToAst.cjs +67 -42
- package/dist/extractor/loadFile.cjs +9 -3
- package/dist/extractor/loadTamagui.cjs +151 -105
- package/dist/extractor/logLines.cjs +27 -19
- package/dist/extractor/normalizeTernaries.cjs +66 -44
- package/dist/extractor/propsToFontFamilyCache.cjs +15 -11
- package/dist/extractor/regenerateConfig.cjs +109 -81
- package/dist/extractor/removeUnusedHooks.cjs +73 -41
- package/dist/extractor/timer.cjs +23 -14
- package/dist/extractor/validHTMLAttributes.cjs +61 -59
- package/dist/extractor/watchTamaguiConfig.cjs +35 -23
- package/dist/getPragmaOptions.cjs +34 -19
- package/dist/helpers/memoize.cjs +24 -16
- package/dist/helpers/requireTamaguiCore.cjs +22 -15
- package/dist/index.cjs +26 -24
- package/dist/registerRequire.cjs +168 -65
- package/dist/server.cjs +35 -28
- package/dist/types.cjs +7 -5
- package/dist/worker.cjs +62 -40
- package/package.json +27 -24
- package/src/checkDeps.ts +305 -68
- package/src/exports.ts +2 -0
- package/src/extractor/babelParse.ts +1 -0
- package/src/extractor/bundle.ts +172 -40
- package/src/extractor/bundleConfig.ts +459 -65
- package/src/extractor/concatClassName.ts +37 -20
- package/src/extractor/createExtractor.ts +300 -30
- package/src/extractor/detectModuleFormat.ts +42 -0
- package/src/extractor/esbuildTsconfigPaths.ts +6 -1
- package/src/extractor/extractToClassNames.ts +15 -9
- package/src/extractor/extractToNative.ts +66 -33
- package/src/extractor/hasTopLevelAwait.ts +28 -0
- package/src/extractor/loadTamagui.ts +5 -4
- package/src/registerRequire.ts +102 -9
- package/types/checkDeps.d.ts.map +1 -1
- package/types/exports.d.ts +2 -0
- package/types/exports.d.ts.map +1 -1
- package/types/extractor/babelParse.d.ts.map +1 -1
- package/types/extractor/bundle.d.ts +83 -1
- package/types/extractor/bundle.d.ts.map +1 -1
- package/types/extractor/bundleConfig.d.ts +15 -2
- package/types/extractor/bundleConfig.d.ts.map +1 -1
- package/types/extractor/createExtractor.d.ts.map +1 -1
- package/types/extractor/detectModuleFormat.d.ts +5 -0
- package/types/extractor/detectModuleFormat.d.ts.map +1 -0
- package/types/extractor/esbuildTsconfigPaths.d.ts +8 -0
- package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -1
- package/types/extractor/extractToClassNames.d.ts.map +1 -1
- package/types/extractor/extractToNative.d.ts.map +1 -1
- package/types/extractor/hasTopLevelAwait.d.ts +2 -0
- package/types/extractor/hasTopLevelAwait.d.ts.map +1 -0
- package/types/extractor/loadTamagui.d.ts +1 -1
- package/types/extractor/loadTamagui.d.ts.map +1 -1
- package/types/registerRequire.d.ts.map +1 -1
- package/dist/check-dep-versions.js +0 -389
- package/dist/check-dep-versions.js.map +0 -6
- package/dist/checkDeps.js +0 -60
- package/dist/checkDeps.js.map +0 -6
- package/dist/constants.js +0 -34
- package/dist/constants.js.map +0 -6
- package/dist/exports.js +0 -34
- package/dist/exports.js.map +0 -6
- package/dist/extractor/accessSafe.js +0 -47
- package/dist/extractor/accessSafe.js.map +0 -6
- package/dist/extractor/babelParse.js +0 -59
- package/dist/extractor/babelParse.js.map +0 -6
- package/dist/extractor/buildClassName.js +0 -72
- package/dist/extractor/buildClassName.js.map +0 -6
- package/dist/extractor/bundle.js +0 -135
- package/dist/extractor/bundle.js.map +0 -6
- package/dist/extractor/bundleConfig.js +0 -352
- package/dist/extractor/bundleConfig.js.map +0 -6
- package/dist/extractor/concatClassName.js +0 -69
- package/dist/extractor/concatClassName.js.map +0 -6
- package/dist/extractor/createEvaluator.js +0 -66
- package/dist/extractor/createEvaluator.js.map +0 -6
- package/dist/extractor/createExtractor.js +0 -1212
- package/dist/extractor/createExtractor.js.map +0 -6
- package/dist/extractor/createLogger.js +0 -32
- package/dist/extractor/createLogger.js.map +0 -6
- package/dist/extractor/ensureImportingConcat.js +0 -50
- package/dist/extractor/ensureImportingConcat.js.map +0 -6
- package/dist/extractor/errors.js +0 -22
- package/dist/extractor/errors.js.map +0 -6
- package/dist/extractor/esbuildAliasPlugin.js +0 -36
- package/dist/extractor/esbuildAliasPlugin.js.map +0 -6
- package/dist/extractor/esbuildTsconfigPaths.js +0 -79
- package/dist/extractor/esbuildTsconfigPaths.js.map +0 -6
- package/dist/extractor/evaluateAstNode.js +0 -99
- package/dist/extractor/evaluateAstNode.js.map +0 -6
- package/dist/extractor/extractHelpers.js +0 -108
- package/dist/extractor/extractHelpers.js.map +0 -6
- package/dist/extractor/extractMediaStyle.js +0 -123
- package/dist/extractor/extractMediaStyle.js.map +0 -6
- package/dist/extractor/extractToClassNames.js +0 -351
- package/dist/extractor/extractToClassNames.js.map +0 -6
- package/dist/extractor/extractToNative.js +0 -286
- package/dist/extractor/extractToNative.js.map +0 -6
- package/dist/extractor/findTopmostFunction.js +0 -32
- package/dist/extractor/findTopmostFunction.js.map +0 -6
- package/dist/extractor/generatedUid.js +0 -42
- package/dist/extractor/generatedUid.js.map +0 -6
- package/dist/extractor/getPrefixLogs.js +0 -24
- package/dist/extractor/getPrefixLogs.js.map +0 -6
- package/dist/extractor/getPropValueFromAttributes.js +0 -65
- package/dist/extractor/getPropValueFromAttributes.js.map +0 -6
- package/dist/extractor/getSourceModule.js +0 -62
- package/dist/extractor/getSourceModule.js.map +0 -6
- package/dist/extractor/getStaticBindingsForScope.js +0 -145
- package/dist/extractor/getStaticBindingsForScope.js.map +0 -6
- package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.js +0 -32
- package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.js.map +0 -6
- package/dist/extractor/hoistClassNames.js +0 -63
- package/dist/extractor/hoistClassNames.js.map +0 -6
- package/dist/extractor/literalToAst.js +0 -90
- package/dist/extractor/literalToAst.js.map +0 -6
- package/dist/extractor/loadFile.js +0 -14
- package/dist/extractor/loadFile.js.map +0 -6
- package/dist/extractor/loadTamagui.js +0 -306
- package/dist/extractor/loadTamagui.js.map +0 -6
- package/dist/extractor/logLines.js +0 -30
- package/dist/extractor/logLines.js.map +0 -6
- package/dist/extractor/normalizeTernaries.js +0 -61
- package/dist/extractor/normalizeTernaries.js.map +0 -6
- package/dist/extractor/propsToFontFamilyCache.js +0 -33
- package/dist/extractor/propsToFontFamilyCache.js.map +0 -6
- package/dist/extractor/regenerateConfig.js +0 -123
- package/dist/extractor/regenerateConfig.js.map +0 -6
- package/dist/extractor/removeUnusedHooks.js +0 -72
- package/dist/extractor/removeUnusedHooks.js.map +0 -6
- package/dist/extractor/timer.js +0 -38
- package/dist/extractor/timer.js.map +0 -6
- package/dist/extractor/validHTMLAttributes.js +0 -72
- package/dist/extractor/validHTMLAttributes.js.map +0 -6
- package/dist/extractor/watchTamaguiConfig.js +0 -57
- package/dist/extractor/watchTamaguiConfig.js.map +0 -6
- package/dist/getPragmaOptions.js +0 -50
- package/dist/getPragmaOptions.js.map +0 -6
- package/dist/helpers/memoize.js +0 -33
- package/dist/helpers/memoize.js.map +0 -6
- package/dist/helpers/requireTamaguiCore.js +0 -30
- package/dist/helpers/requireTamaguiCore.js.map +0 -6
- package/dist/index.js +0 -30
- package/dist/index.js.map +0 -6
- package/dist/registerRequire.js +0 -100
- package/dist/registerRequire.js.map +0 -6
- package/dist/server.js +0 -58
- package/dist/server.js.map +0 -6
- package/dist/setup.js +0 -1
- package/dist/setup.js.map +0 -6
- package/dist/types.js +0 -14
- package/dist/types.js.map +0 -6
- package/dist/worker.js +0 -72
- 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 {
|
|
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'
|
|
@@ -18,7 +16,74 @@ import type { TamaguiOptions } from '../types'
|
|
|
18
16
|
import { babelParse } from './babelParse'
|
|
19
17
|
import { esbuildLoaderConfig, esbundleTamaguiConfig } from './bundle'
|
|
20
18
|
import { getTamaguiConfigPathFromOptionsConfig } from './getTamaguiConfigPathFromOptionsConfig'
|
|
19
|
+
import { hasTopLevelAwait } from './hasTopLevelAwait'
|
|
21
20
|
import { requireTamaguiCore } from '../helpers/requireTamaguiCore'
|
|
21
|
+
import { detectModuleFormat } from './detectModuleFormat'
|
|
22
|
+
|
|
23
|
+
// track temp files for cleanup on exit
|
|
24
|
+
const activeTempFiles = new Set<string>()
|
|
25
|
+
|
|
26
|
+
function getDynamicEvalOutfile(name: string, format: 'esm' | 'cjs', contents: string) {
|
|
27
|
+
const ext = format === 'esm' ? 'mjs' : 'cjs'
|
|
28
|
+
const hash = createHash('sha1')
|
|
29
|
+
.update(name)
|
|
30
|
+
.update('\0')
|
|
31
|
+
.update(format)
|
|
32
|
+
.update('\0')
|
|
33
|
+
.update(contents)
|
|
34
|
+
.digest('hex')
|
|
35
|
+
.slice(0, 10)
|
|
36
|
+
return join(process.cwd(), '.tamagui', `dynamic-eval-${hash}-${basename(name)}.${ext}`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getEsbuildStdinLoader(filePath: string): esbuild.Loader {
|
|
40
|
+
if (filePath.endsWith('.tsx')) return 'tsx'
|
|
41
|
+
if (filePath.endsWith('.ts')) return 'ts'
|
|
42
|
+
if (filePath.endsWith('.jsx')) return 'jsx'
|
|
43
|
+
return 'js'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function resolvePackageEntry(packageName: string, format: 'esm' | 'cjs') {
|
|
47
|
+
if (format === 'cjs') {
|
|
48
|
+
return require.resolve(packageName)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
|
52
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
53
|
+
const packageRoot = dirname(packageJsonPath)
|
|
54
|
+
const exportEntry = packageJson.exports?.['.']
|
|
55
|
+
|
|
56
|
+
const esmEntry =
|
|
57
|
+
exportEntry?.import ||
|
|
58
|
+
exportEntry?.module ||
|
|
59
|
+
exportEntry?.browser ||
|
|
60
|
+
packageJson.module
|
|
61
|
+
|
|
62
|
+
if (typeof esmEntry === 'string') {
|
|
63
|
+
return join(packageRoot, esmEntry)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return require.resolve(packageName)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function cleanupTempFiles() {
|
|
70
|
+
for (const f of activeTempFiles) {
|
|
71
|
+
try {
|
|
72
|
+
unlinkSync(f)
|
|
73
|
+
} catch {}
|
|
74
|
+
}
|
|
75
|
+
activeTempFiles.clear()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
process.on('exit', cleanupTempFiles)
|
|
79
|
+
process.on('SIGINT', () => {
|
|
80
|
+
cleanupTempFiles()
|
|
81
|
+
process.exit()
|
|
82
|
+
})
|
|
83
|
+
process.on('SIGTERM', () => {
|
|
84
|
+
cleanupTempFiles()
|
|
85
|
+
process.exit()
|
|
86
|
+
})
|
|
22
87
|
|
|
23
88
|
type NameToPaths = {
|
|
24
89
|
[key: string]: Set<string>
|
|
@@ -55,18 +120,101 @@ const esbuildExtraOptions = {
|
|
|
55
120
|
},
|
|
56
121
|
}
|
|
57
122
|
|
|
58
|
-
|
|
59
|
-
|
|
123
|
+
// plugin to handle ESM-only features when bundling to CJS
|
|
124
|
+
const handleEsmFeaturesPlugin: esbuild.Plugin = {
|
|
125
|
+
name: 'handle-esm-features',
|
|
126
|
+
setup(build) {
|
|
127
|
+
// only apply transforms for CJS output - ESM supports these natively
|
|
128
|
+
const isCjs = build.initialOptions.format === 'cjs' || !build.initialOptions.format
|
|
129
|
+
|
|
130
|
+
build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs)$/ }, (args) => {
|
|
131
|
+
// skip if ESM output - import.meta and top-level await work natively
|
|
132
|
+
if (!isCjs) {
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// skip most node_modules
|
|
137
|
+
if (args.path.includes('node_modules') && !args.path.includes('@tamagui')) {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let contents = readFileSync(args.path, 'utf8')
|
|
142
|
+
let modified = false
|
|
143
|
+
|
|
144
|
+
// transform import.meta.env -> process.env (Vite-style env vars)
|
|
145
|
+
if (contents.includes('import.meta.env')) {
|
|
146
|
+
contents = contents.replace(/import\.meta\.env/g, 'process.env')
|
|
147
|
+
modified = true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// transform import.meta.url -> "" (not needed for static extraction)
|
|
151
|
+
if (contents.includes('import.meta.url')) {
|
|
152
|
+
contents = contents.replace(/import\.meta\.url/g, '""')
|
|
153
|
+
modified = true
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// transform import.meta.main -> false
|
|
157
|
+
if (contents.includes('import.meta.main')) {
|
|
158
|
+
contents = contents.replace(/import\.meta\.main/g, 'false')
|
|
159
|
+
modified = true
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// stub files with top-level await - they're typically runtime-only
|
|
163
|
+
if (hasTopLevelAwait(contents, args.path)) {
|
|
164
|
+
if (process.env.DEBUG?.startsWith('tamagui')) {
|
|
165
|
+
console.info(`[tamagui] stubbing file with top-level await: ${args.path}`)
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
// Keep this as an ESM-shaped stub so esbuild doesn't inline a top-level
|
|
169
|
+
// `module.exports = {}` into the parent bundle and wipe its exports.
|
|
170
|
+
contents: `// stubbed - contains top-level await\nexport default {}`,
|
|
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>
|
|
67
214
|
|
|
68
215
|
// will use cached one if watching
|
|
69
216
|
let currentBundle: BundledConfig | null = null
|
|
217
|
+
let currentBundleKey = ''
|
|
70
218
|
let isBundling = false
|
|
71
219
|
let lastBundle: BundledConfig | null = null
|
|
72
220
|
const waitForBundle = new Set<Function>()
|
|
@@ -83,22 +231,35 @@ let loadedConfig: TamaguiInternalConfig | null = null
|
|
|
83
231
|
|
|
84
232
|
export const getLoadedConfig = () => loadedConfig
|
|
85
233
|
|
|
234
|
+
function getBundleKey(props: TamaguiOptions) {
|
|
235
|
+
return JSON.stringify({
|
|
236
|
+
components: props.components,
|
|
237
|
+
config: props.config,
|
|
238
|
+
platform: props.platform,
|
|
239
|
+
})
|
|
240
|
+
}
|
|
241
|
+
|
|
86
242
|
export async function getBundledConfig(props: TamaguiOptions, rebuild = false) {
|
|
243
|
+
const bundleKey = getBundleKey(props)
|
|
87
244
|
if (isBundling) {
|
|
88
245
|
await new Promise((res) => {
|
|
89
246
|
waitForBundle.add(res)
|
|
90
247
|
})
|
|
91
|
-
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!currentBundle || currentBundleKey !== bundleKey || rebuild) {
|
|
92
251
|
return await bundleConfig(props)
|
|
93
252
|
}
|
|
253
|
+
|
|
94
254
|
return currentBundle
|
|
95
255
|
}
|
|
96
256
|
|
|
97
257
|
global.tamaguiLastLoaded ||= 0
|
|
98
258
|
|
|
99
|
-
function updateLastLoaded(config: any) {
|
|
259
|
+
function updateLastLoaded(config: any, bundleKey: string) {
|
|
100
260
|
global.tamaguiLastLoaded = Date.now()
|
|
101
261
|
global.tamaguiLastBundledConfig = config
|
|
262
|
+
global.tamaguiLastBundledConfigKey = bundleKey
|
|
102
263
|
}
|
|
103
264
|
|
|
104
265
|
let hasBundledOnce = false
|
|
@@ -109,8 +270,13 @@ let hasBundledOnce = false
|
|
|
109
270
|
let hasLoggedBuild = false
|
|
110
271
|
|
|
111
272
|
export async function bundleConfig(props: TamaguiOptions) {
|
|
273
|
+
const bundleKey = getBundleKey(props)
|
|
112
274
|
// webpack is calling this a ton for no reason
|
|
113
|
-
if (
|
|
275
|
+
if (
|
|
276
|
+
global.tamaguiLastBundledConfig &&
|
|
277
|
+
global.tamaguiLastBundledConfigKey === bundleKey &&
|
|
278
|
+
Date.now() - global.tamaguiLastLoaded < 3000
|
|
279
|
+
) {
|
|
114
280
|
// just loaded recently
|
|
115
281
|
return global.tamaguiLastBundledConfig
|
|
116
282
|
}
|
|
@@ -122,17 +288,31 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
122
288
|
? getTamaguiConfigPathFromOptionsConfig(props.config)
|
|
123
289
|
: ''
|
|
124
290
|
const tmpDir = join(process.cwd(), '.tamagui')
|
|
125
|
-
|
|
291
|
+
// detect module format from config entry point
|
|
292
|
+
const configFormat = configEntry ? detectModuleFormat(configEntry) : 'cjs'
|
|
293
|
+
const configExt = configFormat === 'esm' ? '.mjs' : '.cjs'
|
|
294
|
+
const configOutPath = join(tmpDir, `tamagui.config${configExt}`)
|
|
126
295
|
const baseComponents = (props.components || []).filter((x) => x !== '@tamagui/core')
|
|
127
|
-
|
|
128
|
-
|
|
296
|
+
// detect format per component module
|
|
297
|
+
const componentFormats: Array<'esm' | 'cjs'> = baseComponents.map((mod) => {
|
|
298
|
+
try {
|
|
299
|
+
const pkgJson = require.resolve(mod + '/package.json')
|
|
300
|
+
const pkg = JSON.parse(readFileSync(pkgJson, 'utf-8'))
|
|
301
|
+
return pkg.type === 'module' ? 'esm' : 'cjs'
|
|
302
|
+
} catch {
|
|
303
|
+
return 'cjs'
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
const componentOutPaths = baseComponents.map((componentModule, i) => {
|
|
307
|
+
const ext = componentFormats[i] === 'esm' ? '.mjs' : '.cjs'
|
|
308
|
+
return join(
|
|
129
309
|
tmpDir,
|
|
130
310
|
`${componentModule
|
|
131
311
|
.split(sep)
|
|
132
312
|
.join('-')
|
|
133
|
-
.replace(/[^a-z0-9]+/gi, '')}-components.config
|
|
313
|
+
.replace(/[^a-z0-9]+/gi, '')}-components.config${ext}`
|
|
134
314
|
)
|
|
135
|
-
)
|
|
315
|
+
})
|
|
136
316
|
|
|
137
317
|
if (
|
|
138
318
|
process.env.NODE_ENV === 'development' &&
|
|
@@ -141,7 +321,29 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
141
321
|
console.info(`Building config entry`, configEntry)
|
|
142
322
|
}
|
|
143
323
|
|
|
144
|
-
if (
|
|
324
|
+
// check if ALL output files (config + components) already exist and are recent
|
|
325
|
+
// (built by another worker) - this prevents duplicate builds across worker threads
|
|
326
|
+
// we must check ALL files, not just the config, to avoid a race where another
|
|
327
|
+
// worker has written the config but not yet finished writing component files
|
|
328
|
+
let shouldBuild = !props.disableInitialBuild
|
|
329
|
+
if (shouldBuild && props.config) {
|
|
330
|
+
const allOutFiles = [configOutPath, ...componentOutPaths]
|
|
331
|
+
try {
|
|
332
|
+
const stats = await Promise.all(
|
|
333
|
+
allOutFiles.map((f) => FS.stat(f).catch(() => null))
|
|
334
|
+
)
|
|
335
|
+
const allExistAndRecent = stats.every(
|
|
336
|
+
(s) => s !== null && Date.now() - s.mtimeMs < 3000
|
|
337
|
+
)
|
|
338
|
+
if (allExistAndRecent) {
|
|
339
|
+
shouldBuild = false
|
|
340
|
+
}
|
|
341
|
+
} catch {
|
|
342
|
+
// something went wrong checking files, just build
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (shouldBuild) {
|
|
145
347
|
// build them to node-compat versions
|
|
146
348
|
try {
|
|
147
349
|
await FS.ensureDir(tmpDir)
|
|
@@ -158,7 +360,8 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
158
360
|
entryPoints: [configEntry],
|
|
159
361
|
external,
|
|
160
362
|
outfile: configOutPath,
|
|
161
|
-
target: '
|
|
363
|
+
target: 'node24',
|
|
364
|
+
format: configFormat,
|
|
162
365
|
...esbuildExtraOptions,
|
|
163
366
|
},
|
|
164
367
|
props.platform || 'web'
|
|
@@ -171,7 +374,8 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
171
374
|
resolvePlatformSpecificEntries: true,
|
|
172
375
|
external,
|
|
173
376
|
outfile: componentOutPaths[i],
|
|
174
|
-
target: '
|
|
377
|
+
target: 'node24',
|
|
378
|
+
format: componentFormats[i],
|
|
175
379
|
...esbuildExtraOptions,
|
|
176
380
|
},
|
|
177
381
|
props.platform || 'web'
|
|
@@ -201,25 +405,32 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
201
405
|
}
|
|
202
406
|
}
|
|
203
407
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
408
|
+
// clear specific output file caches so we pick up the fresh (or newly discovered) build
|
|
409
|
+
// only clear the built output files - not all require.cache entries, since that breaks
|
|
410
|
+
// external requires like @tamagui/config/v3 that are externalized in the bundled CJS
|
|
411
|
+
if (hasBundledOnce) {
|
|
412
|
+
try {
|
|
413
|
+
delete require.cache[require.resolve(configOutPath)]
|
|
414
|
+
} catch {
|
|
415
|
+
// file may not exist yet
|
|
416
|
+
}
|
|
417
|
+
for (const p of componentOutPaths) {
|
|
418
|
+
try {
|
|
419
|
+
delete require.cache[require.resolve(p)]
|
|
420
|
+
} catch {
|
|
421
|
+
// file may not exist yet
|
|
215
422
|
}
|
|
216
|
-
} else {
|
|
217
|
-
hasBundledOnce = true
|
|
218
423
|
}
|
|
424
|
+
} else {
|
|
425
|
+
hasBundledOnce = true
|
|
426
|
+
}
|
|
219
427
|
|
|
428
|
+
let out: any
|
|
429
|
+
if (configFormat === 'esm') {
|
|
430
|
+
// use file:// URL for proper ESM resolution
|
|
431
|
+
out = await import(pathToFileURL(configOutPath).href)
|
|
432
|
+
} else {
|
|
220
433
|
out = require(configOutPath)
|
|
221
|
-
} finally {
|
|
222
|
-
unregister()
|
|
223
434
|
}
|
|
224
435
|
|
|
225
436
|
// try and find .config, even if on .default
|
|
@@ -232,6 +443,13 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
232
443
|
throw new Error(`No config: ${config}`)
|
|
233
444
|
}
|
|
234
445
|
|
|
446
|
+
// check for ProxyWorm - indicates a module loading error
|
|
447
|
+
if (config._isProxyWorm) {
|
|
448
|
+
throw new Error(
|
|
449
|
+
`Got a proxied config - likely a module loading error. Set DEBUG=tamagui for details.`
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
|
|
235
453
|
loadedConfig = config
|
|
236
454
|
|
|
237
455
|
if (!config.parsed) {
|
|
@@ -244,7 +462,7 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
244
462
|
await writeTamaguiCSS(props.outputCSS, config)
|
|
245
463
|
}
|
|
246
464
|
|
|
247
|
-
let components = loadComponents({
|
|
465
|
+
let components = await loadComponents({
|
|
248
466
|
...props,
|
|
249
467
|
components: componentOutPaths,
|
|
250
468
|
})
|
|
@@ -284,7 +502,8 @@ export async function bundleConfig(props: TamaguiOptions) {
|
|
|
284
502
|
}
|
|
285
503
|
|
|
286
504
|
currentBundle = res
|
|
287
|
-
|
|
505
|
+
currentBundleKey = bundleKey
|
|
506
|
+
updateLastLoaded(res, bundleKey)
|
|
288
507
|
|
|
289
508
|
return res
|
|
290
509
|
} catch (err: any) {
|
|
@@ -322,14 +541,20 @@ export async function writeTamaguiCSS(outputCSS: string, config: TamaguiInternal
|
|
|
322
541
|
}
|
|
323
542
|
}
|
|
324
543
|
|
|
325
|
-
export function loadComponents(props: TamaguiOptions, forceExports = false) {
|
|
326
|
-
const coreComponents =
|
|
327
|
-
const otherComponents = loadComponentsInner(props, forceExports)
|
|
544
|
+
export async function loadComponents(props: TamaguiOptions, forceExports = false) {
|
|
545
|
+
const coreComponents = getCoreComponentsSync(props)
|
|
546
|
+
const otherComponents = await loadComponentsInner(props, forceExports)
|
|
547
|
+
return [...coreComponents, ...(otherComponents || [])]
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export function loadComponentsSync(props: TamaguiOptions, forceExports = false) {
|
|
551
|
+
const coreComponents = getCoreComponentsSync(props)
|
|
552
|
+
const otherComponents = loadComponentsInnerSync(props, forceExports)
|
|
328
553
|
return [...coreComponents, ...(otherComponents || [])]
|
|
329
554
|
}
|
|
330
555
|
|
|
331
|
-
function
|
|
332
|
-
const loaded =
|
|
556
|
+
function getCoreComponentsSync(props: TamaguiOptions) {
|
|
557
|
+
const loaded = loadComponentsInnerSync({
|
|
333
558
|
...props,
|
|
334
559
|
components: ['@tamagui/core'],
|
|
335
560
|
})
|
|
@@ -347,13 +572,172 @@ function getCoreComponents(props: TamaguiOptions) {
|
|
|
347
572
|
]
|
|
348
573
|
}
|
|
349
574
|
|
|
350
|
-
export function loadComponentsInner(
|
|
575
|
+
export async function loadComponentsInner(
|
|
576
|
+
props: TamaguiOptions,
|
|
577
|
+
forceExports = false
|
|
578
|
+
): Promise<null | LoadedComponents[]> {
|
|
579
|
+
const componentsModules = props.components || []
|
|
580
|
+
|
|
581
|
+
const key = componentsModules.join('\0')
|
|
582
|
+
|
|
583
|
+
if (!forceExports && cacheComponents[key]) {
|
|
584
|
+
return cacheComponents[key]
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const { unregister } = registerRequire(props.platform || 'web', {
|
|
588
|
+
proxyWormImports: forceExports,
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
try {
|
|
592
|
+
const results: LoadedComponents[] = []
|
|
593
|
+
|
|
594
|
+
for (const name of componentsModules) {
|
|
595
|
+
const extension = extname(name)
|
|
596
|
+
const isLocal = Boolean(extension)
|
|
597
|
+
const isDynamic = isLocal && forceExports
|
|
598
|
+
const format = isLocal ? detectModuleFormat(name) : ('cjs' as const)
|
|
599
|
+
|
|
600
|
+
const fileContents = isDynamic ? readFileSync(name, 'utf-8') : ''
|
|
601
|
+
let loadModule = name
|
|
602
|
+
let writtenContents = fileContents
|
|
603
|
+
let didBabel = false
|
|
604
|
+
|
|
605
|
+
const attemptLoad = async ({ forceExports = false } = {}) => {
|
|
606
|
+
if (isDynamic) {
|
|
607
|
+
writtenContents = forceExports
|
|
608
|
+
? transformAddExports(babelParse(esbuildit(fileContents, 'modern'), name))
|
|
609
|
+
: fileContents
|
|
610
|
+
loadModule = getDynamicEvalOutfile(name, format, writtenContents)
|
|
611
|
+
|
|
612
|
+
FS.ensureDirSync(dirname(loadModule))
|
|
613
|
+
activeTempFiles.add(loadModule)
|
|
614
|
+
|
|
615
|
+
await esbuild.build({
|
|
616
|
+
...esbuildOptionsWithPlugins,
|
|
617
|
+
format,
|
|
618
|
+
outfile: loadModule,
|
|
619
|
+
stdin: {
|
|
620
|
+
contents: writtenContents,
|
|
621
|
+
resolveDir: dirname(name),
|
|
622
|
+
sourcefile: name,
|
|
623
|
+
loader: getEsbuildStdinLoader(name),
|
|
624
|
+
},
|
|
625
|
+
alias: {
|
|
626
|
+
'react-native': resolvePackageEntry(
|
|
627
|
+
'@tamagui/react-native-web-lite',
|
|
628
|
+
format
|
|
629
|
+
),
|
|
630
|
+
'@tamagui/react-native-web-lite': resolvePackageEntry(
|
|
631
|
+
'@tamagui/react-native-web-lite',
|
|
632
|
+
format
|
|
633
|
+
),
|
|
634
|
+
'@tamagui/react-native-web-internals': resolvePackageEntry(
|
|
635
|
+
'@tamagui/react-native-web-internals',
|
|
636
|
+
format
|
|
637
|
+
),
|
|
638
|
+
},
|
|
639
|
+
bundle: true,
|
|
640
|
+
packages: 'external',
|
|
641
|
+
allowOverwrite: true,
|
|
642
|
+
sourcemap: false,
|
|
643
|
+
loader: esbuildLoaderConfig,
|
|
644
|
+
})
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (process.env.DEBUG === 'tamagui') {
|
|
648
|
+
console.info(`loadModule`, loadModule, format)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
let moduleResult: any
|
|
652
|
+
if (format === 'esm') {
|
|
653
|
+
// use file:// URL for proper ESM resolution
|
|
654
|
+
moduleResult = await import(pathToFileURL(loadModule).href)
|
|
655
|
+
} else {
|
|
656
|
+
moduleResult = require(loadModule)
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (!forceExports) {
|
|
660
|
+
setRequireResult(name, moduleResult)
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const nameToInfo = getComponentStaticConfigByName(
|
|
664
|
+
name,
|
|
665
|
+
interopDefaultExport(moduleResult)
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
return {
|
|
669
|
+
moduleName: name,
|
|
670
|
+
nameToInfo,
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const dispose = () => {
|
|
675
|
+
if (isDynamic) {
|
|
676
|
+
FS.removeSync(loadModule)
|
|
677
|
+
activeTempFiles.delete(loadModule)
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
let loaded: LoadedComponents | LoadedComponents[] | undefined
|
|
682
|
+
|
|
683
|
+
try {
|
|
684
|
+
loaded = await attemptLoad({ forceExports: true })
|
|
685
|
+
didBabel = true
|
|
686
|
+
} catch (err) {
|
|
687
|
+
console.info('babel err', err, writtenContents)
|
|
688
|
+
writtenContents = fileContents
|
|
689
|
+
if (process.env.DEBUG?.startsWith('tamagui')) {
|
|
690
|
+
console.info(`Error parsing babel likely`, err)
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
try {
|
|
694
|
+
loaded = await attemptLoad({ forceExports: false })
|
|
695
|
+
} catch (err2) {
|
|
696
|
+
if (process.env.TAMAGUI_ENABLE_WARN_DYNAMIC_LOAD) {
|
|
697
|
+
console.info(
|
|
698
|
+
`\nTamagui attempted but failed to dynamically optimize components in:\n ${name}\n`
|
|
699
|
+
)
|
|
700
|
+
console.info(err2)
|
|
701
|
+
console.info(
|
|
702
|
+
`At: ${loadModule}`,
|
|
703
|
+
`\ndidBabel: ${didBabel}`,
|
|
704
|
+
`\nIn:`,
|
|
705
|
+
writtenContents,
|
|
706
|
+
`\nisDynamic: `,
|
|
707
|
+
isDynamic
|
|
708
|
+
)
|
|
709
|
+
}
|
|
710
|
+
loaded = []
|
|
711
|
+
}
|
|
712
|
+
} finally {
|
|
713
|
+
dispose()
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (Array.isArray(loaded)) {
|
|
717
|
+
results.push(...loaded)
|
|
718
|
+
} else if (loaded) {
|
|
719
|
+
results.push(loaded)
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
cacheComponents[key] = results
|
|
724
|
+
return results
|
|
725
|
+
} catch (err: any) {
|
|
726
|
+
console.info(`Tamagui error bundling components`, err.message, err.stack)
|
|
727
|
+
return null
|
|
728
|
+
} finally {
|
|
729
|
+
unregister()
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// sync version - uses cjs format for buildSync (no plugin support)
|
|
734
|
+
export function loadComponentsInnerSync(
|
|
351
735
|
props: TamaguiOptions,
|
|
352
736
|
forceExports = false
|
|
353
737
|
): null | LoadedComponents[] {
|
|
354
738
|
const componentsModules = props.components || []
|
|
355
739
|
|
|
356
|
-
const key = componentsModules.join('')
|
|
740
|
+
const key = componentsModules.join('\0')
|
|
357
741
|
|
|
358
742
|
if (!forceExports && cacheComponents[key]) {
|
|
359
743
|
return cacheComponents[key]
|
|
@@ -370,32 +754,46 @@ export function loadComponentsInner(
|
|
|
370
754
|
const isDynamic = isLocal && forceExports
|
|
371
755
|
|
|
372
756
|
const fileContents = isDynamic ? readFileSync(name, 'utf-8') : ''
|
|
373
|
-
|
|
374
|
-
? join(dirname(name), `.tamagui-dynamic-eval-${basename(name)}.tsx`)
|
|
375
|
-
: name
|
|
757
|
+
let loadModule = name
|
|
376
758
|
let writtenContents = fileContents
|
|
377
759
|
let didBabel = false
|
|
378
760
|
|
|
379
761
|
function attemptLoad({ forceExports = false } = {}) {
|
|
380
|
-
// need to write to tsx to enable reading it properly (:/ esbuild-register)
|
|
381
762
|
if (isDynamic) {
|
|
382
763
|
writtenContents = forceExports
|
|
383
764
|
? transformAddExports(babelParse(esbuildit(fileContents, 'modern'), name))
|
|
384
765
|
: fileContents
|
|
766
|
+
loadModule = getDynamicEvalOutfile(name, 'cjs', writtenContents)
|
|
385
767
|
|
|
386
|
-
FS.
|
|
768
|
+
FS.ensureDirSync(dirname(loadModule))
|
|
769
|
+
activeTempFiles.add(loadModule)
|
|
387
770
|
|
|
388
771
|
esbuild.buildSync({
|
|
389
772
|
...esbuildOptions,
|
|
390
|
-
entryPoints: [loadModule],
|
|
391
773
|
outfile: loadModule,
|
|
774
|
+
stdin: {
|
|
775
|
+
contents: writtenContents,
|
|
776
|
+
resolveDir: dirname(name),
|
|
777
|
+
sourcefile: name,
|
|
778
|
+
loader: getEsbuildStdinLoader(name),
|
|
779
|
+
},
|
|
392
780
|
alias: {
|
|
393
|
-
'react-native':
|
|
781
|
+
'react-native': resolvePackageEntry(
|
|
782
|
+
'@tamagui/react-native-web-lite',
|
|
783
|
+
'esm'
|
|
784
|
+
),
|
|
785
|
+
'@tamagui/react-native-web-lite': resolvePackageEntry(
|
|
786
|
+
'@tamagui/react-native-web-lite',
|
|
787
|
+
'esm'
|
|
788
|
+
),
|
|
789
|
+
'@tamagui/react-native-web-internals': resolvePackageEntry(
|
|
790
|
+
'@tamagui/react-native-web-internals',
|
|
791
|
+
'esm'
|
|
792
|
+
),
|
|
394
793
|
},
|
|
395
794
|
bundle: true,
|
|
396
795
|
packages: 'external',
|
|
397
796
|
allowOverwrite: true,
|
|
398
|
-
// logLevel: 'silent',
|
|
399
797
|
sourcemap: false,
|
|
400
798
|
loader: esbuildLoaderConfig,
|
|
401
799
|
})
|
|
@@ -423,18 +821,18 @@ export function loadComponentsInner(
|
|
|
423
821
|
}
|
|
424
822
|
|
|
425
823
|
const dispose = () => {
|
|
426
|
-
|
|
824
|
+
if (isDynamic) {
|
|
825
|
+
FS.removeSync(loadModule)
|
|
826
|
+
activeTempFiles.delete(loadModule)
|
|
827
|
+
}
|
|
427
828
|
}
|
|
428
829
|
|
|
429
830
|
try {
|
|
430
|
-
const res = attemptLoad({
|
|
431
|
-
forceExports: true,
|
|
432
|
-
})
|
|
831
|
+
const res = attemptLoad({ forceExports: true })
|
|
433
832
|
didBabel = true
|
|
434
833
|
return res
|
|
435
834
|
} catch (err) {
|
|
436
835
|
console.info('babel err', err, writtenContents)
|
|
437
|
-
// ok
|
|
438
836
|
writtenContents = fileContents
|
|
439
837
|
if (process.env.DEBUG?.startsWith('tamagui')) {
|
|
440
838
|
console.info(`Error parsing babel likely`, err)
|
|
@@ -444,16 +842,12 @@ export function loadComponentsInner(
|
|
|
444
842
|
}
|
|
445
843
|
|
|
446
844
|
try {
|
|
447
|
-
return attemptLoad({
|
|
448
|
-
forceExports: false,
|
|
449
|
-
})
|
|
845
|
+
return attemptLoad({ forceExports: false })
|
|
450
846
|
} catch (err) {
|
|
451
847
|
if (process.env.TAMAGUI_ENABLE_WARN_DYNAMIC_LOAD) {
|
|
452
|
-
console.info(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
${name}
|
|
456
|
-
`)
|
|
848
|
+
console.info(
|
|
849
|
+
`\nTamagui attempted but failed to dynamically optimize components in:\n ${name}\n`
|
|
850
|
+
)
|
|
457
851
|
console.info(err)
|
|
458
852
|
console.info(
|
|
459
853
|
`At: ${loadModule}`,
|
|
@@ -481,7 +875,7 @@ Tamagui attempted but failed to dynamically optimize components in:
|
|
|
481
875
|
|
|
482
876
|
const esbuildit = (src: string, target?: 'modern') => {
|
|
483
877
|
return esbuild.transformSync(src, {
|
|
484
|
-
...
|
|
878
|
+
...esbuildTransformOptions,
|
|
485
879
|
...(target === 'modern' && {
|
|
486
880
|
target: 'es2022',
|
|
487
881
|
jsx: 'automatic',
|