Skip to content

Commit d61dbe1

Browse files
authored
chore: update estree walker to ts version (#52)
* chore: update estree walker to ts version * chore: temp commit * refactor: refactor code structure
1 parent 1cd8d79 commit d61dbe1

File tree

11 files changed

+1964
-1806
lines changed

11 files changed

+1964
-1806
lines changed

build/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const baseConfig = {
1313
'fs-extra',
1414
'magic-string',
1515
],
16-
noExternal: ['estree-walker'],
16+
noExternal: ['estree-walker-ts'],
1717
format: ['cjs', 'esm'],
1818
clean: true,
1919
minify: true,

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
},
7474
"peerDependencies": {
7575
"chalk": "^4.1.2",
76-
"estree-walker": "^3.0.3",
76+
"estree-walker-ts": "^1.0.0-beta.2",
7777
"fast-glob": "^3.2.12",
7878
"fs-extra": "^11.1.1",
7979
"hash-sum": "^2.0.0",
@@ -83,7 +83,7 @@
8383
},
8484
"dependencies": {
8585
"chalk": "^4.1.2",
86-
"estree-walker": "^3.0.3",
86+
"estree-walker-ts": "^1.0.0-beta.2",
8787
"fast-glob": "^3.2.12",
8888
"fs-extra": "^11.1.1",
8989
"hash-sum": "^2.0.0",

packages/core/index.ts

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createUnplugin } from 'unplugin'
2-
import { JSX_TSX_REG, NAME, SUPPORT_FILE_REG } from '@unplugin-vue-cssvars/utils'
2+
import { JSX_TSX_REG, NAME, SUPPORT_FILE_REG, setTArray } from '@unplugin-vue-cssvars/utils'
33
import { createFilter } from '@rollup/pluginutils'
44
import { parse } from '@vue/compiler-sfc'
55
import chalk from 'chalk'
@@ -19,7 +19,8 @@ import type { TMatchVariable } from './parser'
1919
import type { Options } from './types'
2020
// TODO: webpack hmr
2121
const unplugin = createUnplugin<Options>(
22-
(options: Options = {}): any => {
22+
(options: Options = {}, meta): any => {
23+
const framework = meta.framework
2324
const userOptions = initOption(options)
2425
const filter = createFilter(
2526
userOptions.include,
@@ -58,12 +59,12 @@ const unplugin = createUnplugin<Options>(
5859
} = getVBindVariableListByPath(descriptor, id, CSSFileModuleMap, isServer, userOptions.alias)
5960
const variableName = getVariable(descriptor)
6061
vbindVariableList.set(id, matchVariable(vbindVariableListByPath, variableName))
61-
62-
if (!isServer)
62+
// TODO: webpack
63+
// 'vite' | 'rollup' | 'esbuild'
64+
if (!isServer && framework !== 'webpack' && framework !== 'rspack')
6365
mgcStr = injectCssOnBuild(mgcStr, injectCSSContent, descriptor)
6466
}
6567
}
66-
6768
return {
6869
code: mgcStr.toString(),
6970
get map() {
@@ -102,24 +103,52 @@ const unplugin = createUnplugin<Options>(
102103
{
103104
name: `${NAME}:inject`,
104105
enforce: 'post',
106+
transformInclude(id: string) {
107+
return filter(id)
108+
},
105109
async transform(code: string, id: string) {
106-
if (id.includes('node_modules'))
107-
return
108-
109110
let mgcStr = new MagicString(code)
110-
111111
// ⭐TODO: 只支持 .vue ? jsx, tsx, js, ts ?
112112
try {
113113
// transform in dev
114+
// 'vite' | 'rollup' | 'esbuild'
114115
if (isServer) {
115-
if (id.endsWith('.vue')) {
116-
const injectRes = injectCSSVars(code, vbindVariableList.get(id), isScriptSetup)
116+
function injectCSSVarsFn(idKey: string) {
117+
const injectRes = injectCSSVars(code, vbindVariableList.get(idKey), isScriptSetup, framework)
117118
mgcStr = mgcStr.overwrite(0, mgcStr.length(), injectRes.code)
118119
injectRes.vbindVariableList && vbindVariableList.set(id, injectRes.vbindVariableList)
119120
isHmring = false
120121
}
121-
if (id.includes('type=style'))
122-
mgcStr = injectCssOnServer(mgcStr, vbindVariableList.get(id.split('?vue')[0]), isHmring)
122+
123+
if (framework === 'vite' ||
124+
framework === 'rollup' ||
125+
framework === 'esbuild') {
126+
if (id.endsWith('.vue'))
127+
injectCSSVarsFn(id)
128+
129+
if (id.includes('vue&type=style')) {
130+
mgcStr = injectCssOnServer(
131+
mgcStr,
132+
vbindVariableList.get(id.split('?vue')[0]),
133+
isHmring,
134+
)
135+
}
136+
}
137+
138+
if (framework === 'webpack') {
139+
if (id.includes('vue&type=script')) {
140+
const transId = id.split('?vue&type=script')[0]
141+
// todo 重复注入了
142+
injectCSSVarsFn(transId)
143+
}
144+
const cssFMM = CSSFileModuleMap.get(id)
145+
if (cssFMM && cssFMM.sfcPath && cssFMM.sfcPath.size > 0) {
146+
const sfcPathIdList = setTArray(cssFMM.sfcPath)
147+
sfcPathIdList.forEach((v) => {
148+
mgcStr = injectCssOnServer(mgcStr, vbindVariableList.get(v), isHmring)
149+
})
150+
}
151+
}
123152
}
124153

125154
return {

packages/core/inject/inject-cssvars.ts

Lines changed: 147 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
import hash from 'hash-sum'
3+
import type { IFramework } from '../types'
34
import type { TMatchVariable } from '../parser'
45

56
const importer = 'import { useCssVars as _useCssVars } from "vue"\n'
@@ -8,57 +9,114 @@ export const injectCSSVars = (
89
code: string,
910
vbindVariableList: TMatchVariable | undefined,
1011
isScriptSetup: boolean,
12+
framework: IFramework,
1113
) => {
1214
if (!vbindVariableList || vbindVariableList.length === 0) return { code, vbindVariableList }
13-
return injectCSSVarsOnServer(code, vbindVariableList, isScriptSetup)
15+
return injectCSSVarsOnServer(code, vbindVariableList, isScriptSetup, framework)
1416
}
1517

18+
// TODO use ast to impl
19+
// code 是 @vitejs/plugin-vue 编译后的代码
20+
// 分为三种种情况
21+
// 1. setup script
22+
// 1.1 有 useCssVars 的情况
23+
// 1.2 无 useCssVars 的情况
24+
// 2. option api
25+
// 2.1 有 useCssVars 的情况
26+
// 2.2 无 useCssVars 的情况
27+
// 3. composition api
28+
// 3.1 有 useCssVars 的情况
29+
// 3.2 无 useCssVars 的情况
1630
export function injectCSSVarsOnServer(
1731
code: string,
1832
vbindVariableList: TMatchVariable,
19-
isScriptSetup: boolean) {
33+
isScriptSetup: boolean,
34+
framework: IFramework) {
2035
let resCode = ''
2136
const hasUseCssVars = code.includes('useCssVars')
22-
const useCssVars = createUseCssVarsCode(code, vbindVariableList, hasUseCssVars, isScriptSetup)
37+
// 1
2338
if (isScriptSetup) {
24-
// setup script
25-
if (!hasUseCssVars) {
26-
(resCode = code.replaceAll(
39+
const useCssVars = createUseCssVarsCode(
40+
code,
41+
vbindVariableList,
42+
hasUseCssVars,
43+
true)
44+
45+
resCode = injectUseCssVarsSetup(code, useCssVars, hasUseCssVars)
46+
} else {
47+
// 2 and 3
48+
const useCssVars = createUseCssVarsCode(
49+
code,
50+
vbindVariableList,
51+
hasUseCssVars,
52+
false)
53+
54+
resCode = injectUseCssVarsOption(code, useCssVars, hasUseCssVars)
55+
}
56+
57+
return { code: resCode, vbindVariableList }
58+
}
59+
60+
// TODO: unit test
61+
export function injectUseCssVarsSetup(
62+
code: string,
63+
useCssVars: string,
64+
hasUseCssVars: boolean,
65+
) {
66+
let resCode = ''
67+
if (!hasUseCssVars) {
68+
// TODO: vite unit test
69+
if (code.includes('setup(__props, { expose }) {')) {
70+
resCode = code.replaceAll(
2771
'setup(__props, { expose }) {',
28-
`setup(__props, { expose }) {${useCssVars}`,
29-
))
30-
resCode = `${importer}${resCode}`
31-
} else {
32-
resCode = useCssVars
72+
`setup(__props, { expose }) {${useCssVars}`)
3373
}
74+
75+
// TODO unit test webpack
76+
if (code.includes('setup: function (__props, _a) {')) {
77+
resCode = code.replaceAll(
78+
'setup: function (__props, _a) {',
79+
`setup: function (__props, _a) {${useCssVars}`)
80+
}
81+
82+
resCode = resCode ? `${importer}${resCode}` : code
3483
} else {
35-
// option api
36-
if (!hasUseCssVars) {
37-
resCode = code.replaceAll('const _sfc_main', 'const __default__')
38-
resCode = resCode.replaceAll(
39-
'function _sfc_render',
40-
`${useCssVars}\n
84+
resCode = useCssVars
85+
}
86+
return resCode
87+
}
88+
89+
// TODO: unit test
90+
export function injectUseCssVarsOption(
91+
code: string,
92+
useCssVars: string,
93+
hasUseCssVars: boolean,
94+
) {
95+
let resCode = ''
96+
if (!hasUseCssVars) {
97+
resCode = code.replaceAll('const _sfc_main', 'const __default__')
98+
resCode = resCode.replaceAll(
99+
'function _sfc_render',
100+
`${useCssVars}\n
41101
const __setup__ = __default__.setup
42102
__default__.setup = __setup__
43103
? (props, ctx) => { __injectCSSVars__(); return __setup__(props, ctx) }
44104
: __injectCSSVars__
45105
const _sfc_main = __default__
46106
function _sfc_render`)
47-
resCode = `${importer}${resCode}`
48-
} else {
49-
resCode = useCssVars
50-
}
107+
resCode = `${importer}${resCode}`
108+
} else {
109+
resCode = useCssVars
51110
}
52-
53-
return { code: resCode, vbindVariableList }
111+
return resCode
54112
}
55113

56-
export function createUseCssVarsCode(
57-
code: string,
114+
// TODO: unit test
115+
export function createCSSVarsObjCode(
58116
vbindVariableList: TMatchVariable,
59-
isHas: boolean,
60-
isScriptSetup: boolean) {
61-
let cssvarsObjectCode = ''
117+
isScriptSetup: boolean,
118+
) {
119+
let resCode = ''
62120
vbindVariableList.forEach((vbVar) => {
63121
// 如果 hash 存在,则说明是由热更新引起的,不需要重新设置 hash
64122
const hashVal = vbVar.hash || hash(vbVar.value + vbVar.has)
@@ -73,29 +131,74 @@ export function createUseCssVarsCode(
73131
// ref 用.value
74132
varStr = vbVar.isRef ? `${vbVar.value}.value` : varStr
75133
}
76-
cssvarsObjectCode = `"${hashVal}": ${varStr},\n ${cssvarsObjectCode}`
134+
resCode = `"${hashVal}": ${varStr},\n ${resCode}`
77135
})
78-
let resCode = ''
79-
if (isHas) {
80-
resCode = code.includes('_useCssVars((_ctx') ? code.replaceAll(
81-
'_useCssVars((_ctx) => ({',
82-
`_useCssVars((_ctx) => ({\n ${cssvarsObjectCode}`)
83-
: code.replaceAll(
84-
'_useCssVars(_ctx => ({',
85-
`_useCssVars((_ctx) => ({\n ${cssvarsObjectCode}`)
86-
} else {
87-
// setup script
88-
resCode = `
136+
return resCode
137+
}
138+
139+
// TODO: unit test
140+
export function createUCVCSetupUnHas(cssvarsObjectCode: string) {
141+
return `
89142
_useCssVars((_ctx) => ({
90143
${cssvarsObjectCode}
91-
}));`
144+
}));`
145+
}
92146

93-
// composition api 和 option api
94-
if (!isScriptSetup) {
95-
resCode = `
147+
// TODO: unit test
148+
export function createUCVCOptionUnHas(resCode: string) {
149+
return `
96150
const __injectCSSVars__ = () => {\n
97151
${resCode}\n
98152
};`
153+
}
154+
155+
// TODO: unit test
156+
export function createUCVCHas(
157+
code: string,
158+
cssvarsObjectCode: string,
159+
) {
160+
let resCode = ''
161+
// TODO: vite unit test
162+
if (code.includes('_useCssVars((_ctx')) {
163+
resCode = code.replaceAll(
164+
'_useCssVars((_ctx) => ({',
165+
`_useCssVars((_ctx) => ({\n ${cssvarsObjectCode}`)
166+
}
167+
168+
// TODO: vite unit test
169+
if (code.includes('_useCssVars(_ctx => ({')) {
170+
resCode = code.replaceAll(
171+
'_useCssVars(_ctx => ({',
172+
`_useCssVars((_ctx) => ({\n ${cssvarsObjectCode}`)
173+
}
174+
175+
// TODO: vite unit webpack
176+
if (code.includes('_useCssVars(function (_ctx) { return ({')) {
177+
resCode = code.replaceAll(
178+
'_useCssVars(function (_ctx) { return ({',
179+
`_useCssVars(function (_ctx) { return ({\n ${cssvarsObjectCode}`)
180+
}
181+
return resCode
182+
}
183+
184+
export function createUseCssVarsCode(
185+
code: string,
186+
vbindVariableList: TMatchVariable,
187+
isHas: boolean,
188+
isScriptSetup: boolean,
189+
) {
190+
const cssvarsObjectCode = createCSSVarsObjCode(vbindVariableList, isScriptSetup)
191+
192+
let resCode = ''
193+
if (isHas) {
194+
resCode = createUCVCHas(code, cssvarsObjectCode)
195+
} else {
196+
if (isScriptSetup) {
197+
// setup script
198+
resCode = createUCVCSetupUnHas(cssvarsObjectCode)
199+
} else {
200+
// composition api 和 option api
201+
resCode = createUCVCOptionUnHas(cssvarsObjectCode)
99202
}
100203
}
101204
return resCode

packages/core/parser/parser-variable.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { parse as babelParse } from '@babel/parser'
2-
import { walk } from 'estree-walker'
2+
import { walk } from 'estree-walker-ts'
33
import { extend, isEmptyObj } from '@unplugin-vue-cssvars/utils'
44
import type { VariableName } from '../types'
55
import type { ParseResult } from '@babel/parser'
@@ -13,7 +13,7 @@ import type {
1313
ReturnStatement,
1414
VariableDeclarator,
1515
} from '@babel/types'
16-
import type { Node } from 'estree-walker'
16+
import type { Node } from 'estree-walker-ts'
1717
/**
1818
* 获取变量
1919
* @param descriptor

packages/core/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,4 @@ export interface InjectStrItem {
7272
content: string
7373
}
7474
export declare type InjectStr = Array<InjectStrItem>
75+
export declare type IFramework = 'rollup' | 'vite' | 'webpack' | 'esbuild' | 'rspack'

play/webpack/src/App.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ const fooColor = appAsd()
1414

1515
<style scoped>
1616
@import '@/assets/css/foo.css';
17+
#foo{
18+
background: v-bind(fooColor);
19+
}
1720
</style>

play/webpack/src/assets/css/foo.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#foo{
22
color: v-bind-m(color);
3-
background: #ffebf8;
43
width: 200px;
54
height: 30px;
65
}

0 commit comments

Comments
 (0)