@@ -41,7 +41,6 @@ import {
4141import { import_peer } from '../../utils/import.js' ;
4242import { compact } from '../../utils/array.js' ;
4343import { should_ignore } from './static_analysis/utils.js' ;
44- import { rollupVersion } from 'vite' ;
4544
4645const cwd = process . cwd ( ) ;
4746
@@ -636,102 +635,30 @@ async function kit({ svelte_config }) {
636635/** @type {Array<{ hash: string, file: string }> } */
637636const remotes = [ ] ;
638637
639- /**
640- * A set of modules that imported by `.remote.ts` modules. By forcing these modules
641- * into their own chunks, we ensure that each chunk created for a `.remote.ts`
642- * module _only_ contains that module, hopefully avoiding any circular
643- * dependency woes that arise from treating chunks as entries
644- */
645- const imported_by_remotes = new Set ( ) ;
646- let uid = 1 ;
638+ /** @type {Map<string, string> } Maps remote hash -> original module id */
639+ const remote_original_by_hash = new Map ( ) ;
640+
641+ /** @type {Set<string> } Track which remote hashes have already been emitted */
642+ const emitted_remote_hashes = new Set ( ) ;
647643
648644/** @type {import('vite').Plugin } */
649645const plugin_remote = {
650646name : 'vite-plugin-sveltekit-remote' ,
651647
652- moduleParsed ( info ) {
653- if ( svelte_config . kit . moduleExtensions . some ( ( ext ) => info . id . endsWith ( `.remote${ ext } ` ) ) ) {
654- for ( const id of info . importedIds ) {
655- imported_by_remotes . add ( id ) ;
656- }
657- }
648+ resolveId ( id ) {
649+ if ( id . startsWith ( '\0sveltekit-remote:' ) ) return id ;
658650} ,
659651
660- config ( config ) {
661- if ( ! config . build ?. ssr ) {
662- // only set manualChunks for the SSR build
663- return ;
664- }
665-
666- // Ensure build.rollupOptions.output exists
667- config . build ??= { } ;
668- config . build . rollupOptions ??= { } ;
669- config . build . rollupOptions . output ??= { } ;
670-
671- if ( Array . isArray ( config . build . rollupOptions . output ) ) {
672- // TODO I have no idea how this could occur
673- throw new Error ( 'rollupOptions.output cannot be an array' ) ;
674- }
675-
676- // Set up manualChunks to isolate *.remote.ts files
677- const { manualChunks } = config . build . rollupOptions . output ;
678-
679- const [ major , minor ] = rollupVersion . split ( '.' ) . map ( Number ) ;
680- const is_outdated_rollup = major === 4 && minor < 52 ;
681- if ( is_outdated_rollup ) {
682- console . warn (
683- 'Rollup >=4.52.0 is recommended when using SvelteKit remote functions as it fixes some bugs related to code-splitting. Current version: ' +
684- rollupVersion
685- ) ;
686- }
687-
688- config . build . rollupOptions . output = {
689- ...config . build . rollupOptions . output ,
690- manualChunks ( id , meta ) {
691- // Check if this is a *.remote.ts file
692- if ( svelte_config . kit . moduleExtensions . some ( ( ext ) => id . endsWith ( `.remote${ ext } ` ) ) ) {
693- const relative = posixify ( path . relative ( cwd , id ) ) ;
694-
695- return `remote-${ hash ( relative ) } ` ;
696- }
697-
698- // With onlyExplicitManualChunks Rollup will keep any manual chunk's dependencies out of that chunk.
699- // This option only exists on more recent Rollup versions; use this as a fallback for older versions.
700- if ( is_outdated_rollup ) {
701- // Prevent core runtime and env from ending up in a remote chunk, which could break because of initialization order
702- if ( id === `${ runtime_directory } /app/server/index.js` ) {
703- return 'app-server' ;
704- }
705- if ( id === `${ runtime_directory } /shared-server.js` ) {
706- return 'app-shared-server' ;
707- }
708- if ( imported_by_remotes . has ( id ) ) {
709- return `chunk-${ uid ++ } ` ;
710- }
711- }
712-
713- // If there was an existing manualChunks function, call it
714- if ( typeof manualChunks === 'function' ) {
715- return manualChunks ( id , meta ) ;
716- }
717-
718- // If manualChunks is an object, check if this module matches any patterns
719- if ( manualChunks ) {
720- for ( const name in manualChunks ) {
721- const patterns = manualChunks [ name ] ;
722-
723- // TODO is `id.includes(pattern)` correct?
724- if ( patterns . some ( ( pattern ) => id . includes ( pattern ) ) ) {
725- return name ;
726- }
727- }
728- }
729- }
730- } ;
731-
732- if ( ! is_outdated_rollup ) {
733- // @ts -expect-error only exists in more recent Rollup versions https://rollupjs.org/configuration-options/#output-onlyexplicitmanualchunks
734- config . build . rollupOptions . output . onlyExplicitManualChunks = true ;
652+ load ( id ) {
653+ // On-the-fly generated entry point for remote file just forwards the original module
654+ // We're not using manualChunks because it can cause problems with circular dependencies
655+ // (e.g. https://github.com/sveltejs/kit/issues/14679) and module ordering in general
656+ // (e.g. https://github.com/sveltejs/kit/issues/14590).
657+ if ( id . startsWith ( '\0sveltekit-remote:' ) ) {
658+ const hash_id = id . slice ( '\0sveltekit-remote:' . length ) ;
659+ const original = remote_original_by_hash . get ( hash_id ) ;
660+ if ( ! original ) throw new Error ( `Expected to find metadata for remote file ${ id } ` ) ;
661+ return `import * as m from ${ s ( original ) } ;\nexport default m;` ;
735662}
736663} ,
737664
@@ -746,7 +673,6 @@ async function kit({ svelte_config }) {
746673}
747674
748675const file = posixify ( path . relative ( cwd , id ) ) ;
749-
750676const remote = {
751677hash : hash ( file ) ,
752678file
@@ -770,10 +696,17 @@ async function kit({ svelte_config }) {
770696}
771697` ;
772698
699+ // Emit a dedicated entry chunk for this remote in SSR builds (prod only)
773700if ( ! dev_server ) {
774- // in prod, prevent the functions from being treeshaken. This will
775- // be replaced with an `export default` in the `writeBundle` hook
776- code += `$$_export_$$($$_self_$$);` ;
701+ remote_original_by_hash . set ( remote . hash , id ) ;
702+ if ( ! emitted_remote_hashes . has ( remote . hash ) ) {
703+ this . emitFile ( {
704+ type : 'chunk' ,
705+ id : `\0sveltekit-remote:${ remote . hash } ` ,
706+ name : `remote-${ remote . hash } `
707+ } ) ;
708+ emitted_remote_hashes . add ( remote . hash ) ;
709+ }
777710}
778711
779712return code ;
@@ -826,19 +759,6 @@ async function kit({ svelte_config }) {
826759return {
827760code : result
828761} ;
829- } ,
830-
831- writeBundle ( ) {
832- for ( const remote of remotes ) {
833- const file = `${ out } /server/chunks/remote-${ remote . hash } .js` ;
834- const code = fs . readFileSync ( file , 'utf-8' ) ;
835-
836- fs . writeFileSync (
837- file ,
838- // build process might have minified/adjusted the $$_self_$$ variable, but not the fake global $$_export_$$ function
839- code . replace ( / \$ \$ _ e x p o r t _ \$ \$ \( ( .+ ?) \) / , ( _ , name ) => `export default ${ name } ;` )
840- ) ;
841- }
842762}
843763} ;
844764
0 commit comments