@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
|
@@ -45,24 +45,9 @@ export function concatClassName(_cn: Record<string, any> | null | undefined): st
|
|
|
45
45
|
continue
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const nextChar = name[splitIndex + 1]
|
|
49
|
-
// synced to static-ui constants
|
|
50
|
-
// MEDIA_SEP
|
|
51
|
-
const isMediaQuery = nextChar === '_'
|
|
52
|
-
// PSEUDO_SEP
|
|
53
|
-
// commenting out three things to make pseudos override properly
|
|
54
|
-
// (leave in for a bit to see if other bugs pop up later):
|
|
55
|
-
// 1. const isPseudoQuery = nextChar === '0'
|
|
56
48
|
const styleKey = name.slice(1, name.indexOf('-'))
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// by finding the underscore after the media key name
|
|
60
|
-
const mediaStart = splitIndex + 2
|
|
61
|
-
const mediaEnd = name.indexOf('_', mediaStart)
|
|
62
|
-
const mediaKey =
|
|
63
|
-
isMediaQuery && mediaEnd > mediaStart ? name.slice(mediaStart, mediaEnd) : null
|
|
64
|
-
const uid = mediaKey ? styleKey + mediaKey : styleKey
|
|
65
|
-
// 3. && !isPseudoQuery
|
|
49
|
+
const { mediaKey, pseudoKey } = getClassNameScope(name, splitIndex)
|
|
50
|
+
const uid = `${styleKey}${mediaKey ? `@${mediaKey}` : ''}${pseudoKey ? `:${pseudoKey}` : ''}`
|
|
66
51
|
|
|
67
52
|
if (usedPrefixes.has(uid)) {
|
|
68
53
|
// if (shouldDebug) console.log('debug exclude:', usedPrefixes, name)
|
|
@@ -75,8 +60,8 @@ export function concatClassName(_cn: Record<string, any> | null | undefined): st
|
|
|
75
60
|
if (propName && propObjects) {
|
|
76
61
|
if (
|
|
77
62
|
propObjects.some((po) => {
|
|
78
|
-
if (
|
|
79
|
-
const propKey = pseudoInvert[
|
|
63
|
+
if (pseudoKey) {
|
|
64
|
+
const propKey = pseudoInvert[pseudoKey]
|
|
80
65
|
return po && po[propKey] && propName in po[propKey] && po[propKey] !== null
|
|
81
66
|
}
|
|
82
67
|
const res = po && propName in po && po[propName] !== null
|
|
@@ -95,11 +80,43 @@ export function concatClassName(_cn: Record<string, any> | null | undefined): st
|
|
|
95
80
|
return final.trim()
|
|
96
81
|
}
|
|
97
82
|
|
|
83
|
+
function getClassNameScope(name: string, splitIndex: number) {
|
|
84
|
+
let mediaKey = ''
|
|
85
|
+
let pseudoKey = ''
|
|
86
|
+
let valueStart = splitIndex + 1
|
|
87
|
+
|
|
88
|
+
if (name[valueStart] === '_') {
|
|
89
|
+
const mediaEnd = name.indexOf('_', valueStart + 1)
|
|
90
|
+
if (mediaEnd > valueStart + 1) {
|
|
91
|
+
mediaKey = name.slice(valueStart + 1, mediaEnd)
|
|
92
|
+
valueStart = mediaEnd + 1
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (name[valueStart] === '0') {
|
|
97
|
+
const pseudoStart = valueStart + 1
|
|
98
|
+
for (const nextPseudoKey of pseudoKeys) {
|
|
99
|
+
if (name.startsWith(`${nextPseudoKey}-`, pseudoStart)) {
|
|
100
|
+
pseudoKey = nextPseudoKey
|
|
101
|
+
break
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { mediaKey, pseudoKey }
|
|
107
|
+
}
|
|
108
|
+
|
|
98
109
|
const pseudoInvert = {
|
|
99
110
|
hover: 'hoverStyle',
|
|
111
|
+
active: 'pressStyle',
|
|
100
112
|
focus: 'focusStyle',
|
|
101
|
-
|
|
113
|
+
'focus-visible': 'focusVisibleStyle',
|
|
114
|
+
'focus-within': 'focusWithinStyle',
|
|
102
115
|
focusVisible: 'focusVisibleStyle',
|
|
103
116
|
focusWithin: 'focusWithinStyle',
|
|
104
117
|
disabled: 'disabledStyle',
|
|
118
|
+
enter: 'enterStyle',
|
|
119
|
+
exit: 'exitStyle',
|
|
105
120
|
}
|
|
121
|
+
|
|
122
|
+
const pseudoKeys = Object.keys(pseudoInvert).sort((a, b) => b.length - a.length)
|
|
@@ -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
|
}
|
|
@@ -505,7 +644,7 @@ export function createExtractor(
|
|
|
505
644
|
getValidImportedComponent(parentName) || getValidImportedComponent(variableName)
|
|
506
645
|
|
|
507
646
|
if (!Component) {
|
|
508
|
-
if (enableDynamicEvaluation
|
|
647
|
+
if (!enableDynamicEvaluation) {
|
|
509
648
|
return
|
|
510
649
|
}
|
|
511
650
|
|
|
@@ -589,6 +728,7 @@ export function createExtractor(
|
|
|
589
728
|
// for now dont parse variants, spreads, etc
|
|
590
729
|
const skipped = new Set<t.ObjectProperty | t.SpreadElement | t.ObjectMethod>()
|
|
591
730
|
const styles = {}
|
|
731
|
+
const staticDefaultProps = {}
|
|
592
732
|
|
|
593
733
|
// Generate scope object at this level
|
|
594
734
|
const staticNamespace = getStaticBindingsForScope(
|
|
@@ -610,6 +750,19 @@ export function createExtractor(
|
|
|
610
750
|
const attemptEvalSafe = createSafeEvaluator(attemptEval)
|
|
611
751
|
|
|
612
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
|
+
|
|
613
766
|
if (
|
|
614
767
|
!t.isObjectProperty(property) ||
|
|
615
768
|
!t.isIdentifier(property.key) ||
|
|
@@ -689,6 +842,34 @@ export function createExtractor(
|
|
|
689
842
|
|
|
690
843
|
res.styled++
|
|
691
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
|
+
|
|
692
873
|
if (shouldPrintDebug) {
|
|
693
874
|
logger.info(`Extracted styled(${variableName})`)
|
|
694
875
|
}
|
|
@@ -717,22 +898,77 @@ export function createExtractor(
|
|
|
717
898
|
// validate its a proper import from tamagui (or internally inside tamagui)
|
|
718
899
|
const binding = traversePath.scope.getBinding(node.name.name)
|
|
719
900
|
let moduleName = ''
|
|
901
|
+
let dynamicComponent: { staticConfig: any } | null = null
|
|
720
902
|
|
|
721
903
|
if (binding) {
|
|
722
904
|
if (t.isImportDeclaration(binding.path.parent)) {
|
|
723
905
|
moduleName = binding.path.parent.source.value
|
|
724
906
|
if (!isValidImport(propsWithFileInfo, moduleName, binding.identifier.name)) {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
)
|
|
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
|
|
729
964
|
}
|
|
730
|
-
return
|
|
731
965
|
}
|
|
732
966
|
}
|
|
733
967
|
}
|
|
734
968
|
|
|
735
|
-
const component =
|
|
969
|
+
const component =
|
|
970
|
+
dynamicComponent ||
|
|
971
|
+
getValidComponent(propsWithFileInfo, moduleName, node.name.name)
|
|
736
972
|
if (!component || !component.staticConfig) {
|
|
737
973
|
if (shouldPrintDebug) {
|
|
738
974
|
logger.info(`\n - No Tamagui conf for: ${node.name.name}\n`)
|
|
@@ -824,13 +1060,6 @@ export function createExtractor(
|
|
|
824
1060
|
const isTextView = staticConfig.isText || false
|
|
825
1061
|
const validStyles = staticConfig?.validStyles ?? {}
|
|
826
1062
|
|
|
827
|
-
if (process.env.NODE_ENV === 'production') {
|
|
828
|
-
if (isTextView) {
|
|
829
|
-
// temporarily disabled - need to fix css nesting dix
|
|
830
|
-
return
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
|
|
834
1063
|
// find render="a" render="main" etc dom indicators
|
|
835
1064
|
let tagName = defaultProps.render ?? (isTextView ? 'span' : 'div')
|
|
836
1065
|
traversePath
|
|
@@ -1215,6 +1444,12 @@ export function createExtractor(
|
|
|
1215
1444
|
)
|
|
1216
1445
|
// remove className - we dont use rnw styling
|
|
1217
1446
|
delete out.className
|
|
1447
|
+
// remove style - rnw createDOMProps unconditionally emits a
|
|
1448
|
+
// (possibly empty) style key, but we passed it a single
|
|
1449
|
+
// non-style prop. Leaving it in causes Object.keys(out) to
|
|
1450
|
+
// iterate twice and emit the original JSXAttribute twice
|
|
1451
|
+
// (e.g. duplicate testID), breaking the DOM output.
|
|
1452
|
+
delete out.style
|
|
1218
1453
|
}
|
|
1219
1454
|
}
|
|
1220
1455
|
|
|
@@ -1238,6 +1473,23 @@ export function createExtractor(
|
|
|
1238
1473
|
key === '__source' ||
|
|
1239
1474
|
key === '__self'
|
|
1240
1475
|
) {
|
|
1476
|
+
if (
|
|
1477
|
+
styleValue === FAILED_EVAL &&
|
|
1478
|
+
key !== name &&
|
|
1479
|
+
t.isJSXAttribute(attr.value)
|
|
1480
|
+
) {
|
|
1481
|
+
// createDOMProps renamed the prop (e.g. testID -> data-testid).
|
|
1482
|
+
// preserve the original expression value but use the new
|
|
1483
|
+
// attribute name. restricted to FAILED_EVAL because the
|
|
1484
|
+
// later `case 'attr'` rename pass only runs on
|
|
1485
|
+
// statically-evaluable values; for static values that pass
|
|
1486
|
+
// intentionally preserves some prop names (e.g. focusable
|
|
1487
|
+
// in v2) instead of doing the createDOMProps rename.
|
|
1488
|
+
return {
|
|
1489
|
+
type: 'attr',
|
|
1490
|
+
value: t.jsxAttribute(t.jsxIdentifier(key), attr.value.value),
|
|
1491
|
+
} as const
|
|
1492
|
+
}
|
|
1241
1493
|
return attr
|
|
1242
1494
|
}
|
|
1243
1495
|
if (shouldPrintDebug) {
|
|
@@ -1284,7 +1536,7 @@ export function createExtractor(
|
|
|
1284
1536
|
return attr
|
|
1285
1537
|
}
|
|
1286
1538
|
|
|
1287
|
-
// $platform-web, $platform-native, $platform-ios, $platform-android
|
|
1539
|
+
// $platform-web, $platform-native, $platform-ios, $platform-android, $platform-tv, $platform-androidtv, $platform-tvos
|
|
1288
1540
|
if (name.startsWith('$platform-')) {
|
|
1289
1541
|
const platformName = name.slice(10) // remove '$platform-'
|
|
1290
1542
|
const isMatchingPlatform =
|
|
@@ -1306,6 +1558,20 @@ export function createExtractor(
|
|
|
1306
1558
|
attr: path.node,
|
|
1307
1559
|
}))
|
|
1308
1560
|
} else {
|
|
1561
|
+
// On native builds, sub-platform variants (android, ios, tv, androidtv, tvos)
|
|
1562
|
+
// can't be resolved at compile time - leave for runtime evaluation
|
|
1563
|
+
if (
|
|
1564
|
+
platform === 'native' &&
|
|
1565
|
+
nativeOnlyPlatforms.has(platformName)
|
|
1566
|
+
) {
|
|
1567
|
+
if (shouldPrintDebug) {
|
|
1568
|
+
logger.info(
|
|
1569
|
+
` ! keeping platform-specific style for runtime evaluation: ${name}`
|
|
1570
|
+
)
|
|
1571
|
+
}
|
|
1572
|
+
inlined.set(name, true)
|
|
1573
|
+
return attr
|
|
1574
|
+
}
|
|
1309
1575
|
// Platform doesn't match, skip these styles entirely
|
|
1310
1576
|
if (shouldPrintDebug) {
|
|
1311
1577
|
logger.info(` ! skipping non-matching platform style: ${name}`)
|
|
@@ -1912,6 +2178,10 @@ export function createExtractor(
|
|
|
1912
2178
|
)
|
|
1913
2179
|
// remove rnw className use ours
|
|
1914
2180
|
out.className = cn
|
|
2181
|
+
// see note in single-prop branch above; createDOMProps
|
|
2182
|
+
// also emits a stray style key here that would duplicate
|
|
2183
|
+
// emitted JSXAttributes downstream.
|
|
2184
|
+
delete out.style
|
|
1915
2185
|
}
|
|
1916
2186
|
if (shouldPrintDebug) {
|
|
1917
2187
|
logger.info([' - expanded variant', name, out].join(' '))
|
|
@@ -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') ||
|