@@ -203,6 +203,23 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
203203 {
204204 name : "marko-vite:pre" ,
205205 enforce : "pre" , // Must be pre to allow us to resolve assets before vite.
206+ sharedDuringBuild : true ,
207+ async buildApp ( builder ) {
208+ const { ssr, client } = builder . environments ;
209+ if ( ! ssr || ! client ) {
210+ // vite on legacy linked build
211+ return ;
212+ }
213+ // vite environment api build
214+ if ( builder . config ?. builder ?. buildApp ) {
215+ // let custom builder take priority
216+ return ;
217+ }
218+ if ( linked ) {
219+ await builder . build ( ssr ) ;
220+ }
221+ await builder . build ( client ) ;
222+ } ,
206223 async config ( config , env ) {
207224 let optimize = env . mode === "production" ;
208225 isTest = env . mode === "test" ;
@@ -412,6 +429,11 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
412429 ! isCJSModule ( id , rootResolveFile ) ;
413430 }
414431
432+ if ( linked && ! isSSRBuild ) {
433+ config . build ??= { } ;
434+ config . build . emptyOutDir = false ;
435+ }
436+
415437 if ( basePathVar ) {
416438 config . experimental ??= { } ;
417439
@@ -468,6 +490,53 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
468490 } ,
469491 } ;
470492 } ,
493+ configEnvironment ( name , options ) {
494+ if ( name === "ssr" ) {
495+ options . resolve ??= { } ;
496+ const { noExternal } = options . resolve ;
497+ if ( noExternal !== true ) {
498+ const noExternalReg = / \. m a r k o $ / ;
499+ if ( noExternal ) {
500+ if ( Array . isArray ( noExternal ) ) {
501+ options . resolve . noExternal = [ ...noExternal , noExternalReg ] ;
502+ } else {
503+ options . resolve . noExternal = [ noExternal , noExternalReg ] ;
504+ }
505+ } else {
506+ options . resolve . noExternal = noExternalReg ;
507+ }
508+ }
509+
510+ options . build ??= { } ;
511+ options . build . emptyOutDir = true ;
512+
513+ if ( ! options . build ?. rollupOptions ?. output ) {
514+ // For the server build vite will still output code split chunks to the `assets` directory by default.
515+ // this is problematic since you might have server assets in your client assets folder.
516+ // Here we change the default chunkFileNames config to instead output to the outDir directly.
517+ options . build . rollupOptions ??= { } ;
518+ options . build . rollupOptions . output = {
519+ chunkFileNames : `[name]-[hash].js` ,
520+ } ;
521+ }
522+ if ( ! options . build ?. commonjsOptions ?. esmExternals ) {
523+ // Rollup rewrites `require` calls to default imports for commonjs dependencies; however, if the
524+ // dependency is inlined, its require calls which were assumed to be commonjs are also rewritten but
525+ // now resolve from an ESM context and the default import is no longer safe due to conditional exports.
526+ // This tells Rollup which dependencies are ESM so it uses a namespace import instead.
527+ options . build . commonjsOptions ??= { } ;
528+ options . build . commonjsOptions . esmExternals = ( id ) =>
529+ ! isCJSModule ( id , rootResolveFile ) ;
530+ }
531+ } else {
532+ if ( linked ) {
533+ options . build ??= { } ;
534+ options . build . emptyOutDir = false ;
535+ }
536+ }
537+
538+ return options ;
539+ } ,
471540 configResolved ( config ) {
472541 basePath = config . base ;
473542 cacheDir = config . cacheDir && normalizePath ( config . cacheDir ) ;
@@ -535,7 +604,7 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
535604
536605 async options ( inputOptions ) {
537606 if ( linked && isBuild ) {
538- if ( isSSRBuild ) {
607+ if ( isSSRBuild || this . environment ?. name === "ssr" ) {
539608 serverManifest = {
540609 entries : { } ,
541610 entrySources : { } ,
@@ -567,7 +636,12 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
567636 }
568637 } ,
569638 async buildStart ( ) {
570- if ( isBuild && linked && ! isSSRBuild ) {
639+ if (
640+ isBuild &&
641+ linked &&
642+ ! isSSRBuild &&
643+ this . environment ?. name !== "ssr"
644+ ) {
571645 for ( const assetId of serverManifest ! . ssrAssetIds ) {
572646 this . load ( {
573647 id : normalizePath ( path . resolve ( root , assetId ) ) ,
@@ -911,7 +985,8 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
911985 {
912986 name : "marko-vite:post" ,
913987 apply : "build" ,
914- enforce : "post" , // We use a "post" plugin to allow us to read the final generated `.html` from vite.
988+ enforce : "post" , // We use a "post" plugin to allow us to read the final generated `.html` from vite.,
989+ sharedDuringBuild : true ,
915990 transform ( _source , id , opts ) {
916991 if ( ! opts ?. ssr && / \. m o d u l e \. [ ^ . ] + (?: \? | $ ) / . test ( id ) ) {
917992 // CSS modules in vite tree shake, however when coupled with
@@ -935,7 +1010,7 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
9351010 ) ;
9361011 }
9371012
938- if ( isSSRBuild ) {
1013+ if ( isSSRBuild || this . environment ?. name === "ssr" ) {
9391014 const dir = outputOptions . dir
9401015 ? path . resolve ( outputOptions . dir )
9411016 : path . resolve ( outputOptions . file ! , ".." ) ;
0 commit comments