Skip to content

Commit f9458e3

Browse files
authored
fix: include universal load assets as server assets (#13531)
* some type description cleanup * add failing test * fix test * universal load assets are server assets too * changeset * format * regenerate types * we love periods
1 parent fd13f36 commit f9458e3

File tree

9 files changed

+80
-46
lines changed

9 files changed

+80
-46
lines changed

.changeset/dirty-radios-smile.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: include universal load assets as server assets

packages/kit/src/core/generate_manifest/find_server_assets.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export function find_server_assets(build_data, routes) {
4141

4242
for (const n of used_nodes) {
4343
const node = build_data.manifest_data.nodes[n];
44+
if (node?.universal) add_assets(node.universal);
4445
if (node?.server) add_assets(node.server);
4546
}
4647

packages/kit/src/exports/public.d.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,7 +1177,7 @@ export interface RequestEvent<
11771177
* - During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://svelte.dev/docs/kit/hooks#Server-hooks-handle)
11781178
* - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
11791179
*
1180-
* You can learn more about making credentialed requests with cookies [here](https://svelte.dev/docs/kit/load#Cookies)
1180+
* You can learn more about making credentialed requests with cookies [here](https://svelte.dev/docs/kit/load#Cookies).
11811181
*/
11821182
fetch: typeof fetch;
11831183
/**
@@ -1189,23 +1189,23 @@ export interface RequestEvent<
11891189
*/
11901190
locals: App.Locals;
11911191
/**
1192-
* The parameters of the current route - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object
1192+
* The parameters of the current route - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object.
11931193
*/
11941194
params: Params;
11951195
/**
11961196
* Additional data made available through the adapter.
11971197
*/
11981198
platform: Readonly<App.Platform> | undefined;
11991199
/**
1200-
* The original request object
1200+
* The original request object.
12011201
*/
12021202
request: Request;
12031203
/**
1204-
* Info about the current route
1204+
* Info about the current route.
12051205
*/
12061206
route: {
12071207
/**
1208-
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `/blog/[slug]`
1208+
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `/blog/[slug]`.
12091209
*/
12101210
id: RouteId;
12111211
};
@@ -1302,15 +1302,16 @@ export class Server {
13021302
}
13031303

13041304
export interface ServerInitOptions {
1305-
/** A map of environment variables */
1305+
/** A map of environment variables. */
13061306
env: Record<string, string>;
1307-
/** A function that turns an asset filename into a `ReadableStream`. Required for the `read` export from `$app/server` to work */
1307+
/** A function that turns an asset filename into a `ReadableStream`. Required for the `read` export from `$app/server` to work. */
13081308
read?: (file: string) => ReadableStream;
13091309
}
13101310

13111311
export interface SSRManifest {
13121312
appDir: string;
13131313
appPath: string;
1314+
/** Static files from `kit.config.files.assets` and the service worker (if any). */
13141315
assets: Set<string>;
13151316
mimeTypes: Record<string, string>;
13161317

@@ -1321,7 +1322,7 @@ export interface SSRManifest {
13211322
routes: SSRRoute[];
13221323
prerendered_routes: Set<string>;
13231324
matchers: () => Promise<Record<string, ParamMatcher>>;
1324-
/** A `[file]: size` map of all assets imported by server code */
1325+
/** A `[file]: size` map of all assets imported by server code. */
13251326
server_assets: Record<string, number>;
13261327
};
13271328
}
@@ -1452,7 +1453,7 @@ export interface HttpError {
14521453
}
14531454

14541455
/**
1455-
* The object returned by the [`redirect`](https://svelte.dev/docs/kit/@sveltejs-kit#redirect) function
1456+
* The object returned by the [`redirect`](https://svelte.dev/docs/kit/@sveltejs-kit#redirect) function.
14561457
*/
14571458
export interface Redirect {
14581459
/** The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages), in the range 300-308. */

packages/kit/src/types/internal.d.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ export interface BuildData {
6868
out_dir: string;
6969
service_worker: string | null;
7070
client: {
71-
/** Path to the client entry point */
71+
/** Path to the client entry point. */
7272
start: string;
73-
/** Path to the generated `app.js` file that contains the client manifest. Only set in case of `bundleStrategy === 'split'` */
73+
/** Path to the generated `app.js` file that contains the client manifest. Only set in case of `bundleStrategy === 'split'`. */
7474
app?: string;
75-
/** JS files that the client entry point relies on */
75+
/** JS files that the client entry point relies on. */
7676
imports: string[];
7777
/**
7878
* JS files that represent the entry points of the layouts/pages.
@@ -95,7 +95,7 @@ export interface BuildData {
9595
stylesheets: string[];
9696
fonts: string[];
9797
uses_env_dynamic_public: boolean;
98-
/** Only set in case of `bundleStrategy === 'inline'` */
98+
/** Only set in case of `bundleStrategy === 'inline'`. */
9999
inline?: {
100100
script: string;
101101
style: string | undefined;
@@ -172,14 +172,15 @@ export class InternalServer extends Server {
172172
options: RequestOptions & {
173173
prerendering?: PrerenderOptions;
174174
read: (file: string) => Buffer;
175-
/** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated */
175+
/** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated. */
176176
before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
177177
emulator?: Emulator;
178178
}
179179
): Promise<Response>;
180180
}
181181

182182
export interface ManifestData {
183+
/** Static files from `kit.config.files.assets`. */
183184
assets: Asset[];
184185
hooks: {
185186
client: string | null;
@@ -193,15 +194,15 @@ export interface ManifestData {
193194

194195
export interface PageNode {
195196
depth: number;
196-
/** The +page/layout.svelte */
197+
/** The `+page/layout.svelte`. */
197198
component?: string; // TODO supply default component if it's missing (bit of an edge case)
198-
/** The +page/layout.js/.ts */
199+
/** The `+page/layout.js/.ts`. */
199200
universal?: string;
200-
/** The +page/layout.server.js/ts */
201+
/** The `+page/layout.server.js/ts`. */
201202
server?: string;
202203
parent_id?: string;
203204
parent?: PageNode;
204-
/** Filled with the pages that reference this layout (if this is a layout) */
205+
/** Filled with the pages that reference this layout (if this is a layout). */
205206
child_pages?: PageNode[];
206207
}
207208

@@ -219,6 +220,7 @@ export interface PrerenderOptions {
219220
export type RecursiveRequired<T> = {
220221
// Recursive implementation of TypeScript's Required utility type.
221222
// Will recursively continue until it reaches a primitive or Function
223+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
222224
[K in keyof T]-?: Extract<T[K], Function> extends never // If it does not have a Function type
223225
? RecursiveRequired<T[K]> // recursively continue through.
224226
: T[K]; // Use the exact type for everything else
@@ -305,20 +307,20 @@ export interface ServerDataChunkNode {
305307

306308
/**
307309
* Signals that the server `load` function was not run, and the
308-
* client should use what it has in memory
310+
* client should use what it has in memory.
309311
*/
310312
export interface ServerDataSkippedNode {
311313
type: 'skip';
312314
}
313315

314316
/**
315-
* Signals that the server `load` function failed
317+
* Signals that the server `load` function failed.
316318
*/
317319
export interface ServerErrorNode {
318320
type: 'error';
319321
error: App.Error;
320322
/**
321-
* Only set for HttpErrors
323+
* Only set for HttpErrors.
322324
*/
323325
status?: number;
324326
}
@@ -338,7 +340,7 @@ export interface ServerMetadataRoute {
338340

339341
export interface ServerMetadata {
340342
nodes: Array<{
341-
/** Also `true` when using `trailingSlash`, because we need to do a server request in that case to get its value */
343+
/** Also `true` when using `trailingSlash`, because we need to do a server request in that case to get its value. */
342344
has_server_load: boolean;
343345
}>;
344346
routes: Map<string, ServerMetadataRoute>;
@@ -364,15 +366,15 @@ export type SSRComponentLoader = () => Promise<SSRComponent>;
364366

365367
export interface SSRNode {
366368
component: SSRComponentLoader;
367-
/** index into the `nodes` array in the generated `client/app.js` */
369+
/** index into the `nodes` array in the generated `client/app.js`. */
368370
index: number;
369371
/** external JS files that are loaded on the client. `imports[0]` is the entry point (e.g. `client/nodes/0.js`) */
370372
imports: string[];
371373
/** external CSS files that are loaded on the client */
372374
stylesheets: string[];
373375
/** external font files that are loaded on the client */
374376
fonts: string[];
375-
/** inlined styles */
377+
/** inlined styles. */
376378
inline_styles?(): MaybePromise<Record<string, string>>;
377379

378380
universal: {
@@ -465,18 +467,18 @@ export interface SSRState {
465467
fallback?: string;
466468
getClientAddress(): string;
467469
/**
468-
* True if we're currently attempting to render an error page
470+
* True if we're currently attempting to render an error page.
469471
*/
470472
error: boolean;
471473
/**
472-
* Allows us to prevent `event.fetch` from making infinitely looping internal requests
474+
* Allows us to prevent `event.fetch` from making infinitely looping internal requests.
473475
*/
474476
depth: number;
475477
platform?: any;
476478
prerendering?: PrerenderOptions;
477479
/**
478480
* When fetching data from a +server.js endpoint in `load`, the page's
479-
* prerender option is inherited by the endpoint, unless overridden
481+
* prerender option is inherited by the endpoint, unless overridden.
480482
*/
481483
prerender_default?: PrerenderOption;
482484
read?: (file: string) => Buffer;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @ts-expect-error we need both queries to prevent Vite from inlining the asset as base64 string on build
2+
// see https://github.com/vitejs/vite/issues/19562
3+
import asset from './example.json?url&no-inline';
4+
5+
export async function load({ fetch }) {
6+
const res = await fetch(asset);
7+
const data = await res.json();
8+
return data;
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
export let data;
3+
</script>
4+
5+
<p>{data.a}</p>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"a": "1"
3+
}

packages/kit/test/apps/basics/test/server.test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,11 @@ test.describe('Load', () => {
477477
expect(await response.text()).toContain('status: 404');
478478
});
479479

480+
test('fetch reads universal load assets on the server', async ({ page }) => {
481+
await page.goto('/load/fetch-asset');
482+
await expect(page.locator('p')).toHaveText('1');
483+
});
484+
480485
test('includes origin header on non-GET internal request', async ({ page, baseURL }) => {
481486
await page.goto('/load/fetch-origin-internal');
482487
expect(await page.textContent('h1')).toBe(`origin: ${new URL(baseURL).origin}`);

0 commit comments

Comments
 (0)