@@ -9,8 +9,7 @@ import { toESBuildError } from './error.js';
99 */
1010
1111export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade' ;
12-
13- const svelteModuleExtension = '.svelte.js' ;
12+ export const facadeEsbuildSvelteModulePluginName = 'vite-plugin-svelte-module:facade' ;
1413
1514/**
1615 * @param {import('../types/options.d.ts').ResolvedOptions } options
@@ -24,18 +23,15 @@ export function esbuildSveltePlugin(options) {
2423 // Otherwise this would heavily slow down the scanning phase.
2524 if ( build . initialOptions . plugins ?. some ( ( v ) => v . name === 'vite:dep-scan' ) ) return ;
2625
27- const svelteExtensions = ( options . extensions ?? [ '.svelte' ] ) . map ( ( ext ) => ext . slice ( 1 ) ) ;
28- svelteExtensions . push ( svelteModuleExtension . slice ( 1 ) ) ;
29-
30- const svelteFilter = new RegExp ( '\\.(' + svelteExtensions . join ( '|' ) + ')(\\?.*)?$' ) ;
26+ const filter = / \. s v e l t e (?: \? .* ) ? $ / ;
3127 /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined } */
3228 let statsCollection ;
3329 build . onStart ( ( ) => {
34- statsCollection = options . stats ?. startCollection ( 'prebundle libraries ' , {
30+ statsCollection = options . stats ?. startCollection ( 'prebundle library components ' , {
3531 logResult : ( c ) => c . stats . length > 1
3632 } ) ;
3733 } ) ;
38- build . onLoad ( { filter : svelteFilter } , async ( { path : filename } ) => {
34+ build . onLoad ( { filter } , async ( { path : filename } ) => {
3935 const code = readFileSync ( filename , 'utf8' ) ;
4036 try {
4137 const contents = await compileSvelte ( options , { filename, code } , statsCollection ) ;
@@ -58,26 +54,14 @@ export function esbuildSveltePlugin(options) {
5854 * @returns {Promise<string> }
5955 */
6056async function compileSvelte ( options , { filename, code } , statsCollection ) {
61- if ( filename . endsWith ( svelteModuleExtension ) ) {
62- const endStat = statsCollection ?. start ( filename ) ;
63- const compiled = svelte . compileModule ( code , {
64- filename,
65- generate : 'client'
66- } ) ;
67- if ( endStat ) {
68- endStat ( ) ;
69- }
70- return compiled . js . map
71- ? compiled . js . code + '//# sourceMappingURL=' + compiled . js . map . toUrl ( )
72- : compiled . js . code ;
73- }
7457 let css = options . compilerOptions . css ;
7558 if ( css !== 'injected' ) {
7659 // TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js
7760 css = 'injected' ;
7861 }
7962 /** @type {import('svelte/compiler').CompileOptions } */
8063 const compileOptions = {
64+ dev : true , // default to dev: true because prebundling is only used in dev
8165 ...options . compilerOptions ,
8266 css,
8367 filename,
@@ -127,3 +111,60 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
127111 ? compiled . js . code + '//# sourceMappingURL=' + compiled . js . map . toUrl ( )
128112 : compiled . js . code ;
129113}
114+
115+ /**
116+ * @param {import('../types/options.d.ts').ResolvedOptions } options
117+ * @returns {EsbuildPlugin }
118+ */
119+ export function esbuildSvelteModulePlugin ( options ) {
120+ return {
121+ name : 'vite-plugin-svelte-module:optimize-svelte' ,
122+ setup ( build ) {
123+ // Skip in scanning phase as Vite already handles scanning Svelte files.
124+ // Otherwise this would heavily slow down the scanning phase.
125+ if ( build . initialOptions . plugins ?. some ( ( v ) => v . name === 'vite:dep-scan' ) ) return ;
126+
127+ const filter = / \. s v e l t e \. [ j t ] s (?: \? .* ) ? $ / ;
128+ /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined } */
129+ let statsCollection ;
130+ build . onStart ( ( ) => {
131+ statsCollection = options . stats ?. startCollection ( 'prebundle library modules' , {
132+ logResult : ( c ) => c . stats . length > 1
133+ } ) ;
134+ } ) ;
135+ build . onLoad ( { filter } , async ( { path : filename } ) => {
136+ const code = readFileSync ( filename , 'utf8' ) ;
137+ try {
138+ const contents = await compileSvelteModule ( options , { filename, code } , statsCollection ) ;
139+ return { contents } ;
140+ } catch ( e ) {
141+ return { errors : [ toESBuildError ( e , options ) ] } ;
142+ }
143+ } ) ;
144+ build . onEnd ( ( ) => {
145+ statsCollection ?. finish ( ) ;
146+ } ) ;
147+ }
148+ } ;
149+ }
150+
151+ /**
152+ * @param {import('../types/options.d.ts').ResolvedOptions } options
153+ * @param {{ filename: string; code: string } } input
154+ * @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection } [statsCollection]
155+ * @returns {Promise<string> }
156+ */
157+ async function compileSvelteModule ( options , { filename, code } , statsCollection ) {
158+ const endStat = statsCollection ?. start ( filename ) ;
159+ const compiled = svelte . compileModule ( code , {
160+ dev : options . compilerOptions ?. dev ?? true , // default to dev: true because prebundling is only used in dev
161+ filename,
162+ generate : 'client'
163+ } ) ;
164+ if ( endStat ) {
165+ endStat ( ) ;
166+ }
167+ return compiled . js . map
168+ ? compiled . js . code + '//# sourceMappingURL=' + compiled . js . map . toUrl ( )
169+ : compiled . js . code ;
170+ }
0 commit comments