33 JSX_TSX_REG , NAME ,
44 SUPPORT_FILE_REG ,
55 setTArray ,
6- transformSymbol } from '@unplugin-vue-cssvars/utils'
6+ transformSymbol ,
7+ } from '@unplugin-vue-cssvars/utils'
78import { createFilter } from '@rollup/pluginutils'
89import { parse } from '@vue/compiler-sfc'
910import chalk from 'chalk'
@@ -15,12 +16,14 @@ import { getVariable, matchVariable, parserCompiledSfc } from './parser'
1516import {
1617 injectCSSVars ,
1718 injectCssOnBuild ,
18- injectCssOnServer ,
19+ injectCSSOnServer ,
1920} from './inject'
20- import { viteHMR } from './hmr/hmr'
21+ import { viteHMR , webpackHMR } from './hmr/hmr'
22+ import type { MagicStringBase } from 'magic-string-ast'
2123import type { HmrContext , ResolvedConfig } from 'vite'
2224import type { TMatchVariable } from './parser'
2325import type { Options } from './types'
26+
2427// TODO: webpack hmr
2528const unplugin = createUnplugin < Options > (
2629 ( options : Options = { } , meta ) : any => {
@@ -39,7 +42,41 @@ const unplugin = createUnplugin<Options>(
3942 console . warn ( chalk . yellowBright . bold ( `[${ NAME } ] See: https://github.com/baiwusanyu-c/unplugin-vue-cssvars/blob/master/README.md#option` ) )
4043 }
4144 let isServer = ! ! userOptions . server
42- let isHmring = false
45+ let isHMR = false
46+ const cacheWebpackModule = new Map < string , any > ( )
47+ let cacheCodeWepackHMR = ''
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 ) )
66+
67+ // wepack 热更新统一
68+ // TODO: webpack 热更新时应该打平
69+ if ( ( id . includes ( 'vue&type=style' ) && framework === 'webpack' && isHMR ) ) {
70+ vbindVariableList . set ( id . split ( '?vue' ) [ 0 ] , matchVariable ( vbindVariableListByPath , variableName ) )
71+ }
72+ // vite、rollup、esbuild 打包生效
73+ if ( mgcStr && ! isServer && framework !== 'webpack' && framework !== 'rspack' ) {
74+ mgcStr = injectCssOnBuild ( mgcStr , injectCSSContent , descriptor )
75+ return mgcStr
76+ }
77+ }
78+ }
79+
4380 return [
4481 {
4582 name : NAME ,
@@ -56,22 +93,11 @@ const unplugin = createUnplugin<Options>(
5693 // webpack dev 和 build 都回进入这里
5794 if ( transId . endsWith ( '.vue' )
5895 || ( transId . includes ( 'vue&type=style' ) && framework === 'webpack' ) ) {
59- const { descriptor } = parse ( code )
60- const lang = descriptor ?. script ?. lang ?? 'js'
61- // ⭐TODO: 只支持 .vue ? jsx, tsx, js, ts ?
62- if ( ! JSX_TSX_REG . test ( `.${ lang } ` ) ) {
63- isScriptSetup = ! ! descriptor . scriptSetup
64- const {
65- vbindVariableListByPath,
66- injectCSSContent,
67- } = getVBindVariableListByPath ( descriptor , transId , CSSFileModuleMap , isServer , userOptions . alias )
68- const variableName = getVariable ( descriptor )
69- vbindVariableList . set ( transId , matchVariable ( vbindVariableListByPath , variableName ) )
96+ cacheCodeWepackHMR = code
7097
71- // vite、rollup、esbuild 打包生效
72- if ( ! isServer && framework !== 'webpack' && framework !== 'rspack' )
73- mgcStr = injectCssOnBuild ( mgcStr , injectCSSContent , descriptor )
74- }
98+ const res = handleVBindVariable ( code , transId , mgcStr )
99+ if ( res )
100+ mgcStr = res
75101 }
76102
77103 return {
@@ -98,17 +124,75 @@ const unplugin = createUnplugin<Options>(
98124 } ,
99125 handleHotUpdate ( hmr : HmrContext ) {
100126 if ( SUPPORT_FILE_REG . test ( hmr . file ) ) {
101- isHmring = true
127+ isHMR = true
102128 viteHMR (
103129 CSSFileModuleMap ,
104130 userOptions ,
105- hmr . file ,
131+ transformSymbol ( hmr . file ) ,
106132 hmr . server ,
107133 )
108134 }
109135 } ,
110136 } ,
137+ webpack ( compiler ) {
138+ // mark webpack hmr
139+ compiler . hooks . watchRun . tap ( `${ NAME } :webpack:watchRun` , ( compilation ) => {
140+ let file = ''
141+ if ( compilation . modifiedFiles ) {
142+ file = transformSymbol ( setTArray ( compilation . modifiedFiles ) [ 0 ] as string )
143+ if ( SUPPORT_FILE_REG . test ( file ) ) {
144+ isHMR = true
145+ webpackHMR (
146+ CSSFileModuleMap ,
147+ userOptions ,
148+ file ,
149+ )
150+ }
151+ }
152+ compiler . hooks . compilation . tap ( `${ NAME } :webpack:watchRun:compilation` , ( compilation ) => {
153+ compilation . hooks . finishModules . tap ( `${ NAME } :webpack:watchRun:finishModules` , ( modules ) => {
154+ // TODO:
155+ const keyPath = 'D:/project-github/unplugin-vue-cssvars/play/webpack/src/App.vue'
156+ // rebuild module to hmr
157+ if ( isHMR ) {
158+ const cwm = cacheWebpackModule . get ( keyPath )
159+ console . log ( cwm . size )
160+ for ( const mv of cwm ) {
161+ compilation . rebuildModule ( mv , ( e ) => {
162+ if ( e ) {
163+ console . log ( e )
164+ return
165+ }
166+ console . log ( 'hot updated' )
167+ } )
168+ }
169+ }
170+ } )
171+ } )
172+ } )
173+
174+ compiler . hooks . compilation . tap ( `${ NAME } :webpack:compilation` , ( compilation ) => {
175+ compilation . hooks . finishModules . tap ( `${ NAME } :webpack:finishModules` , ( modules ) => {
176+ // cache module
177+ for ( const value of modules ) {
178+ const resource = transformSymbol ( value . resource )
179+ if ( resource . includes ( 'vue&type=script' ) ) {
180+ const transId = resource . split ( '?vue&type=script' ) [ 0 ]
181+ if ( vbindVariableList . get ( transId ) ) {
182+ let ca = cacheWebpackModule . get ( transId )
183+ if ( ! ca ) {
184+ ca = new Set ( )
185+ }
186+ ca . add ( value )
187+ cacheWebpackModule . set ( transId , ca )
188+ }
189+ }
190+ }
191+ } )
192+ } )
193+ } ,
111194 } ,
195+
112196 {
113197 name : `${ NAME } :inject` ,
114198 enforce : 'post' ,
@@ -125,7 +209,7 @@ const unplugin = createUnplugin<Options>(
125209 const injectRes = injectCSSVars ( vbindVariableList . get ( idKey ) , isScriptSetup , parseRes , mgcStr )
126210 mgcStr = injectRes . mgcStr
127211 injectRes . vbindVariableList && vbindVariableList . set ( transId , injectRes . vbindVariableList )
128- isHmring = false
212+ isHMR = false
129213 }
130214
131215 // transform in dev
@@ -134,13 +218,15 @@ const unplugin = createUnplugin<Options>(
134218 if ( framework === 'vite'
135219 || framework === 'rollup'
136220 || framework === 'esbuild' ) {
221+ // inject cssvars to sfc code
137222 if ( transId . endsWith ( '.vue' ) )
138223 injectCSSVarsFn ( transId )
224+ // inject css code
139225 if ( transId . includes ( 'vue&type=style' ) ) {
140- mgcStr = injectCssOnServer (
226+ mgcStr = injectCSSOnServer (
141227 mgcStr ,
142228 vbindVariableList . get ( transId . split ( '?vue' ) [ 0 ] ) ,
143- isHmring ,
229+ isHMR ,
144230 )
145231 }
146232 }
@@ -152,18 +238,19 @@ const unplugin = createUnplugin<Options>(
152238 transId = transId . split ( '?vue&type=script' ) [ 0 ]
153239 injectCSSVarsFn ( transId )
154240 }
155- /*mgcStr = mgcStr.replaceAll(
156- 'vue&type=template&id=7ba5bd90&scoped=true&ts=true", () => {',
157- 'vue&type=template&id=7ba5bd90&scoped=true&ts=true", () => { console.log(render);')*/
241+
158242 const cssFMM = CSSFileModuleMap . get ( transId )
159243 if ( cssFMM && cssFMM . sfcPath && cssFMM . sfcPath . size > 0 ) {
160244 const sfcPathIdList = setTArray ( cssFMM . sfcPath )
161245 sfcPathIdList . forEach ( ( v ) => {
162- mgcStr = injectCssOnServer ( mgcStr , vbindVariableList . get ( v ) , isHmring )
246+ mgcStr = injectCSSOnServer (
247+ mgcStr ,
248+ vbindVariableList . get ( v ) ,
249+ isHMR )
163250 } )
164251 }
165252 }
166- // console.log(mgcStr.toString())
253+ // console.log(mgcStr.toString())
167254 return {
168255 code : mgcStr . toString ( ) ,
169256 get map ( ) {
0 commit comments