@@ -11,6 +11,7 @@ import { crawlFrameworkPkgs } from 'vitefu';
1111const require = createRequire ( import . meta. url ) ;
1212
1313const runtimePublicPath = '/@solid-refresh' ;
14+ const runtimePublicPathFilter = / ^ \/ @ s o l i d - r e f r e s h $ / ;
1415const runtimeFilePath = require . resolve ( 'solid-refresh/dist/solid-refresh.mjs' ) ;
1516const runtimeCode = readFileSync ( runtimeFilePath , 'utf-8' ) ;
1617
@@ -332,103 +333,125 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
332333 needHmr = config . command === 'serve' && config . mode !== 'production' && options . hot !== false ;
333334 } ,
334335
335- resolveId ( id ) {
336- if ( id === runtimePublicPath ) return id ;
336+ resolveId : {
337+ // Filter is used by Rolldown and newer Rollup/Vite versions (Vite >= 6.3.0) to skip
338+ // unnecessary Rust-to-JS calls. The inner check is kept for backward compatibility
339+ // with older versions that ignore hook filters and call the handler for every module.
340+ // @ts -ignore filter is not yet in Vite's type definitions but is supported at runtime
341+ filter : { id : runtimePublicPathFilter } ,
342+ handler ( id ) {
343+ if ( id === runtimePublicPath ) return id ;
344+ } ,
337345 } ,
338346
339- load ( id ) {
340- if ( id === runtimePublicPath ) return runtimeCode ;
347+ load : {
348+ // Same backward-compatibility strategy as resolveId above.
349+ // @ts -ignore filter is not yet in Vite's type definitions but is supported at runtime
350+ filter : { id : runtimePublicPathFilter } ,
351+ handler ( id ) {
352+ if ( id === runtimePublicPath ) return runtimeCode ;
353+ } ,
341354 } ,
342355
343- async transform ( source , id , transformOptions ) {
344- const isSsr = this . environment
345- ? this . environment . config . consumer === 'server'
346- : Boolean ( transformOptions ?. ssr ) ;
347- const currentFileExtension = getExtension ( id ) ;
348-
349- const extensionsToWatch = options . extensions || [ ] ;
350- const allExtensions = extensionsToWatch . map ( ( extension ) =>
351- // An extension can be a string or a tuple [extension, options]
352- typeof extension === 'string' ? extension : extension [ 0 ] ,
353- ) ;
354-
355- if ( ! filter ( id ) ) {
356- return null ;
357- }
356+ transform : {
357+ // Limit invocations to files that could contain Solid JSX. Custom extensions
358+ // (options.extensions) cannot be represented as a static regex, so they are
359+ // still handled by the inner extension check below — this filter covers the
360+ // common case and is the source of the largest performance win.
361+ // The inner checks (filter(id) / extension regex) are kept as-is so that the
362+ // hook behaves correctly on older Vite/Rollup versions that ignore hook filters.
363+ // @ts -ignore filter is not yet in Vite's type definitions but is supported at runtime
364+ filter : { id : / \. [ m c ] ? [ t j ] s x $ / i } ,
365+ async handler ( source , id , transformOptions ) {
366+ const isSsr = this . environment
367+ ? this . environment . config . consumer === 'server'
368+ : Boolean ( transformOptions ?. ssr ) ;
369+ const currentFileExtension = getExtension ( id ) ;
370+
371+ const extensionsToWatch = options . extensions || [ ] ;
372+ const allExtensions = extensionsToWatch . map ( ( extension ) =>
373+ // An extension can be a string or a tuple [extension, options]
374+ typeof extension === 'string' ? extension : extension [ 0 ] ,
375+ ) ;
376+
377+ if ( ! filter ( id ) ) {
378+ return null ;
379+ }
358380
359- id = id . replace ( / \? .* $ / , '' ) ;
381+ id = id . replace ( / \? .* $ / , '' ) ;
360382
361- if ( ! ( / \. [ m c ] ? [ t j ] s x $ / i. test ( id ) || allExtensions . includes ( currentFileExtension ) ) ) {
362- return null ;
363- }
383+ if ( ! ( / \. [ m c ] ? [ t j ] s x $ / i. test ( id ) || allExtensions . includes ( currentFileExtension ) ) ) {
384+ return null ;
385+ }
364386
365- const inNodeModules = / n o d e _ m o d u l e s / . test ( id ) ;
387+ const inNodeModules = / n o d e _ m o d u l e s / . test ( id ) ;
366388
367- let solidOptions : { generate : 'ssr' | 'dom' ; hydratable : boolean } ;
389+ let solidOptions : { generate : 'ssr' | 'dom' ; hydratable : boolean } ;
368390
369- if ( options . ssr ) {
370- if ( isSsr ) {
371- solidOptions = { generate : 'ssr' , hydratable : true } ;
391+ if ( options . ssr ) {
392+ if ( isSsr ) {
393+ solidOptions = { generate : 'ssr' , hydratable : true } ;
394+ } else {
395+ solidOptions = { generate : 'dom' , hydratable : true } ;
396+ }
372397 } else {
373- solidOptions = { generate : 'dom' , hydratable : true } ;
398+ solidOptions = { generate : 'dom' , hydratable : false } ;
374399 }
375- } else {
376- solidOptions = { generate : 'dom' , hydratable : false } ;
377- }
378-
379- // We need to know if the current file extension has a typescript options tied to it
380- const shouldBeProcessedWithTypescript =
381- / \. [ m c ] ? t s x $ / i. test ( id ) ||
382- extensionsToWatch . some ( ( extension ) => {
383- if ( typeof extension === 'string' ) {
384- return extension . includes ( 'tsx' ) ;
385- }
386-
387- const [ extensionName , extensionOptions ] = extension ;
388- if ( extensionName !== currentFileExtension ) return false ;
389400
390- return extensionOptions . typescript ;
391- } ) ;
392- const plugins : NonNullable < NonNullable < babel . TransformOptions [ 'parserOpts' ] > [ 'plugins' ] > = [
393- 'jsx' ,
394- ] ;
395-
396- if ( shouldBeProcessedWithTypescript ) {
397- plugins . push ( 'typescript' ) ;
398- }
399-
400- const opts : babel . TransformOptions = {
401- root : projectRoot ,
402- filename : id ,
403- sourceFileName : id ,
404- presets : [ [ solid , { ...solidOptions , ...( options . solid || { } ) } ] ] ,
405- plugins : needHmr && ! isSsr && ! inNodeModules ? [ [ solidRefresh , { bundler : 'vite' } ] ] : [ ] ,
406- ast : false ,
407- sourceMaps : true ,
408- configFile : false ,
409- babelrc : false ,
410- parserOpts : {
411- plugins,
412- } ,
413- } ;
414-
415- // Default value for babel user options
416- let babelUserOptions : babel . TransformOptions = { } ;
401+ // We need to know if the current file extension has a typescript options tied to it
402+ const shouldBeProcessedWithTypescript =
403+ / \. [ m c ] ? t s x $ / i. test ( id ) ||
404+ extensionsToWatch . some ( ( extension ) => {
405+ if ( typeof extension === 'string' ) {
406+ return extension . includes ( 'tsx' ) ;
407+ }
408+
409+ const [ extensionName , extensionOptions ] = extension ;
410+ if ( extensionName !== currentFileExtension ) return false ;
411+
412+ return extensionOptions . typescript ;
413+ } ) ;
414+ const plugins : NonNullable < NonNullable < babel . TransformOptions [ 'parserOpts' ] > [ 'plugins' ] > = [
415+ 'jsx' ,
416+ ] ;
417+
418+ if ( shouldBeProcessedWithTypescript ) {
419+ plugins . push ( 'typescript' ) ;
420+ }
417421
418- if ( options . babel ) {
419- if ( typeof options . babel === 'function' ) {
420- const babelOptions = options . babel ( source , id , isSsr ) ;
421- babelUserOptions = babelOptions instanceof Promise ? await babelOptions : babelOptions ;
422- } else {
423- babelUserOptions = options . babel ;
422+ const opts : babel . TransformOptions = {
423+ root : projectRoot ,
424+ filename : id ,
425+ sourceFileName : id ,
426+ presets : [ [ solid , { ...solidOptions , ...( options . solid || { } ) } ] ] ,
427+ plugins : needHmr && ! isSsr && ! inNodeModules ? [ [ solidRefresh , { bundler : 'vite' } ] ] : [ ] ,
428+ ast : false ,
429+ sourceMaps : true ,
430+ configFile : false ,
431+ babelrc : false ,
432+ parserOpts : {
433+ plugins,
434+ } ,
435+ } ;
436+
437+ // Default value for babel user options
438+ let babelUserOptions : babel . TransformOptions = { } ;
439+
440+ if ( options . babel ) {
441+ if ( typeof options . babel === 'function' ) {
442+ const babelOptions = options . babel ( source , id , isSsr ) ;
443+ babelUserOptions = babelOptions instanceof Promise ? await babelOptions : babelOptions ;
444+ } else {
445+ babelUserOptions = options . babel ;
446+ }
424447 }
425- }
426448
427- const babelOptions = mergeAndConcat ( babelUserOptions , opts ) as babel . TransformOptions ;
449+ const babelOptions = mergeAndConcat ( babelUserOptions , opts ) as babel . TransformOptions ;
428450
429- const { code, map } = await babel . transformAsync ( source , babelOptions ) ;
451+ const { code, map } = await babel . transformAsync ( source , babelOptions ) ;
430452
431- return { code, map } ;
453+ return { code, map } ;
454+ } ,
432455 } ,
433456 } ;
434457}
0 commit comments