11import { readFileSync } from 'node:fs' ;
22import * as svelte from 'svelte/compiler' ;
33import { log } from './log.js' ;
4- import { toESBuildError } from './error.js' ;
4+ import { toESBuildError , toRollupError } from './error.js' ;
55import { safeBase64Hash } from './hash.js' ;
66import { normalize } from './id.js' ;
77
88/**
99 * @typedef {NonNullable<import('vite').DepOptimizationOptions['esbuildOptions']> } EsbuildOptions
1010 * @typedef {NonNullable<EsbuildOptions['plugins']>[number] } EsbuildPlugin
1111 */
12-
13- export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade' ;
14- export const facadeEsbuildSvelteModulePluginName = 'vite-plugin-svelte-module:facade' ;
12+ /*
13+ * @typedef {NonNullable<import('vite').DepOptimizationOptions['rollupOptions']> } RollupOptions
14+ * @typedef {NonNullable<RollupOptions['plugins']>[number] } RolldownPlugin
15+ */
16+ // TODO type correctly when the above works
17+ /**
18+ * @typedef {{
19+ * name: string,
20+ * options: ()=>void,
21+ * transform?:{
22+ * filter: any
23+ * handler: (code: string,id: string)=>Promise<any>
24+ * },
25+ * buildStart?:()=>void,
26+ * buildEnd?:()=>void
27+ * }} RolldownPlugin
28+ */
29+ export const facadeOptimizeSveltePluginName = 'vite-plugin-svelte:facade' ;
30+ export const facadeOptimizeSvelteModulePluginName = 'vite-plugin-svelte-module:facade' ;
1531
1632/**
1733 * @param {import('../types/options.d.ts').ResolvedOptions } options
@@ -36,7 +52,10 @@ export function esbuildSveltePlugin(options) {
3652build . onLoad ( { filter } , async ( { path : filename } ) => {
3753const code = readFileSync ( filename , 'utf8' ) ;
3854try {
39- const contents = await compileSvelte ( options , { filename, code } , statsCollection ) ;
55+ const result = await compileSvelte ( options , { filename, code } , statsCollection ) ;
56+ const contents = result . map
57+ ? result . code + '//# sourceMappingURL=' + result . map . toUrl ( )
58+ : result . code ;
4059return { contents } ;
4160} catch ( e ) {
4261return { errors : [ toESBuildError ( e , options ) ] } ;
@@ -49,11 +68,63 @@ export function esbuildSveltePlugin(options) {
4968} ;
5069}
5170
71+ /**
72+ * @param {import('../types/options.d.ts').ResolvedOptions } options
73+ * @returns {RolldownPlugin }
74+ */
75+ export function rolldownOptimizeSveltePlugin ( options ) {
76+ /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined } */
77+ let statsCollection ;
78+ /** @type {RolldownPlugin } */
79+ const plugin = {
80+ name : 'vite-plugin-svelte:rolldown-optimize-svelte' ,
81+ // @ts -expect-error not typed in rolldown yet
82+ options ( opts ) {
83+ if (
84+ opts . plugins ?. some ( ( /** @type {{ name: string; } } */ p ) =>
85+ p . name . startsWith ( 'vite:dep-scan' )
86+ )
87+ ) {
88+ delete plugin . transform ;
89+ delete plugin . buildStart ;
90+ delete plugin . buildEnd ;
91+ }
92+ } ,
93+ transform : {
94+ filter : {
95+ // TODO: remove excludes once above options hook works
96+ id : { include : [ / ^ [ ^ ? # ] + \. s v e l t e (?: [ ? # ] | $ ) / ] , exclude : [ / ^ v i r t u a l - m o d u l e : / ] } ,
97+ code : { exclude : [ / (?: i m p o r t | e x p o r t ) [ ^ " \n ] + " v i r t u a l - m o d u l e : / ] }
98+ } ,
99+ /**
100+ * @param {string } code
101+ * @param {string } filename
102+ */
103+ async handler ( code , filename ) {
104+ try {
105+ return await compileSvelte ( options , { filename, code } , statsCollection ) ;
106+ } catch ( e ) {
107+ throw toRollupError ( e , options ) ;
108+ }
109+ }
110+ } ,
111+ buildStart ( ) {
112+ statsCollection = options . stats ?. startCollection ( 'prebundle library components' , {
113+ logResult : ( c ) => c . stats . length > 1
114+ } ) ;
115+ } ,
116+ buildEnd ( ) {
117+ statsCollection ?. finish ( ) ;
118+ }
119+ } ;
120+ return plugin ;
121+ }
122+
52123/**
53124 * @param {import('../types/options.d.ts').ResolvedOptions } options
54125 * @param {{ filename: string, code: string } } input
55126 * @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection } [statsCollection]
56- * @returns {Promise<string > }
127+ * @returns {Promise<import('../types/compile.d.ts').Code > }
57128 */
58129async function compileSvelte ( options , { filename, code } , statsCollection ) {
59130let css = options . compilerOptions . css ;
@@ -114,9 +185,10 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
114185if ( endStat ) {
115186endStat ( ) ;
116187}
117- return compiled . js . map
118- ? compiled . js . code + '//# sourceMappingURL=' + compiled . js . map . toUrl ( )
119- : compiled . js . code ;
188+ return {
189+ ...compiled . js ,
190+ moduleType : 'js'
191+ } ;
120192}
121193
122194/**
@@ -142,7 +214,10 @@ export function esbuildSvelteModulePlugin(options) {
142214build . onLoad ( { filter } , async ( { path : filename } ) => {
143215const code = readFileSync ( filename , 'utf8' ) ;
144216try {
145- const contents = await compileSvelteModule ( options , { filename, code } , statsCollection ) ;
217+ const result = await compileSvelteModule ( options , { filename, code } , statsCollection ) ;
218+ const contents = result . map
219+ ? result . code + '//# sourceMappingURL=' + result . map . toUrl ( )
220+ : result . code ;
146221return { contents } ;
147222} catch ( e ) {
148223return { errors : [ toESBuildError ( e , options ) ] } ;
@@ -155,11 +230,63 @@ export function esbuildSvelteModulePlugin(options) {
155230} ;
156231}
157232
233+ /**
234+ * @param {import('../types/options.d.ts').ResolvedOptions } options
235+ * @returns {RolldownPlugin }
236+ */
237+ export function rolldownOptimizeSvelteModulePlugin ( options ) {
238+ /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined } */
239+ let statsCollection ;
240+ /** @type {RolldownPlugin } */
241+ const plugin = {
242+ name : 'vite-plugin-svelte:rolldown-optimize-svelte-module' ,
243+ // @ts -expect-error not typed in rolldown yet
244+ options ( opts ) {
245+ if (
246+ opts . plugins ?. some ( ( /** @type {{ name: string; } } */ p ) =>
247+ p . name . startsWith ( 'vite:dep-scan' )
248+ )
249+ ) {
250+ delete plugin . transform ;
251+ delete plugin . buildStart ;
252+ delete plugin . buildEnd ;
253+ }
254+ } ,
255+ transform : {
256+ filter : {
257+ // TODO: remove excludes once above options hook works
258+ id : { include : [ / ^ [ ^ ? # ] + \. s v e l t e \. j s (?: [ ? # ] | $ ) / ] , exclude : [ / ^ v i r t u a l - m o d u l e : / ] } ,
259+ code : { exclude : [ / (?: i m p o r t | e x p o r t ) [ ^ " \n ] + " v i r t u a l - m o d u l e : / ] }
260+ } ,
261+ /**
262+ * @param {string } code
263+ * @param {string } filename
264+ */
265+ async handler ( code , filename ) {
266+ try {
267+ return await compileSvelteModule ( options , { filename, code } , statsCollection ) ;
268+ } catch ( e ) {
269+ throw toRollupError ( e , options ) ;
270+ }
271+ }
272+ } ,
273+ buildStart ( ) {
274+ statsCollection = options . stats ?. startCollection ( 'prebundle library components' , {
275+ logResult : ( c ) => c . stats . length > 1
276+ } ) ;
277+ } ,
278+ buildEnd ( ) {
279+ statsCollection ?. finish ( ) ;
280+ }
281+ } ;
282+ return plugin ;
283+ }
284+
158285/**
159286 * @param {import('../types/options.d.ts').ResolvedOptions } options
160287 * @param {{ filename: string; code: string } } input
161288 * @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection } [statsCollection]
162- * @returns {Promise<string > }
289+ * @returns {Promise<import('../types/compile.d.ts').Code > }
163290 */
164291async function compileSvelteModule ( options , { filename, code } , statsCollection ) {
165292const endStat = statsCollection ?. start ( filename ) ;
@@ -171,7 +298,8 @@ async function compileSvelteModule(options, { filename, code }, statsCollection)
171298if ( endStat ) {
172299endStat ( ) ;
173300}
174- return compiled . js . map
175- ? compiled . js . code + '//# sourceMappingURL=' + compiled . js . map . toUrl ( )
176- : compiled . js . code ;
301+ return {
302+ ...compiled . js ,
303+ moduleType : 'js'
304+ } ;
177305}
0 commit comments