11import * as devalue from 'devalue' ;
22import { readable , writable } from 'svelte/store' ;
33import { DEV } from 'esm-env' ;
4- import { assets , base } from '__sveltekit/paths' ;
4+ import * as paths from '__sveltekit/paths' ;
55import { hash } from '../../hash.js' ;
66import { serialize_data } from './serialize_data.js' ;
77import { s } from '../../../utils/misc.js' ;
@@ -11,6 +11,7 @@ import { clarify_devalue_error, stringify_uses, handle_error_and_jsonify } from
1111import { public_env } from '../../shared-server.js' ;
1212import { text } from '../../../exports/index.js' ;
1313import { create_async_iterator } from '../../../utils/streaming.js' ;
14+ import { SVELTE_KIT_ASSETS } from '../../../constants.js' ;
1415
1516// TODO rename this function/module
1617
@@ -80,6 +81,43 @@ export async function render_response({
8081 ? action_result . data ?? null
8182 : null ;
8283
84+ /** @type {string } */
85+ let base = paths . base ;
86+
87+ /** @type {string } */
88+ let assets = paths . assets ;
89+
90+ /**
91+ * An expression that will evaluate in the client to determine the resolved base path.
92+ * We use a relative path when possible to support IPFS, the internet archive, etc.
93+ */
94+ let base_expression = s ( paths . base ) ;
95+
96+ // if appropriate, use relative paths for greater portability
97+ if ( paths . relative !== false && ! state . prerendering ?. fallback ) {
98+ const segments = event . url . pathname . slice ( paths . base . length ) . split ( '/' ) ;
99+
100+ if ( segments . length === 1 && paths . base !== '' ) {
101+ // if we're on `/my-base-path`, relative links need to start `./my-base-path` rather than `.`
102+ base = `./${ paths . base . split ( '/' ) . at ( - 1 ) } ` ;
103+
104+ base_expression = `new URL(${ s ( base ) } , location).pathname` ;
105+ } else {
106+ base =
107+ segments
108+ . slice ( 2 )
109+ . map ( ( ) => '..' )
110+ . join ( '/' ) || '.' ;
111+
112+ // resolve e.g. '../..' against current location, then remove trailing slash
113+ base_expression = `new URL(${ s ( base ) } , location).pathname.slice(0, -1)` ;
114+ }
115+
116+ if ( ! paths . assets || ( paths . assets [ 0 ] === '/' && paths . assets !== SVELTE_KIT_ASSETS ) ) {
117+ assets = base ;
118+ }
119+ }
120+
83121 if ( page_config . ssr ) {
84122 if ( __SVELTEKIT_DEV__ && ! branch . at ( - 1 ) ?. node . component ) {
85123 // Can only be the leaf, layouts have a fallback component generated
@@ -116,6 +154,10 @@ export async function render_response({
116154 form : form_value
117155 } ;
118156
157+ // use relative paths during rendering, so that the resulting HTML is as
158+ // portable as possible, but reset afterwards
159+ if ( paths . relative ) paths . override ( { base, assets } ) ;
160+
119161 if ( __SVELTEKIT_DEV__ ) {
120162 const fetch = globalThis . fetch ;
121163 let warned = false ;
@@ -138,9 +180,14 @@ export async function render_response({
138180 rendered = options . root . render ( props ) ;
139181 } finally {
140182 globalThis . fetch = fetch ;
183+ paths . reset ( ) ;
141184 }
142185 } else {
143- rendered = options . root . render ( props ) ;
186+ try {
187+ rendered = options . root . render ( props ) ;
188+ } finally {
189+ paths . reset ( ) ;
190+ }
144191 }
145192
146193 for ( const { node } of branch ) {
@@ -156,35 +203,6 @@ export async function render_response({
156203 rendered = { head : '' , html : '' , css : { code : '' , map : null } } ;
157204 }
158205
159- /**
160- * The prefix to use for static assets. Replaces `%sveltekit.assets%` in the template
161- * @type {string }
162- */
163- let resolved_assets ;
164-
165- /**
166- * An expression that will evaluate in the client to determine the resolved asset path
167- */
168- let asset_expression ;
169-
170- if ( assets ) {
171- // if an asset path is specified, use it
172- resolved_assets = assets ;
173- asset_expression = s ( assets ) ;
174- } else if ( state . prerendering ?. fallback ) {
175- // if we're creating a fallback page, asset paths need to be root-relative
176- resolved_assets = base ;
177- asset_expression = s ( base ) ;
178- } else {
179- // otherwise we want asset paths to be relative to the page, so that they
180- // will work in odd contexts like IPFS, the internet archive, and so on
181- const segments = event . url . pathname . slice ( base . length ) . split ( '/' ) . slice ( 2 ) ;
182- resolved_assets = segments . length > 0 ? segments . map ( ( ) => '..' ) . join ( '/' ) : '.' ;
183- asset_expression = `new URL(${ s (
184- resolved_assets
185- ) } , location.href).pathname.replace(/^\\\/$/, '')`;
186- }
187-
188206 let head = '' ;
189207 let body = rendered . html ;
190208
@@ -198,9 +216,9 @@ export async function render_response({
198216 // Vite makes the start script available through the base path and without it.
199217 // We load it via the base path in order to support remote IDE environments which proxy
200218 // all URLs under the base path during development.
201- return base + path ;
219+ return paths . base + path ;
202220 }
203- return `${ resolved_assets } /${ path } ` ;
221+ return `${ assets } /${ path } ` ;
204222 } ;
205223
206224 if ( inline_styles . size > 0 ) {
@@ -286,9 +304,10 @@ export async function render_response({
286304
287305 const properties = [
288306 `env: ${ s ( public_env ) } ` ,
289- `assets: ${ asset_expression } ` ,
307+ paths . assets && `assets: ${ s ( paths . assets ) } ` ,
308+ `base: ${ base_expression } ` ,
290309 `element: document.currentScript.parentElement`
291- ] ;
310+ ] . filter ( Boolean ) ;
292311
293312 if ( chunks ) {
294313 blocks . push ( `const deferred = new Map();` ) ;
@@ -419,7 +438,7 @@ export async function render_response({
419438 const html = options . templates . app ( {
420439 head,
421440 body,
422- assets : resolved_assets ,
441+ assets,
423442 nonce : /** @type {string } */ ( csp . nonce ) ,
424443 env : public_env
425444 } ) ;
0 commit comments