Skip to content

Commit 7e57559

Browse files
authored
feat: jsx support in sfc (#63)
* chore: temp commit * chore: temp commit * chore: updated todo * chore: support jsx with vite on dev * feat: jsx support in sfc
1 parent 7a23064 commit 7e57559

24 files changed

+2021
-596
lines changed

package.json

+24-24
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": false,
55
"type": "module",
66
"version": "1.3.3",
7-
"packageManager": "pnpm@6.32.4",
7+
"packageManager": "pnpm@6.35.1",
88
"keywords": [
99
"cssvars",
1010
"sass",
@@ -70,7 +70,8 @@
7070
"prepare": "npx simple-git-hooks",
7171
"test": "vitest",
7272
"test:update": "vitest -u",
73-
"test:coverage": "vitest --coverage"
73+
"test:coverage": "vitest --coverage",
74+
"update:deps": "npx taze -w && pnpm run init"
7475
},
7576
"peerDependencies": {
7677
"baiwusanyu-utils": "^1.0.12",
@@ -84,62 +85,61 @@
8485
"vue": "^3.2.47"
8586
},
8687
"dependencies": {
87-
"baiwusanyu-utils": "^1.0.8",
88+
"baiwusanyu-utils": "^1.0.12",
8889
"chalk": "^4.1.2",
8990
"estree-walker-ts": "^1.0.0",
9091
"fast-glob": "^3.2.12",
9192
"fs-extra": "^11.1.1",
9293
"hash-sum": "^2.0.0",
9394
"magic-string": "^0.30.0",
9495
"unplugin": "^1.3.1",
95-
"vue": "^3.2.47"
96+
"vue": "^3.3.4"
9697
},
9798
"devDependencies": {
98-
"@babel/parser": "^7.20.15",
99-
"@babel/types": "^7.20.7",
99+
"@babel/parser": "^7.21.9",
100+
"@babel/types": "^7.21.5",
100101
"@baiwusanyu/eslint-config": "^1.0.12",
101102
"@rollup/pluginutils": "^5.0.2",
102103
"@types/css-tree": "^2.3.1",
103-
"@types/debug": "^4.1.7",
104-
"@types/estree": "^1.0.0",
104+
"@types/debug": "^4.1.8",
105+
"@types/estree": "^1.0.1",
105106
"@types/fs-extra": "^11.0.1",
106107
"@types/gulp": "^4.0.10",
107108
"@types/hash-sum": "^1.0.0",
108109
"@types/less": "^3.0.3",
109-
"@types/node": "^20.1.2",
110+
"@types/node": "^20.2.3",
110111
"@types/stylus": "^0.48.38",
111112
"@unplugin-vue-cssvars/build": "workspace:*",
112113
"@unplugin-vue-cssvars/core": "workspace:*",
113114
"@unplugin-vue-cssvars/entry": "workspace:*",
114115
"@unplugin-vue-cssvars/utils": "workspace:*",
115-
"@vitejs/plugin-vue": "^4.1.0",
116+
"@vitejs/plugin-vue": "^4.2.3",
116117
"@vitejs/plugin-vue-jsx": "^3.0.1",
117-
"@vitest/coverage-c8": "^0.31.0",
118-
"@vitest/ui": "^0.31.0",
119-
"@vue/compiler-sfc": "^3.2.47",
118+
"@vitest/coverage-c8": "^0.31.1",
119+
"@vitest/ui": "^0.31.1",
120+
"@vue/compiler-sfc": "^3.3.4",
120121
"bumpp": "^9.1.0",
121122
"cross-env": "^7.0.3",
122-
"debug": "^4.3.4",
123-
"eslint": "^8.38.0",
123+
"eslint": "^8.41.0",
124124
"esno": "^0.16.3",
125125
"git-ensure": "^0.1.0",
126126
"gulp": "^4.0.2",
127127
"jsdom": "^22.0.0",
128128
"less": "^4.1.3",
129-
"lint-staged": "^13.1.1",
129+
"lint-staged": "^13.2.2",
130130
"magic-string-ast": "^0.1.2",
131131
"npm-run-all": "^4.1.5",
132-
"rimraf": "^5.0.0",
133-
"rollup": "^3.19.1",
134-
"sass": "^1.60.0",
132+
"rimraf": "^5.0.1",
133+
"rollup": "^3.23.0",
134+
"sass": "^1.62.1",
135135
"simple-git-hooks": "^2.8.1",
136136
"stylus": "^0.59.0",
137-
"sucrase": "^3.21.0",
138-
"tsup": "^6.2.3",
137+
"sucrase": "^3.32.0",
138+
"tsup": "^6.7.0",
139139
"typescript": "5.0.4",
140-
"vite": "^4.3.0",
141-
"vitest": "^0.31.0",
142-
"webpack": "^5.80.0"
140+
"vite": "^4.3.8",
141+
"vitest": "^0.31.1",
142+
"webpack": "^5.83.1"
143143
},
144144
"simple-git-hooks": {
145145
"pre-commit": "pnpm lint-staged",

packages/core/hmr/hmr.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ export function updatedCSSModules(
3737
CSSFileModuleMap: ICSSFileMap,
3838
userOptions: Options,
3939
file: string) {
40-
const updatedCSSMS = preProcessCSS(userOptions, userOptions.alias, [file]).get(file)
40+
const updatedCSSMS = preProcessCSS(userOptions, userOptions.alias, [file]).get(file)!
41+
const sfcPath = CSSFileModuleMap.get(file)!.sfcPath || new Set<string>()
4142
const res = {
4243
...updatedCSSMS,
43-
sfcPath: CSSFileModuleMap.get(file).sfcPath,
44+
sfcPath,
4445
}
4546
CSSFileModuleMap.set(file, res!)
4647
}

packages/core/index.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import MagicString from 'magic-string'
77
import { preProcessCSS } from './runtime/pre-process-css'
88
import { initOption } from './option'
99
import {
10-
transformPostVite,
10+
transformPostViteDev,
1111
transformPreVite,
1212
vitePlugin,
1313
} from './runtime/vite'
@@ -54,15 +54,18 @@ const unplugin = createUnplugin<Options>(
5454
const transId = normalizePath(id)
5555
let mgcStr = new MagicString(code)
5656
try {
57-
if (context.framework !== 'webpack'
58-
&& context.framework !== 'rspack') {
57+
if (context.framework === 'vite'
58+
|| context.framework === 'rollup'
59+
|| context.framework === 'esbuild') {
5960
mgcStr = transformPreVite(
6061
transId,
6162
code,
6263
mgcStr,
6364
context,
6465
)
65-
} else {
66+
}
67+
68+
if (context.framework === 'webpack') {
6669
transformPreWebpack(
6770
transId,
6871
code,
@@ -84,7 +87,7 @@ const unplugin = createUnplugin<Options>(
8487
this.error(`[${NAME}] ${err}`)
8588
}
8689
},
87-
// handle hmr with vite
90+
// handle hmr with vite and command
8891
vite: vitePlugin(context),
8992
// handle hmr with webpack
9093
webpack(compiler: Compiler) {
@@ -103,15 +106,15 @@ const unplugin = createUnplugin<Options>(
103106
let mgcStr = new MagicString(code)
104107
try {
105108
// transform in dev
106-
// 'vite' | 'rollup' | 'esbuild'
109+
// dev only
107110
if (context.isServer) {
108111
if (context.framework === 'vite'
109112
|| context.framework === 'rollup'
110113
|| context.framework === 'esbuild')
111-
mgcStr = transformPostVite(transId, code, mgcStr, context)
114+
mgcStr = transformPostViteDev(transId, code, mgcStr, context)
112115
}
113116

114-
// webpack dev 和 build 都回进入这里
117+
// webpack dev 和 build 都会执行
115118
if (context.framework === 'webpack')
116119
mgcStr = transformPostWebpack(transId, code, mgcStr, context)
117120

packages/core/inject/inject-css.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ export function injectCssOnBuild(
2626
injectCSSContent: TInjectCSSContent | null,
2727
descriptor: SFCDescriptor | null) {
2828
if (!injectCSSContent && !descriptor) return mgcStr
29-
const cssContent = [...injectCSSContent]
29+
const cssContent = [...injectCSSContent!]
3030
let resCode = ''
3131

32-
descriptor.styles && descriptor.styles.forEach((value, index) => {
32+
descriptor!.styles && descriptor!.styles.forEach((value, index) => {
3333
let injectCssCode = ''
3434
cssContent.forEach((value) => {
3535
if (value.styleTagIndex === index)

packages/core/parser/__test__/parser-compiled-sfc.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
parseSetupBody,
88
parseUseCSSVars,
99
parserCompiledSfc,
10-
reSetVar,
10+
resetVar,
1111
setVar,
1212
} from '../parser-compiled-sfc'
1313
import type { CallExpression, Identifier, ImportSpecifier, ObjectExpression } from '@babel/types'
@@ -16,7 +16,7 @@ describe('parseSetupBody', () => {
1616

1717
beforeEach(() => {
1818
node = {}
19-
reSetVar()
19+
resetVar()
2020
})
2121

2222
test('should set isSetupEnter to true when node is an Identifier with name "setup"', () => {
@@ -62,7 +62,7 @@ describe('parseSetupBody', () => {
6262
describe('parseHasCSSVars', () => {
6363
beforeEach(() => {
6464
// reset the state of `hasCSSVars` to `false` after each test
65-
reSetVar()
65+
resetVar()
6666
})
6767

6868
test('should set `hasCSSVars` to `true` if node type is Identifier with name "useCssVars" and has a parent ImportSpecifier', () => {
@@ -106,7 +106,7 @@ describe('parseUseCSSVars function', () => {
106106
let parent: Node & { scopeIds?: Set<string> } & Identifier & CallExpression & ObjectExpression
107107

108108
beforeEach(() => {
109-
reSetVar()
109+
resetVar()
110110
node = {} as Node & { scopeIds?: Set<string> } & Identifier & CallExpression & ObjectExpression
111111
parent = {} as Node & { scopeIds?: Set<string> } & Identifier & CallExpression & ObjectExpression
112112
})

packages/core/parser/__test__/parser-variable.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ describe('get variable name', () => {
7373
const mockContent = 'const color = "red"'
7474
const ast = babelParse(mockContent, {
7575
sourceType: 'module',
76-
plugins: ['typescript'],
76+
plugins: ['typescript', 'jsx'],
7777
})
7878
const res = getVariableNameBySetup('', ast)
7979
expect(res).toMatchObject({

packages/core/parser/parser-compiled-sfc.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,11 @@ export function parseUseCSSVars(
5757
}
5858

5959
export function parserCompiledSfc(code: string) {
60-
reSetVar()
60+
resetVar()
6161
const ast = babelParse(code, {
6262
sourceType: 'module',
63-
plugins: ['typescript'],
63+
plugins: ['typescript', 'jsx'],
6464
});
65-
6665
(walk as any)(ast, {
6766
enter(
6867
node: Node & { scopeIds?: Set<string> },
@@ -79,7 +78,7 @@ export function parserCompiledSfc(code: string) {
7978
} as IParseSFCRes
8079
}
8180

82-
export function reSetVar() {
81+
export function resetVar() {
8382
isSetupEnter = false
8483
setupBodyNode = {} as BlockStatement
8584
isUseCSSVarsEnter = false

packages/core/parser/parser-variable.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export function getVariableNameBySetup(content: string, contextAst?: ParseResult
4848

4949
const ast = contextAst || babelParse(content, {
5050
sourceType: 'module',
51-
plugins: ['typescript'],
51+
plugins: ['typescript', 'jsx'],
5252
});
5353
(walk as any)(ast, {
5454
enter(node: Node & { scopeIds?: Set<string> }, parent: Node | undefined) {
@@ -92,7 +92,7 @@ export function getVariableNameByScript(content: string, variableName: VariableN
9292

9393
const ast = babelParse(content, {
9494
sourceType: 'module',
95-
plugins: ['typescript'],
95+
plugins: ['typescript', 'jsx'],
9696
});
9797
(walk as any)(ast, {
9898
enter(
+26-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { parse } from '@vue/compiler-sfc'
2-
import { JSX_TSX_REG } from '@unplugin-vue-cssvars/utils'
32
import { getVariable, matchVariable } from '../parser'
43
import { getVBindVariableListByPath } from './process-css'
54
import type { IVueCSSVarsCtx } from '../types'
@@ -10,32 +9,34 @@ export function handleVBindVariable(
109
ctx: IVueCSSVarsCtx,
1110
) {
1211
const { descriptor } = parse(code)
13-
let lang = 'js'
14-
if (descriptor?.scriptSetup?.lang)
15-
lang = descriptor.scriptSetup.lang
12+
// let lang = 'js'
13+
// if (descriptor?.scriptSetup?.lang)
14+
// lang = descriptor.scriptSetup.lang
1615

17-
if (descriptor?.script?.lang)
18-
lang = descriptor.script.lang
16+
// if (descriptor?.script?.lang)
17+
// lang = descriptor.script.lang
1918

2019
// ⭐TODO: 只支持 .vue ? jsx, tsx, js, ts ?
21-
if (!JSX_TSX_REG.test(`.${lang}`)) {
22-
ctx.isScriptSetup = !!descriptor.scriptSetup
23-
const {
24-
vbindVariableListByPath,
25-
injectCSSContent,
26-
} = getVBindVariableListByPath(
27-
descriptor,
28-
id,
29-
ctx.CSSFileModuleMap,
30-
ctx.isServer,
31-
ctx.userOptions.alias,
32-
)
33-
34-
const variableName = getVariable(descriptor)
35-
ctx.vbindVariableList.set(id, matchVariable(vbindVariableListByPath, variableName))
36-
return {
37-
descriptor,
38-
injectCSSContent,
39-
}
20+
// if (!JSX_TSX_REG.test(`.${lang}`)) {
21+
ctx.isScriptSetup = !!descriptor.scriptSetup
22+
// 分析 @import 的链路
23+
const {
24+
vbindVariableListByPath,
25+
injectCSSContent,
26+
} = getVBindVariableListByPath(
27+
descriptor,
28+
id,
29+
ctx.CSSFileModuleMap,
30+
ctx.isServer,
31+
ctx.userOptions.alias,
32+
)
33+
// 分析 sfc 内容中的变量
34+
const variableName = getVariable(descriptor)
35+
// 进行匹配得到最终的 cssvars 内容
36+
ctx.vbindVariableList.set(id, matchVariable(vbindVariableListByPath, variableName))
37+
return {
38+
descriptor,
39+
injectCSSContent,
4040
}
41+
// }
4142
}

0 commit comments

Comments
 (0)