Skip to content

Commit 11065c3

Browse files
committed
chore: refactor runtime code
1 parent 2bd3008 commit 11065c3

File tree

9 files changed

+307
-198
lines changed

9 files changed

+307
-198
lines changed

packages/core/index.ts

Lines changed: 50 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,48 @@
11
import { createUnplugin } from 'unplugin'
22
import {
3-
JSX_TSX_REG, NAME,
4-
SUPPORT_FILE_REG,
3+
NAME,
54
log,
6-
setTArray,
75
transformSymbol,
86
} from '@unplugin-vue-cssvars/utils'
97
import { createFilter } from '@rollup/pluginutils'
10-
import { parse } from '@vue/compiler-sfc'
11-
import chalk from 'chalk'
128
import MagicString from 'magic-string'
139
import { preProcessCSS } from './runtime/pre-process-css'
14-
import { getVBindVariableListByPath } from './runtime/process-css'
1510
import { initOption } from './option'
16-
import { getVariable, matchVariable, parserCompiledSfc } from './parser'
1711
import {
18-
injectCSSOnServer,
19-
injectCSSVars,
20-
injectCssOnBuild,
21-
} from './inject'
22-
import { viteHMR, webpackHMR } from './hmr/hmr'
23-
import type { MagicStringBase } from 'magic-string-ast'
24-
import type { HmrContext, ResolvedConfig } from 'vite'
12+
transformPostVite,
13+
transformPreVite,
14+
vitePlugin,
15+
} from './runtime/vite'
16+
import {
17+
transformPostWebpack,
18+
transformPreWebpack,
19+
webpackPlugin,
20+
} from './runtime/webpack'
2521
import type { TMatchVariable } from './parser'
26-
import type { Options } from './types'
27-
// TODO refactor
22+
import type { IVueCSSVarsCtx, Options } from './types'
23+
2824
const unplugin = createUnplugin<Options>(
2925
(options: Options = {}, meta): any => {
30-
const framework = meta.framework
3126
const userOptions = initOption(options)
3227
const filter = createFilter(
3328
userOptions.include,
3429
userOptions.exclude,
3530
)
36-
// 预处理 css 文件
37-
const CSSFileModuleMap = preProcessCSS(userOptions, userOptions.alias)
38-
const vbindVariableList = new Map<string, TMatchVariable>()
39-
let isScriptSetup = false
31+
4032
if (userOptions.server === undefined) {
4133
log('warning', 'The server of option is not set, you need to specify whether you are using the development server or building the project')
42-
log('warning', 'The server of option is not set, you need to specify whether you are using the development server or building the project')
43-
console.warn(chalk.yellowBright.bold(`[${NAME}] The server of option is not set, you need to specify whether you are using the development server or building the project`))
44-
console.warn(chalk.yellowBright.bold(`[${NAME}] See: https://github.com/baiwusanyu-c/unplugin-vue-cssvars/blob/master/README.md#option`))
34+
log('warning', 'See: https://github.com/baiwusanyu-c/unplugin-vue-cssvars/blob/master/README.md#option')
4535
}
46-
let isServer = !!userOptions.server
47-
let isHMR = false
48-
49-
function handleVBindVariable(
50-
code: string,
51-
id: string,
52-
mgcStr?: MagicStringBase,
53-
) {
54-
const { descriptor } = parse(code)
55-
const lang = descriptor?.script?.lang ?? 'js'
56-
// ⭐TODO: 只支持 .vue ? jsx, tsx, js, ts ?
57-
if (!JSX_TSX_REG.test(`.${lang}`)) {
58-
isScriptSetup = !!descriptor.scriptSetup
59-
const {
60-
vbindVariableListByPath,
61-
injectCSSContent,
62-
} = getVBindVariableListByPath(descriptor, id, CSSFileModuleMap, isServer, userOptions.alias)
63-
64-
const variableName = getVariable(descriptor)
65-
vbindVariableList.set(id, matchVariable(vbindVariableListByPath, variableName))
6636

67-
// vite、rollup、esbuild 打包生效
68-
if (mgcStr && !isServer && framework !== 'webpack' && framework !== 'rspack') {
69-
mgcStr = injectCssOnBuild(mgcStr, injectCSSContent, descriptor)
70-
return mgcStr
71-
}
72-
}
73-
}
37+
const context = {
38+
CSSFileModuleMap: preProcessCSS(userOptions, userOptions.alias),
39+
vbindVariableList: new Map<string, TMatchVariable>(),
40+
isServer: !!userOptions.server,
41+
isHMR: false,
42+
userOptions,
43+
framework: meta.framework,
44+
isScriptSetup: false,
45+
} as IVueCSSVarsCtx
7446

7547
return [
7648
{
@@ -80,25 +52,23 @@ const unplugin = createUnplugin<Options>(
8052
return filter(id)
8153
},
8254
async transform(code: string, id: string) {
83-
let transId = transformSymbol(id)
55+
const transId = transformSymbol(id)
8456
let mgcStr = new MagicString(code)
8557
try {
86-
// ⭐TODO: 只支持 .vue ? jsx, tsx, js, ts ?
87-
// webpack 时 使用 id.includes('?vue&type=style') 判断
88-
// webpack dev 和 build 都回进入这里
89-
90-
if (transId.endsWith('.vue')) {
91-
const res = handleVBindVariable(code, transId, mgcStr)
92-
if (res)
93-
mgcStr = res
94-
}
95-
96-
if ((transId.includes('?vue&type=style') || transId.includes('?vue&type=script'))
97-
&& isHMR && framework === 'webpack') {
98-
transId = transId.split('?vue')[0]
99-
const res = handleVBindVariable(code, transId, mgcStr)
100-
if (res)
101-
mgcStr = res
58+
if (context.framework !== 'webpack'
59+
&& context.framework !== 'rspack') {
60+
mgcStr = transformPreVite(
61+
transId,
62+
code,
63+
mgcStr,
64+
context,
65+
)
66+
} else {
67+
transformPreWebpack(
68+
transId,
69+
code,
70+
context,
71+
)
10272
}
10373

10474
return {
@@ -115,89 +85,11 @@ const unplugin = createUnplugin<Options>(
11585
this.error(`[${NAME}] ${err}`)
11686
}
11787
},
118-
vite: {
119-
// Vite plugin
120-
configResolved(config: ResolvedConfig) {
121-
if (userOptions.server !== undefined)
122-
isServer = userOptions.server
123-
else
124-
isServer = config.command === 'serve'
125-
},
126-
handleHotUpdate(hmr: HmrContext) {
127-
if (SUPPORT_FILE_REG.test(hmr.file)) {
128-
isHMR = true
129-
viteHMR(
130-
CSSFileModuleMap,
131-
userOptions,
132-
transformSymbol(hmr.file),
133-
hmr.server,
134-
)
135-
}
136-
},
137-
},
138-
139-
// TODO unit test
88+
// handle hmr with vite
89+
vite: vitePlugin(context),
90+
// handle hmr with webpack
14091
webpack(compiler) {
141-
// mark webpack hmr
142-
let modifiedFile = ''
143-
compiler.hooks.watchRun.tapAsync(NAME, (compilation1, watchRunCallBack) => {
144-
if (compilation1.modifiedFiles) {
145-
modifiedFile = transformSymbol(setTArray(compilation1.modifiedFiles)[0] as string)
146-
if (SUPPORT_FILE_REG.test(modifiedFile)) {
147-
isHMR = true
148-
webpackHMR(
149-
CSSFileModuleMap,
150-
userOptions,
151-
modifiedFile,
152-
)
153-
}
154-
}
155-
watchRunCallBack()
156-
})
157-
158-
compiler.hooks.compilation.tap(NAME, (compilation) => {
159-
compilation.hooks.finishModules.tapAsync(NAME, async(modules, callback) => {
160-
if (isHMR) {
161-
const needRebuildModules = new Map<string, any>()
162-
for (const value of modules) {
163-
const resource = transformSymbol(value.resource)
164-
if (resource.includes('?vue&type=script')) {
165-
const sfcPathKey = resource.split('?vue')[0]
166-
if (CSSFileModuleMap.get(modifiedFile).sfcPath.has(sfcPathKey))
167-
needRebuildModules.set(sfcPathKey, value)
168-
}
169-
}
170-
if (needRebuildModules.size > 0) {
171-
const promises = []
172-
for (const [key] of needRebuildModules) {
173-
// 创建一个 Promise 对象,表示异步操作
174-
const promise = new Promise((resolve, reject) => {
175-
compilation.rebuildModule(needRebuildModules.get(key), (e) => {
176-
if (e)
177-
reject(e)
178-
else
179-
resolve()
180-
})
181-
})
182-
promises.push(promise)
183-
}
184-
Promise.all(promises)
185-
.then(() => {
186-
callback()
187-
// hmr end
188-
isHMR = false
189-
})
190-
.catch((e) => {
191-
log('error', e)
192-
})
193-
} else {
194-
callback()
195-
}
196-
} else {
197-
callback()
198-
}
199-
})
200-
})
92+
webpackPlugin(context, compiler)
20193
},
20294
},
20395

@@ -208,57 +100,21 @@ const unplugin = createUnplugin<Options>(
208100
return filter(id)
209101
},
210102
async transform(code: string, id: string) {
211-
console.log(id)
212-
let transId = transformSymbol(id)
103+
const transId = transformSymbol(id)
213104
let mgcStr = new MagicString(code)
214-
// ⭐TODO: 只支持 .vue ? jsx, tsx, js, ts ?
215105
try {
216-
function injectCSSVarsFn(idKey: string) {
217-
const parseRes = parserCompiledSfc(code)
218-
const injectRes = injectCSSVars(vbindVariableList.get(idKey), isScriptSetup, parseRes, mgcStr)
219-
mgcStr = injectRes.mgcStr
220-
injectRes.vbindVariableList && vbindVariableList.set(transId, injectRes.vbindVariableList)
221-
// TODO vite hmr close ? isHMR -> false
222-
}
223-
224106
// transform in dev
225107
// 'vite' | 'rollup' | 'esbuild'
226-
if (isServer) {
227-
if (framework === 'vite'
228-
|| framework === 'rollup'
229-
|| framework === 'esbuild') {
230-
// inject cssvars to sfc code
231-
if (transId.endsWith('.vue'))
232-
injectCSSVarsFn(transId)
233-
// inject css code
234-
if (transId.includes('?vue&type=style')) {
235-
mgcStr = injectCSSOnServer(
236-
mgcStr,
237-
vbindVariableList.get(transId.split('?vue')[0]),
238-
isHMR,
239-
)
240-
}
241-
}
108+
if (context.isServer) {
109+
if (context.framework === 'vite'
110+
|| context.framework === 'rollup'
111+
|| context.framework === 'esbuild')
112+
mgcStr = transformPostVite(transId, code, mgcStr, context)
242113
}
243114

244115
// webpack dev 和 build 都回进入这里
245-
if (framework === 'webpack') {
246-
if (transId.includes('?vue&type=script')) {
247-
transId = transId.split('?vue')[0]
248-
injectCSSVarsFn(transId)
249-
}
250-
251-
const cssFMM = CSSFileModuleMap.get(transId)
252-
if (cssFMM && cssFMM.sfcPath && cssFMM.sfcPath.size > 0) {
253-
const sfcPathIdList = setTArray(cssFMM.sfcPath)
254-
sfcPathIdList.forEach((v) => {
255-
mgcStr = injectCSSOnServer(
256-
mgcStr,
257-
vbindVariableList.get(v),
258-
isHMR)
259-
})
260-
}
261-
}
116+
if (context.framework === 'webpack')
117+
mgcStr = transformPostWebpack(transId, code, mgcStr, context)
262118

263119
return {
264120
code: mgcStr.toString(),

packages/core/inject/inject-css.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ export function injectCSSOnServer(
2323

2424
export function injectCssOnBuild(
2525
mgcStr: MagicStringBase,
26-
injectCSSContent: TInjectCSSContent,
27-
descriptor: SFCDescriptor) {
26+
injectCSSContent: TInjectCSSContent | null,
27+
descriptor: SFCDescriptor | null) {
28+
if (!injectCSSContent && !descriptor) return mgcStr
2829
const cssContent = [...injectCSSContent]
2930
let resCode = ''
3031

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { parserCompiledSfc } from '../parser'
2+
import { injectCSSVars } from '../inject'
3+
import type { MagicStringBase } from 'magic-string-ast'
4+
import type { IVueCSSVarsCtx } from '../types'
5+
6+
export function handleInjectCss(
7+
id: string,
8+
code: string,
9+
mgcStr: MagicStringBase,
10+
ctx: IVueCSSVarsCtx,
11+
) {
12+
const parseRes = parserCompiledSfc(code)
13+
const injectRes = injectCSSVars(
14+
ctx.vbindVariableList.get(id),
15+
ctx.isScriptSetup,
16+
parseRes,
17+
mgcStr,
18+
)
19+
mgcStr = injectRes.mgcStr
20+
injectRes.vbindVariableList && ctx.vbindVariableList.set(id, injectRes.vbindVariableList)
21+
// TODO vite hmr close ? isHMR -> false
22+
return mgcStr
23+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { parse } from '@vue/compiler-sfc'
2+
import { JSX_TSX_REG } from '@unplugin-vue-cssvars/utils'
3+
import { getVariable, matchVariable } from '../parser'
4+
import { getVBindVariableListByPath } from './process-css'
5+
import type { IVueCSSVarsCtx } from '../types'
6+
7+
export function handleVBindVariable(
8+
code: string,
9+
id: string,
10+
ctx: IVueCSSVarsCtx,
11+
) {
12+
const { descriptor } = parse(code)
13+
const lang = descriptor?.script?.lang ?? 'js'
14+
// ⭐TODO: 只支持 .vue ? jsx, tsx, js, ts ?
15+
if (!JSX_TSX_REG.test(`.${lang}`)) {
16+
ctx.isScriptSetup = !!descriptor.scriptSetup
17+
const {
18+
vbindVariableListByPath,
19+
injectCSSContent,
20+
} = getVBindVariableListByPath(
21+
descriptor,
22+
id,
23+
ctx.CSSFileModuleMap,
24+
ctx.isServer,
25+
ctx.userOptions.alias,
26+
)
27+
28+
const variableName = getVariable(descriptor)
29+
ctx.vbindVariableList.set(id, matchVariable(vbindVariableListByPath, variableName))
30+
return {
31+
descriptor,
32+
injectCSSContent,
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)