@tamagui/static 2.0.0-rc.4 → 2.0.0-rc.40
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 +18 -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 +177 -101
- package/dist/extractor/bundleConfig.cjs +554 -167
- package/dist/extractor/concatClassName.cjs +41 -29
- package/dist/extractor/createEvaluator.cjs +54 -41
- package/dist/extractor/createExtractor.cjs +1400 -581
- 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 +149 -104
- 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 +38 -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 +167 -65
- package/dist/server.cjs +35 -28
- package/dist/types.cjs +7 -5
- package/dist/worker.cjs +62 -40
- package/package.json +26 -22
- package/src/checkDeps.ts +305 -68
- package/src/exports.ts +1 -0
- package/src/extractor/babelParse.ts +1 -0
- package/src/extractor/bundle.ts +140 -37
- package/src/extractor/bundleConfig.ts +435 -61
- package/src/extractor/createExtractor.ts +283 -48
- 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 +2 -2
- package/src/getPragmaOptions.ts +6 -1
- package/src/registerRequire.ts +88 -8
- package/types/checkDeps.d.ts.map +1 -1
- package/types/exports.d.ts +1 -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/getPragmaOptions.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 -1215
- 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 -46
- 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
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
type StaticConfig,
|
|
13
13
|
type TamaguiComponentState,
|
|
14
14
|
} from '@tamagui/web'
|
|
15
|
-
import {
|
|
15
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
16
|
+
import { basename, dirname, resolve, relative } from 'node:path'
|
|
17
|
+
import { nodeModuleNameResolver, sys } from 'typescript'
|
|
16
18
|
import type { ViewStyle } from 'react-native'
|
|
17
19
|
|
|
18
20
|
import { FAILED_EVAL } from '../constants'
|
|
@@ -26,7 +28,7 @@ import type {
|
|
|
26
28
|
TamaguiOptionsWithFileInfo,
|
|
27
29
|
Ternary,
|
|
28
30
|
} from '../types'
|
|
29
|
-
import type { TamaguiProjectInfo } from './bundleConfig'
|
|
31
|
+
import type { LoadedComponents, TamaguiProjectInfo } from './bundleConfig'
|
|
30
32
|
import { createEvaluator, createSafeEvaluator } from './createEvaluator'
|
|
31
33
|
import { evaluateAstNode } from './evaluateAstNode'
|
|
32
34
|
import {
|
|
@@ -49,6 +51,7 @@ import { setPropsToFontFamily } from './propsToFontFamilyCache'
|
|
|
49
51
|
import { timer } from './timer'
|
|
50
52
|
import { validHTMLAttributes } from './validHTMLAttributes'
|
|
51
53
|
import { BailOptimizationError } from './errors'
|
|
54
|
+
import { loadCompilerOptionsFromTsconfig } from './esbuildTsconfigPaths'
|
|
52
55
|
|
|
53
56
|
const UNTOUCHED_PROPS = {
|
|
54
57
|
key: true,
|
|
@@ -56,6 +59,11 @@ const UNTOUCHED_PROPS = {
|
|
|
56
59
|
className: true,
|
|
57
60
|
}
|
|
58
61
|
|
|
62
|
+
// Platform variants that can't be resolved at compile time on native builds.
|
|
63
|
+
// Defined at module level (not inside the loop) to avoid repeated Set allocations during compilation.
|
|
64
|
+
// (requires runtime Platform.OS + Platform.isTV checks via react-native-tvos)
|
|
65
|
+
const nativeOnlyPlatforms = new Set(['android', 'ios', 'tv', 'androidtv', 'tvos'])
|
|
66
|
+
|
|
59
67
|
const createTernary = (x: Ternary) => x
|
|
60
68
|
|
|
61
69
|
export type Extractor = ReturnType<typeof createExtractor>
|
|
@@ -71,10 +79,6 @@ function isFullyDisabled(props: TamaguiOptions) {
|
|
|
71
79
|
export function createExtractor(
|
|
72
80
|
{ logger = console, platform = 'web' }: ExtractorOptions = { logger: console }
|
|
73
81
|
) {
|
|
74
|
-
if (!process.env.TAMAGUI_TARGET) {
|
|
75
|
-
throw new Error('Please set process.env.TAMAGUI_TARGET to either "web" or "native"')
|
|
76
|
-
}
|
|
77
|
-
|
|
78
82
|
const INLINE_EXTRACTABLE = {
|
|
79
83
|
ref: 'ref',
|
|
80
84
|
key: 'key',
|
|
@@ -85,6 +89,29 @@ export function createExtractor(
|
|
|
85
89
|
onPressIn: 'onMouseDown',
|
|
86
90
|
onPressOut: 'onMouseUp',
|
|
87
91
|
}),
|
|
92
|
+
...(platform === 'native' && {
|
|
93
|
+
// native view props that should pass through without preventing flattening
|
|
94
|
+
testID: 'testID',
|
|
95
|
+
nativeID: 'nativeID',
|
|
96
|
+
accessibilityLabel: 'accessibilityLabel',
|
|
97
|
+
accessibilityHint: 'accessibilityHint',
|
|
98
|
+
accessibilityRole: 'accessibilityRole',
|
|
99
|
+
accessibilityState: 'accessibilityState',
|
|
100
|
+
accessibilityValue: 'accessibilityValue',
|
|
101
|
+
accessibilityActions: 'accessibilityActions',
|
|
102
|
+
accessibilityLabelledBy: 'accessibilityLabelledBy',
|
|
103
|
+
accessibilityLiveRegion: 'accessibilityLiveRegion',
|
|
104
|
+
accessibilityElementsHidden: 'accessibilityElementsHidden',
|
|
105
|
+
accessibilityViewIsModal: 'accessibilityViewIsModal',
|
|
106
|
+
importantForAccessibility: 'importantForAccessibility',
|
|
107
|
+
collapsable: 'collapsable',
|
|
108
|
+
needsOffscreenAlphaCompositing: 'needsOffscreenAlphaCompositing',
|
|
109
|
+
removeClippedSubviews: 'removeClippedSubviews',
|
|
110
|
+
renderToHardwareTextureAndroid: 'renderToHardwareTextureAndroid',
|
|
111
|
+
shouldRasterizeIOS: 'shouldRasterizeIOS',
|
|
112
|
+
hitSlop: 'hitSlop',
|
|
113
|
+
pointerEvents: 'pointerEvents',
|
|
114
|
+
}),
|
|
88
115
|
}
|
|
89
116
|
|
|
90
117
|
const componentState: TamaguiComponentState = {
|
|
@@ -99,7 +126,7 @@ export function createExtractor(
|
|
|
99
126
|
} as const
|
|
100
127
|
|
|
101
128
|
const styleProps: SplitStyleProps = {
|
|
102
|
-
resolveValues:
|
|
129
|
+
resolveValues: platform === 'native' ? 'value' : 'variable',
|
|
103
130
|
noClass: false,
|
|
104
131
|
isAnimated: false,
|
|
105
132
|
}
|
|
@@ -107,12 +134,89 @@ export function createExtractor(
|
|
|
107
134
|
const shouldAddDebugProp =
|
|
108
135
|
// really basic disable this for next.js because it messes with ssr
|
|
109
136
|
!process.env.npm_package_dependencies_next &&
|
|
110
|
-
|
|
137
|
+
platform !== 'native' &&
|
|
111
138
|
process.env.IDENTIFY_TAGS !== 'false' &&
|
|
112
139
|
(process.env.NODE_ENV === 'development' || process.env.IDENTIFY_TAGS)
|
|
113
140
|
|
|
114
141
|
let projectInfo: TamaguiProjectInfo | null = null
|
|
115
142
|
|
|
143
|
+
// cache of dynamically discovered styled components, keyed by absolute file path
|
|
144
|
+
// persists across files within the same worker/extractor instance
|
|
145
|
+
const dynamicComponentCache = new Map<string, LoadedComponents>()
|
|
146
|
+
const dynamicLoadingInProgress = new Set<string>()
|
|
147
|
+
|
|
148
|
+
// lazily loaded tsconfig compiler options for path alias resolution
|
|
149
|
+
let _compilerOptions: any = null
|
|
150
|
+
function getCompilerOptions() {
|
|
151
|
+
if (!_compilerOptions) {
|
|
152
|
+
try {
|
|
153
|
+
_compilerOptions = loadCompilerOptionsFromTsconfig()
|
|
154
|
+
} catch {
|
|
155
|
+
_compilerOptions = {}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return _compilerOptions
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function resolveImportPath(fromFile: string, importPath: string): string | null {
|
|
162
|
+
if (importPath.startsWith('.')) {
|
|
163
|
+
// relative path resolution
|
|
164
|
+
const dir = dirname(fromFile)
|
|
165
|
+
const base = resolve(dir, importPath)
|
|
166
|
+
const extensions = ['.tsx', '.ts', '.jsx', '.js']
|
|
167
|
+
for (const ext of extensions) {
|
|
168
|
+
const full = base + ext
|
|
169
|
+
if (existsSync(full)) return full
|
|
170
|
+
}
|
|
171
|
+
// try index files
|
|
172
|
+
for (const ext of extensions) {
|
|
173
|
+
const full = resolve(base, `index${ext}`)
|
|
174
|
+
if (existsSync(full)) return full
|
|
175
|
+
}
|
|
176
|
+
return null
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// tsconfig path alias resolution (e.g. ~/foo, @/bar)
|
|
180
|
+
const compilerOptions = getCompilerOptions()
|
|
181
|
+
if (compilerOptions.paths) {
|
|
182
|
+
try {
|
|
183
|
+
const { resolvedModule } = nodeModuleNameResolver(
|
|
184
|
+
importPath,
|
|
185
|
+
fromFile,
|
|
186
|
+
compilerOptions,
|
|
187
|
+
sys
|
|
188
|
+
)
|
|
189
|
+
if (
|
|
190
|
+
resolvedModule &&
|
|
191
|
+
!resolvedModule.resolvedFileName.endsWith('.d.ts') &&
|
|
192
|
+
!resolvedModule.isExternalLibraryImport
|
|
193
|
+
) {
|
|
194
|
+
return resolvedModule.resolvedFileName
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
197
|
+
// fallback - tsconfig resolution failed
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return null
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const styledCheckCache = new Map<string, boolean>()
|
|
205
|
+
|
|
206
|
+
function mightHaveStyledComponents(filePath: string): boolean {
|
|
207
|
+
const cached = styledCheckCache.get(filePath)
|
|
208
|
+
if (cached !== undefined) return cached
|
|
209
|
+
try {
|
|
210
|
+
const content = readFileSync(filePath, 'utf-8')
|
|
211
|
+
const result = content.includes('styled(')
|
|
212
|
+
styledCheckCache.set(filePath, result)
|
|
213
|
+
return result
|
|
214
|
+
} catch {
|
|
215
|
+
styledCheckCache.set(filePath, false)
|
|
216
|
+
return false
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
116
220
|
// we load tamagui delayed because we need to set some global/env stuff before importing
|
|
117
221
|
// otherwise we'd import `rnw` and cause it to evaluate react-native-web which causes errors
|
|
118
222
|
|
|
@@ -178,6 +282,12 @@ export function createExtractor(
|
|
|
178
282
|
...restProps
|
|
179
283
|
} = options
|
|
180
284
|
|
|
285
|
+
// invalidate dynamic cache for this file on re-parse (HMR)
|
|
286
|
+
if (sourcePath && dynamicComponentCache.has(sourcePath)) {
|
|
287
|
+
dynamicComponentCache.delete(sourcePath)
|
|
288
|
+
styledCheckCache.delete(sourcePath)
|
|
289
|
+
}
|
|
290
|
+
|
|
181
291
|
if (sourcePath.includes('.tamagui-dynamic-eval')) {
|
|
182
292
|
return null
|
|
183
293
|
}
|
|
@@ -375,12 +485,12 @@ export function createExtractor(
|
|
|
375
485
|
logger.info(` - import via ${moduleName} ${valid}`)
|
|
376
486
|
}
|
|
377
487
|
|
|
378
|
-
if (extractStyledDefinitions) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
488
|
+
if (extractStyledDefinitions && enableDynamicEvaluation) {
|
|
489
|
+
// check all imports for `styled`, not just valid packages
|
|
490
|
+
// styled( is basically guaranteed to be tamagui regardless of source
|
|
491
|
+
if (node.specifiers.some((specifier) => specifier.local.name === 'styled')) {
|
|
492
|
+
doesUseValidImport = true
|
|
493
|
+
// don't break - need to collect all import declarations for the styled() handler
|
|
384
494
|
}
|
|
385
495
|
}
|
|
386
496
|
|
|
@@ -400,7 +510,7 @@ export function createExtractor(
|
|
|
400
510
|
}
|
|
401
511
|
if (isValidComponent) {
|
|
402
512
|
doesUseValidImport = true
|
|
403
|
-
break
|
|
513
|
+
if (!(extractStyledDefinitions && enableDynamicEvaluation)) break
|
|
404
514
|
}
|
|
405
515
|
}
|
|
406
516
|
}
|
|
@@ -411,6 +521,35 @@ export function createExtractor(
|
|
|
411
521
|
)
|
|
412
522
|
}
|
|
413
523
|
|
|
524
|
+
if (
|
|
525
|
+
!doesUseValidImport &&
|
|
526
|
+
extractStyledDefinitions &&
|
|
527
|
+
enableDynamicEvaluation &&
|
|
528
|
+
sourcePath
|
|
529
|
+
) {
|
|
530
|
+
// check if any local import is in the dynamic cache or has styled components
|
|
531
|
+
for (const bodyPath of body) {
|
|
532
|
+
if (bodyPath.type !== 'ImportDeclaration') continue
|
|
533
|
+
const node = (
|
|
534
|
+
'node' in bodyPath ? bodyPath.node : bodyPath
|
|
535
|
+
) as t.ImportDeclaration
|
|
536
|
+
const moduleName = node.source.value
|
|
537
|
+
|
|
538
|
+
const resolved = resolveImportPath(sourcePath, moduleName)
|
|
539
|
+
if (!resolved) continue
|
|
540
|
+
|
|
541
|
+
if (dynamicComponentCache.has(resolved)) {
|
|
542
|
+
doesUseValidImport = true
|
|
543
|
+
break
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (mightHaveStyledComponents(resolved)) {
|
|
547
|
+
doesUseValidImport = true
|
|
548
|
+
break
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
414
553
|
if (!doesUseValidImport) {
|
|
415
554
|
return null
|
|
416
555
|
}
|
|
@@ -484,6 +623,10 @@ export function createExtractor(
|
|
|
484
623
|
? path.parent.id.name
|
|
485
624
|
: 'unknown'
|
|
486
625
|
|
|
626
|
+
if (shouldPrintDebug) {
|
|
627
|
+
logger.info(` [styled] Found styled(${variableName})`)
|
|
628
|
+
}
|
|
629
|
+
|
|
487
630
|
const parentNode = path.node.arguments[0]
|
|
488
631
|
|
|
489
632
|
if (!t.isIdentifier(parentNode)) {
|
|
@@ -496,10 +639,12 @@ export function createExtractor(
|
|
|
496
639
|
return
|
|
497
640
|
}
|
|
498
641
|
|
|
499
|
-
|
|
642
|
+
// look up by parent first (e.g. View in `styled(View, {...})`), then by self
|
|
643
|
+
let Component =
|
|
644
|
+
getValidImportedComponent(parentName) || getValidImportedComponent(variableName)
|
|
500
645
|
|
|
501
646
|
if (!Component) {
|
|
502
|
-
if (enableDynamicEvaluation
|
|
647
|
+
if (!enableDynamicEvaluation) {
|
|
503
648
|
return
|
|
504
649
|
}
|
|
505
650
|
|
|
@@ -583,6 +728,7 @@ export function createExtractor(
|
|
|
583
728
|
// for now dont parse variants, spreads, etc
|
|
584
729
|
const skipped = new Set<t.ObjectProperty | t.SpreadElement | t.ObjectMethod>()
|
|
585
730
|
const styles = {}
|
|
731
|
+
const staticDefaultProps = {}
|
|
586
732
|
|
|
587
733
|
// Generate scope object at this level
|
|
588
734
|
const staticNamespace = getStaticBindingsForScope(
|
|
@@ -604,6 +750,19 @@ export function createExtractor(
|
|
|
604
750
|
const attemptEvalSafe = createSafeEvaluator(attemptEval)
|
|
605
751
|
|
|
606
752
|
for (const property of definition.properties) {
|
|
753
|
+
if (
|
|
754
|
+
t.isObjectProperty(property) &&
|
|
755
|
+
(t.isIdentifier(property.key) || t.isStringLiteral(property.key))
|
|
756
|
+
) {
|
|
757
|
+
const key = t.isIdentifier(property.key)
|
|
758
|
+
? property.key.name
|
|
759
|
+
: property.key.value
|
|
760
|
+
const defaultPropValue = attemptEvalSafe(property.value)
|
|
761
|
+
if (defaultPropValue !== FAILED_EVAL) {
|
|
762
|
+
staticDefaultProps[key] = defaultPropValue
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
607
766
|
if (
|
|
608
767
|
!t.isObjectProperty(property) ||
|
|
609
768
|
!t.isIdentifier(property.key) ||
|
|
@@ -667,23 +826,9 @@ export function createExtractor(
|
|
|
667
826
|
)
|
|
668
827
|
}
|
|
669
828
|
|
|
670
|
-
//
|
|
671
|
-
//
|
|
672
|
-
|
|
673
|
-
if (
|
|
674
|
-
skipped.has(prop) ||
|
|
675
|
-
!t.isObjectProperty(prop) ||
|
|
676
|
-
!t.isIdentifier(prop.key)
|
|
677
|
-
) {
|
|
678
|
-
return prop
|
|
679
|
-
}
|
|
680
|
-
const key = prop.key.name
|
|
681
|
-
const value = classNames[key]
|
|
682
|
-
if (value) {
|
|
683
|
-
return t.objectProperty(t.stringLiteral(key), t.stringLiteral(value))
|
|
684
|
-
}
|
|
685
|
-
return prop
|
|
686
|
-
})
|
|
829
|
+
// don't replace definition values with class name strings -
|
|
830
|
+
// the runtime needs real values for animations, context, and group styles.
|
|
831
|
+
// we only emit the CSS rules so they're available if the runtime uses classNames.
|
|
687
832
|
|
|
688
833
|
if (out.rulesToInsert) {
|
|
689
834
|
for (const key in out.rulesToInsert) {
|
|
@@ -697,6 +842,34 @@ export function createExtractor(
|
|
|
697
842
|
|
|
698
843
|
res.styled++
|
|
699
844
|
|
|
845
|
+
// register so JSX handler can find this component (same-file and cross-file)
|
|
846
|
+
if (extractStyledDefinitions && enableDynamicEvaluation && Component) {
|
|
847
|
+
const dynamicStaticConfig = {
|
|
848
|
+
...Component.staticConfig,
|
|
849
|
+
defaultProps: {
|
|
850
|
+
...Component.staticConfig.defaultProps,
|
|
851
|
+
...staticDefaultProps,
|
|
852
|
+
},
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// add to allLoadedComponents with '' so getValidComponent matches when moduleName is ''
|
|
856
|
+
// (same-file styled components have '' as moduleName in JSX handler)
|
|
857
|
+
propsWithFileInfo.allLoadedComponents.push({
|
|
858
|
+
moduleName: '',
|
|
859
|
+
nameToInfo: { [variableName]: { staticConfig: dynamicStaticConfig } },
|
|
860
|
+
})
|
|
861
|
+
|
|
862
|
+
// also cache by file path so other files importing from this path can find it
|
|
863
|
+
if (sourcePath) {
|
|
864
|
+
let existing = dynamicComponentCache.get(sourcePath)
|
|
865
|
+
if (!existing) {
|
|
866
|
+
existing = { moduleName: sourcePath, nameToInfo: {} }
|
|
867
|
+
dynamicComponentCache.set(sourcePath, existing)
|
|
868
|
+
}
|
|
869
|
+
existing.nameToInfo[variableName] = { staticConfig: dynamicStaticConfig }
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
700
873
|
if (shouldPrintDebug) {
|
|
701
874
|
logger.info(`Extracted styled(${variableName})`)
|
|
702
875
|
}
|
|
@@ -725,22 +898,77 @@ export function createExtractor(
|
|
|
725
898
|
// validate its a proper import from tamagui (or internally inside tamagui)
|
|
726
899
|
const binding = traversePath.scope.getBinding(node.name.name)
|
|
727
900
|
let moduleName = ''
|
|
901
|
+
let dynamicComponent: { staticConfig: any } | null = null
|
|
728
902
|
|
|
729
903
|
if (binding) {
|
|
730
904
|
if (t.isImportDeclaration(binding.path.parent)) {
|
|
731
905
|
moduleName = binding.path.parent.source.value
|
|
732
906
|
if (!isValidImport(propsWithFileInfo, moduleName, binding.identifier.name)) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
)
|
|
907
|
+
// fallback: try dynamic component cache for local imports (relative or tsconfig alias)
|
|
908
|
+
if (enableDynamicEvaluation && sourcePath) {
|
|
909
|
+
const resolved = resolveImportPath(sourcePath, moduleName)
|
|
910
|
+
if (resolved) {
|
|
911
|
+
// check cache first
|
|
912
|
+
const cached = dynamicComponentCache.get(resolved)
|
|
913
|
+
if (cached?.nameToInfo[binding.identifier.name]) {
|
|
914
|
+
dynamicComponent = cached.nameToInfo[binding.identifier.name]
|
|
915
|
+
} else if (
|
|
916
|
+
!dynamicLoadingInProgress.has(resolved) &&
|
|
917
|
+
mightHaveStyledComponents(resolved)
|
|
918
|
+
) {
|
|
919
|
+
// proactively load the file
|
|
920
|
+
dynamicLoadingInProgress.add(resolved)
|
|
921
|
+
try {
|
|
922
|
+
const out = loadTamaguiSync({
|
|
923
|
+
forceExports: true,
|
|
924
|
+
components: [resolved],
|
|
925
|
+
})
|
|
926
|
+
if (out?.components) {
|
|
927
|
+
for (const comp of out.components) {
|
|
928
|
+
// merge into cache
|
|
929
|
+
let existing = dynamicComponentCache.get(resolved)
|
|
930
|
+
if (!existing) {
|
|
931
|
+
existing = { moduleName: resolved, nameToInfo: {} }
|
|
932
|
+
dynamicComponentCache.set(resolved, existing)
|
|
933
|
+
}
|
|
934
|
+
Object.assign(existing.nameToInfo, comp.nameToInfo)
|
|
935
|
+
// also add to allLoadedComponents so getValidComponent works
|
|
936
|
+
propsWithFileInfo.allLoadedComponents.push({
|
|
937
|
+
moduleName: resolved,
|
|
938
|
+
nameToInfo: comp.nameToInfo,
|
|
939
|
+
})
|
|
940
|
+
}
|
|
941
|
+
const cachedNow = dynamicComponentCache.get(resolved)
|
|
942
|
+
if (cachedNow?.nameToInfo[binding.identifier.name]) {
|
|
943
|
+
dynamicComponent = cachedNow.nameToInfo[binding.identifier.name]
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
} catch (err) {
|
|
947
|
+
if (shouldPrintDebug) {
|
|
948
|
+
logger.info(` - Failed to dynamically load ${resolved}: ${err}`)
|
|
949
|
+
}
|
|
950
|
+
} finally {
|
|
951
|
+
dynamicLoadingInProgress.delete(resolved)
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
if (!dynamicComponent) {
|
|
958
|
+
if (shouldPrintDebug) {
|
|
959
|
+
logger.info(
|
|
960
|
+
` - Binding in component ${componentName} not valid import: "${binding.identifier.name}" isn't in ${moduleName}\n`
|
|
961
|
+
)
|
|
962
|
+
}
|
|
963
|
+
return
|
|
737
964
|
}
|
|
738
|
-
return
|
|
739
965
|
}
|
|
740
966
|
}
|
|
741
967
|
}
|
|
742
968
|
|
|
743
|
-
const component =
|
|
969
|
+
const component =
|
|
970
|
+
dynamicComponent ||
|
|
971
|
+
getValidComponent(propsWithFileInfo, moduleName, node.name.name)
|
|
744
972
|
if (!component || !component.staticConfig) {
|
|
745
973
|
if (shouldPrintDebug) {
|
|
746
974
|
logger.info(`\n - No Tamagui conf for: ${node.name.name}\n`)
|
|
@@ -832,13 +1060,6 @@ export function createExtractor(
|
|
|
832
1060
|
const isTextView = staticConfig.isText || false
|
|
833
1061
|
const validStyles = staticConfig?.validStyles ?? {}
|
|
834
1062
|
|
|
835
|
-
if (process.env.NODE_ENV === 'production') {
|
|
836
|
-
if (isTextView) {
|
|
837
|
-
// temporarily disabled - need to fix css nesting dix
|
|
838
|
-
return
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
|
|
842
1063
|
// find render="a" render="main" etc dom indicators
|
|
843
1064
|
let tagName = defaultProps.render ?? (isTextView ? 'span' : 'div')
|
|
844
1065
|
traversePath
|
|
@@ -1292,7 +1513,7 @@ export function createExtractor(
|
|
|
1292
1513
|
return attr
|
|
1293
1514
|
}
|
|
1294
1515
|
|
|
1295
|
-
// $platform-web, $platform-native, $platform-ios, $platform-android
|
|
1516
|
+
// $platform-web, $platform-native, $platform-ios, $platform-android, $platform-tv, $platform-androidtv, $platform-tvos
|
|
1296
1517
|
if (name.startsWith('$platform-')) {
|
|
1297
1518
|
const platformName = name.slice(10) // remove '$platform-'
|
|
1298
1519
|
const isMatchingPlatform =
|
|
@@ -1314,6 +1535,20 @@ export function createExtractor(
|
|
|
1314
1535
|
attr: path.node,
|
|
1315
1536
|
}))
|
|
1316
1537
|
} else {
|
|
1538
|
+
// On native builds, sub-platform variants (android, ios, tv, androidtv, tvos)
|
|
1539
|
+
// can't be resolved at compile time - leave for runtime evaluation
|
|
1540
|
+
if (
|
|
1541
|
+
platform === 'native' &&
|
|
1542
|
+
nativeOnlyPlatforms.has(platformName)
|
|
1543
|
+
) {
|
|
1544
|
+
if (shouldPrintDebug) {
|
|
1545
|
+
logger.info(
|
|
1546
|
+
` ! keeping platform-specific style for runtime evaluation: ${name}`
|
|
1547
|
+
)
|
|
1548
|
+
}
|
|
1549
|
+
inlined.set(name, true)
|
|
1550
|
+
return attr
|
|
1551
|
+
}
|
|
1317
1552
|
// Platform doesn't match, skip these styles entirely
|
|
1318
1553
|
if (shouldPrintDebug) {
|
|
1319
1554
|
logger.info(` ! skipping non-matching platform style: ${name}`)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, extname, join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
type ModuleFormat = 'cjs' | 'esm'
|
|
5
|
+
|
|
6
|
+
// cache per directory to avoid repeated fs reads
|
|
7
|
+
const formatCache = new Map<string, ModuleFormat>()
|
|
8
|
+
|
|
9
|
+
export function detectModuleFormat(filePath: string): ModuleFormat {
|
|
10
|
+
const ext = extname(filePath)
|
|
11
|
+
|
|
12
|
+
// definitive by extension
|
|
13
|
+
if (ext === '.mjs') return 'esm'
|
|
14
|
+
if (ext === '.cjs') return 'cjs'
|
|
15
|
+
|
|
16
|
+
// walk up to find nearest package.json with "type" field
|
|
17
|
+
let dir = dirname(filePath)
|
|
18
|
+
while (true) {
|
|
19
|
+
if (formatCache.has(dir)) {
|
|
20
|
+
return formatCache.get(dir)!
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'))
|
|
25
|
+
const format: ModuleFormat = pkg.type === 'module' ? 'esm' : 'cjs'
|
|
26
|
+
formatCache.set(dir, format)
|
|
27
|
+
return format
|
|
28
|
+
} catch {
|
|
29
|
+
// no package.json or malformed, keep walking
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const parent = dirname(dir)
|
|
33
|
+
if (parent === dir) break
|
|
34
|
+
dir = parent
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return 'cjs'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function clearFormatCache() {
|
|
41
|
+
formatCache.clear()
|
|
42
|
+
}
|
|
@@ -25,6 +25,11 @@ export function TsconfigPathsPlugin(): Plugin {
|
|
|
25
25
|
name,
|
|
26
26
|
setup({ onResolve }) {
|
|
27
27
|
onResolve({ filter: /.*/ }, (args) => {
|
|
28
|
+
// skip @tamagui packages - they should be externalized, not resolved via tsconfig
|
|
29
|
+
if (args.path.startsWith('@tamagui/')) {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
const paths = compilerOptions.paths || {}
|
|
29
34
|
const hasMatchingPath = Object.keys(paths).some((p) =>
|
|
30
35
|
new RegExp(p.replace('*', '\\w*')).test(args.path)
|
|
@@ -59,7 +64,7 @@ export function TsconfigPathsPlugin(): Plugin {
|
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
function loadCompilerOptionsFromTsconfig(tsconfig?: Tsconfig | string) {
|
|
67
|
+
export function loadCompilerOptionsFromTsconfig(tsconfig?: Tsconfig | string) {
|
|
63
68
|
if (!tsconfig) {
|
|
64
69
|
const configPath =
|
|
65
70
|
findConfigFile(process.cwd(), sys.fileExists, 'tsconfig.json') ||
|
|
@@ -107,7 +107,7 @@ export async function extractToClassNames({
|
|
|
107
107
|
sourcePath,
|
|
108
108
|
extractStyledDefinitions: true,
|
|
109
109
|
onStyledDefinitionRule(identifier, rules) {
|
|
110
|
-
const css = rules.join('
|
|
110
|
+
const css = rules.join('\n')
|
|
111
111
|
if (shouldPrintDebug) {
|
|
112
112
|
console.info(`adding styled() rule: .${identifier} ${css}`)
|
|
113
113
|
}
|
|
@@ -343,11 +343,18 @@ export async function extractToClassNames({
|
|
|
343
343
|
baseClassNameStr = `font_${baseFontFamily}${baseClassNameStr ? ` ${baseClassNameStr}` : ''}`
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
346
|
+
// add is_View or is_Text base class matching runtime behavior
|
|
347
|
+
const baseTypeClass = staticConfig.isText ? 'is_Text' : 'is_View'
|
|
348
|
+
baseClassNameStr = `${baseTypeClass}${baseClassNameStr ? ` ${baseClassNameStr}` : ''}`
|
|
349
|
+
|
|
350
|
+
// add component name class (skip 'Text' since is_Text already covers it)
|
|
351
|
+
const componentNameFinal = staticConfig.componentName
|
|
352
|
+
let base =
|
|
353
|
+
componentNameFinal && componentNameFinal !== 'Text'
|
|
354
|
+
? t.stringLiteral(
|
|
355
|
+
`is_${componentNameFinal}${baseClassNameStr ? ` ${baseClassNameStr}` : ''}`
|
|
356
|
+
)
|
|
357
|
+
: t.stringLiteral(baseClassNameStr || '')
|
|
351
358
|
|
|
352
359
|
attrClassName = attrClassName as t.Expression | null // actual typescript bug, flatMap doesn't update from never
|
|
353
360
|
|
|
@@ -616,10 +623,9 @@ function hoistClassName(path: NodePath<t.JSXElement>, str: string) {
|
|
|
616
623
|
function cleanupClassName(inStr: string) {
|
|
617
624
|
const out = new Set<string>()
|
|
618
625
|
for (const part of inStr.split(' ')) {
|
|
619
|
-
if (part === ' ') continue
|
|
626
|
+
if (!part || part === ' ') continue
|
|
620
627
|
if (part === 'font_') continue
|
|
621
628
|
out.add(part)
|
|
622
629
|
}
|
|
623
|
-
|
|
624
|
-
return [...out].join(' ') + ' '
|
|
630
|
+
return [...out].join(' ')
|
|
625
631
|
}
|