@@ -9,6 +9,7 @@ import type {
99} from 'vue/compiler-sfc'
1010import type * as _compiler from 'vue/compiler-sfc'
1111import { computed , shallowRef } from 'vue'
12+ import { exactRegex } from '@rolldown/pluginutils'
1213import { version } from '../package.json'
1314import { resolveCompiler } from './compiler'
1415import { parseVueRequest } from './utils/query'
@@ -162,7 +163,7 @@ export interface Options {
162163 customElement ?: boolean | string | RegExp | ( string | RegExp ) [ ]
163164}
164165
165- export interface ResolvedOptions extends Options {
166+ export interface ResolvedOptions extends Omit < Options , 'include' | 'exclude' > {
166167 compiler : typeof _compiler
167168 root : string
168169 sourceMap : boolean
@@ -174,6 +175,14 @@ export interface ResolvedOptions extends Options {
174175export interface Api {
175176 get options ( ) : ResolvedOptions
176177 set options ( value : ResolvedOptions )
178+
179+ get include ( ) : string | RegExp | ( string | RegExp ) [ ] | undefined
180+ /** include cannot be updated after `options` hook is called */
181+ set include ( value : string | RegExp | ( string | RegExp ) [ ] | undefined )
182+ get exclude ( ) : string | RegExp | ( string | RegExp ) [ ] | undefined
183+ /** exclude cannot be updated after `options` hook is called */
184+ set exclude ( value : string | RegExp | ( string | RegExp ) [ ] | undefined )
185+
177186 version : string
178187}
179188
@@ -183,17 +192,19 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
183192 const options = shallowRef < ResolvedOptions > ( {
184193 isProduction : process . env . NODE_ENV === 'production' ,
185194 compiler : null as any , // to be set in buildStart
186- include : / \. v u e $ / ,
187195 customElement : / \. c e \. v u e $ / ,
188196 ...rawOptions ,
189197 root : process . cwd ( ) ,
190198 sourceMap : true ,
191199 cssDevSourcemap : false ,
192200 } )
193-
194- const filter = computed ( ( ) =>
195- createFilter ( options . value . include , options . value . exclude ) ,
201+ const include = shallowRef < Exclude < Options [ 'include' ] , undefined > > (
202+ rawOptions . include ?? / \. v u e $ / ,
196203 )
204+ const exclude = shallowRef < Options [ 'exclude' ] > ( rawOptions . exclude )
205+ let optionsHookIsCalled = false
206+
207+ const filter = computed ( ( ) => createFilter ( include . value , exclude . value ) )
197208 const customElementFilter = computed ( ( ) => {
198209 const customElement =
199210 options . value . features ?. customElement || options . value . customElement
@@ -204,7 +215,7 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
204215
205216 let transformCachedModule = false
206217
207- return {
218+ const plugin : Plugin < Api > = {
208219 name : 'vite:vue' ,
209220
210221 api : {
@@ -214,6 +225,28 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
214225 set options ( value ) {
215226 options . value = value
216227 } ,
228+ get include ( ) {
229+ return include . value
230+ } ,
231+ set include ( value ) {
232+ if ( optionsHookIsCalled ) {
233+ throw new Error (
234+ 'include cannot be updated after `options` hook is called' ,
235+ )
236+ }
237+ include . value = value
238+ } ,
239+ get exclude ( ) {
240+ return exclude . value
241+ } ,
242+ set exclude ( value ) {
243+ if ( optionsHookIsCalled ) {
244+ throw new Error (
245+ 'exclude cannot be updated after `options` hook is called' ,
246+ )
247+ }
248+ exclude . value = value
249+ } ,
217250 version,
218251 } ,
219252
@@ -317,6 +350,20 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
317350 config . build . watch != null
318351 } ,
319352
353+ options ( ) {
354+ type TransformObjectHook = Extract <
355+ typeof plugin . transform ,
356+ { filter ?: unknown }
357+ >
358+ optionsHookIsCalled = true
359+ ; ( plugin . transform as TransformObjectHook ) . filter = {
360+ id : {
361+ include : [ ...ensureArray ( include . value ) , / [ ? & ] v u e \b / ] ,
362+ exclude : exclude . value ,
363+ } ,
364+ }
365+ } ,
366+
320367 shouldTransformCachedModule ( { id } ) {
321368 if ( transformCachedModule && parseVueRequest ( id ) . query . vue ) {
322369 return true
@@ -338,110 +385,128 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
338385 }
339386 } ,
340387
341- async resolveId ( id ) {
342- // component export helper
343- if ( id === EXPORT_HELPER_ID ) {
344- return id
345- }
346- // serve sub-part requests (*?vue) as virtual modules
347- if ( parseVueRequest ( id ) . query . vue ) {
348- return id
349- }
388+ resolveId : {
389+ filter : {
390+ id : [ exactRegex ( EXPORT_HELPER_ID ) , / [ ? & ] v u e \b / ] ,
391+ } ,
392+ handler ( id ) {
393+ // component export helper
394+ if ( id === EXPORT_HELPER_ID ) {
395+ return id
396+ }
397+ // serve sub-part requests (*?vue) as virtual modules
398+ if ( parseVueRequest ( id ) . query . vue ) {
399+ return id
400+ }
401+ } ,
350402 } ,
351403
352- load ( id , opt ) {
353- if ( id === EXPORT_HELPER_ID ) {
354- return helperCode
355- }
404+ load : {
405+ filter : {
406+ id : [ exactRegex ( EXPORT_HELPER_ID ) , / [ ? & ] v u e \b / ] ,
407+ } ,
408+ handler ( id , opt ) {
409+ if ( id === EXPORT_HELPER_ID ) {
410+ return helperCode
411+ }
356412
357- const ssr = opt ?. ssr === true
413+ const ssr = opt ?. ssr === true
358414
359- const { filename, query } = parseVueRequest ( id )
415+ const { filename, query } = parseVueRequest ( id )
360416
361- // select corresponding block for sub-part virtual modules
362- if ( query . vue ) {
363- if ( query . src ) {
364- return fs . readFileSync ( filename , 'utf-8' )
365- }
366- const descriptor = getDescriptor ( filename , options . value ) !
367- let block : SFCBlock | null | undefined
368- if ( query . type === 'script' ) {
369- // handle <script> + <script setup> merge via compileScript()
370- block = resolveScript (
371- descriptor ,
372- options . value ,
373- ssr ,
374- customElementFilter . value ( filename ) ,
375- )
376- } else if ( query . type === 'template' ) {
377- block = descriptor . template !
378- } else if ( query . type === 'style' ) {
379- block = descriptor . styles [ query . index ! ]
380- } else if ( query . index != null ) {
381- block = descriptor . customBlocks [ query . index ]
382- }
383- if ( block ) {
384- return {
385- code : block . content ,
386- map : block . map as any ,
417+ // select corresponding block for sub-part virtual modules
418+ if ( query . vue ) {
419+ if ( query . src ) {
420+ return fs . readFileSync ( filename , 'utf-8' )
421+ }
422+ const descriptor = getDescriptor ( filename , options . value ) !
423+ let block : SFCBlock | null | undefined
424+ if ( query . type === 'script' ) {
425+ // handle <script> + <script setup> merge via compileScript()
426+ block = resolveScript (
427+ descriptor ,
428+ options . value ,
429+ ssr ,
430+ customElementFilter . value ( filename ) ,
431+ )
432+ } else if ( query . type === 'template' ) {
433+ block = descriptor . template !
434+ } else if ( query . type === 'style' ) {
435+ block = descriptor . styles [ query . index ! ]
436+ } else if ( query . index != null ) {
437+ block = descriptor . customBlocks [ query . index ]
438+ }
439+ if ( block ) {
440+ return {
441+ code : block . content ,
442+ map : block . map as any ,
443+ }
387444 }
388445 }
389- }
446+ } ,
390447 } ,
391448
392- transform ( code , id , opt ) {
393- const ssr = opt ?. ssr === true
394- const { filename, query } = parseVueRequest ( id )
449+ transform : {
450+ // filter is set in options() hook
451+ handler ( code , id , opt ) {
452+ const ssr = opt ?. ssr === true
453+ const { filename, query } = parseVueRequest ( id )
395454
396- if ( query . raw || query . url ) {
397- return
398- }
399-
400- if ( ! filter . value ( filename ) && ! query . vue ) {
401- return
402- }
455+ if ( query . raw || query . url ) {
456+ return
457+ }
403458
404- if ( ! query . vue ) {
405- // main request
406- return transformMain (
407- code ,
408- filename ,
409- options . value ,
410- this ,
411- ssr ,
412- customElementFilter . value ( filename ) ,
413- )
414- } else {
415- // sub block request
416- const descriptor : ExtendedSFCDescriptor = query . src
417- ? getSrcDescriptor ( filename , query ) ||
418- getTempSrcDescriptor ( filename , query )
419- : getDescriptor ( filename , options . value ) !
420-
421- if ( query . src ) {
422- this . addWatchFile ( filename )
459+ if ( ! filter . value ( filename ) && ! query . vue ) {
460+ return
423461 }
424462
425- if ( query . type === 'template' ) {
426- return transformTemplateAsModule (
463+ if ( ! query . vue ) {
464+ // main request
465+ return transformMain (
427466 code ,
428- descriptor ,
467+ filename ,
429468 options . value ,
430469 this ,
431470 ssr ,
432471 customElementFilter . value ( filename ) ,
433472 )
434- } else if ( query . type === 'style' ) {
435- return transformStyle (
436- code ,
437- descriptor ,
438- Number ( query . index || 0 ) ,
439- options . value ,
440- this ,
441- filename ,
442- )
473+ } else {
474+ // sub block request
475+ const descriptor : ExtendedSFCDescriptor = query . src
476+ ? getSrcDescriptor ( filename , query ) ||
477+ getTempSrcDescriptor ( filename , query )
478+ : getDescriptor ( filename , options . value ) !
479+
480+ if ( query . src ) {
481+ this . addWatchFile ( filename )
482+ }
483+
484+ if ( query . type === 'template' ) {
485+ return transformTemplateAsModule (
486+ code ,
487+ descriptor ,
488+ options . value ,
489+ this ,
490+ ssr ,
491+ customElementFilter . value ( filename ) ,
492+ )
493+ } else if ( query . type === 'style' ) {
494+ return transformStyle (
495+ code ,
496+ descriptor ,
497+ Number ( query . index || 0 ) ,
498+ options . value ,
499+ this ,
500+ filename ,
501+ )
502+ }
443503 }
444- }
504+ } ,
445505 } ,
446506 }
507+ return plugin
508+ }
509+
510+ function ensureArray < T > ( value : T | T [ ] ) : T [ ] {
511+ return Array . isArray ( value ) ? value : [ value ]
447512}
0 commit comments