Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dirty-radios-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: include universal load assets as server assets
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export function find_server_assets(build_data, routes) {

for (const n of used_nodes) {
const node = build_data.manifest_data.nodes[n];
if (node?.universal) add_assets(node.universal);
if (node?.server) add_assets(node.server);
}

Expand Down
19 changes: 10 additions & 9 deletions packages/kit/src/exports/public.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ export interface RequestEvent<
* - 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)
* - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
*
* You can learn more about making credentialed requests with cookies [here](https://svelte.dev/docs/kit/load#Cookies)
* You can learn more about making credentialed requests with cookies [here](https://svelte.dev/docs/kit/load#Cookies).
*/
fetch: typeof fetch;
/**
Expand All @@ -1189,23 +1189,23 @@ export interface RequestEvent<
*/
locals: App.Locals;
/**
* The parameters of the current route - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object
* The parameters of the current route - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object.
*/
params: Params;
/**
* Additional data made available through the adapter.
*/
platform: Readonly<App.Platform> | undefined;
/**
* The original request object
* The original request object.
*/
request: Request;
/**
* Info about the current route
* Info about the current route.
*/
route: {
/**
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `/blog/[slug]`
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `/blog/[slug]`.
*/
id: RouteId;
};
Expand Down Expand Up @@ -1302,15 +1302,16 @@ export class Server {
}

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

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

Expand All @@ -1321,7 +1322,7 @@ export interface SSRManifest {
routes: SSRRoute[];
prerendered_routes: Set<string>;
matchers: () => Promise<Record<string, ParamMatcher>>;
/** A `[file]: size` map of all assets imported by server code */
/** A `[file]: size` map of all assets imported by server code. */
server_assets: Record<string, number>;
};
}
Expand Down Expand Up @@ -1452,7 +1453,7 @@ export interface HttpError {
}

/**
* The object returned by the [`redirect`](https://svelte.dev/docs/kit/@sveltejs-kit#redirect) function
* The object returned by the [`redirect`](https://svelte.dev/docs/kit/@sveltejs-kit#redirect) function.
*/
export interface Redirect {
/** The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages), in the range 300-308. */
Expand Down
42 changes: 22 additions & 20 deletions packages/kit/src/types/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,24 +68,24 @@ export interface BuildData {
out_dir: string;
service_worker: string | null;
client: {
/** Path to the client entry point */
/** Path to the client entry point. */
start: string;
/** Path to the generated `app.js` file that contains the client manifest. Only set in case of `bundleStrategy === 'split'` */
/** Path to the generated `app.js` file that contains the client manifest. Only set in case of `bundleStrategy === 'split'`. */
app?: string;
/** JS files that the client entry point relies on */
/** JS files that the client entry point relies on. */
imports: string[];
/**
* JS files that represent the entry points of the layouts/pages.
* An entry is undefined if the layout/page has no component or universal file (i.e. only has a `.server.js` file).
* Only set in case of `router.resolution === 'server'`.
*/
nodes?: (string | undefined)[];
nodes?: Array<string | undefined>;
/**
* CSS files referenced in the entry points of the layouts/pages.
* An entry is undefined if the layout/page has no component or universal file (i.e. only has a `.server.js` file) or if has no CSS.
* Only set in case of `router.resolution === 'server'`.
*/
css?: (string[] | undefined)[];
css?: Array<string[] | undefined>;
/**
* Contains the client route manifest in a form suitable for the server which is used for server side route resolution.
* Notably, it contains all routes, regardless of whether they are prerendered or not (those are missing in the optimized server route manifest).
Expand All @@ -95,7 +95,7 @@ export interface BuildData {
stylesheets: string[];
fonts: string[];
uses_env_dynamic_public: boolean;
/** Only set in case of `bundleStrategy === 'inline'` */
/** Only set in case of `bundleStrategy === 'inline'`. */
inline?: {
script: string;
style: string | undefined;
Expand Down Expand Up @@ -172,14 +172,15 @@ export class InternalServer extends Server {
options: RequestOptions & {
prerendering?: PrerenderOptions;
read: (file: string) => Buffer;
/** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated */
/** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated. */
before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
emulator?: Emulator;
}
): Promise<Response>;
}

export interface ManifestData {
/** Static files from `kit.config.files.assets`. */
assets: Asset[];
hooks: {
client: string | null;
Expand All @@ -193,15 +194,15 @@ export interface ManifestData {

export interface PageNode {
depth: number;
/** The +page/layout.svelte */
/** The `+page/layout.svelte`. */
component?: string; // TODO supply default component if it's missing (bit of an edge case)
/** The +page/layout.js/.ts */
/** The `+page/layout.js/.ts`. */
universal?: string;
/** The +page/layout.server.js/ts */
/** The `+page/layout.server.js/ts`. */
server?: string;
parent_id?: string;
parent?: PageNode;
/** Filled with the pages that reference this layout (if this is a layout) */
/** Filled with the pages that reference this layout (if this is a layout). */
child_pages?: PageNode[];
}

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

/**
* Signals that the server `load` function was not run, and the
* client should use what it has in memory
* client should use what it has in memory.
*/
export interface ServerDataSkippedNode {
type: 'skip';
}

/**
* Signals that the server `load` function failed
* Signals that the server `load` function failed.
*/
export interface ServerErrorNode {
type: 'error';
error: App.Error;
/**
* Only set for HttpErrors
* Only set for HttpErrors.
*/
status?: number;
}
Expand All @@ -338,7 +340,7 @@ export interface ServerMetadataRoute {

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

export interface SSRNode {
component: SSRComponentLoader;
/** index into the `nodes` array in the generated `client/app.js` */
/** index into the `nodes` array in the generated `client/app.js`. */
index: number;
/** external JS files that are loaded on the client. `imports[0]` is the entry point (e.g. `client/nodes/0.js`) */
imports: string[];
/** external CSS files that are loaded on the client */
stylesheets: string[];
/** external font files that are loaded on the client */
fonts: string[];
/** inlined styles */
/** inlined styles. */
inline_styles?(): MaybePromise<Record<string, string>>;

universal: {
Expand Down Expand Up @@ -465,18 +467,18 @@ export interface SSRState {
fallback?: string;
getClientAddress(): string;
/**
* True if we're currently attempting to render an error page
* True if we're currently attempting to render an error page.
*/
error: boolean;
/**
* Allows us to prevent `event.fetch` from making infinitely looping internal requests
* Allows us to prevent `event.fetch` from making infinitely looping internal requests.
*/
depth: number;
platform?: any;
prerendering?: PrerenderOptions;
/**
* When fetching data from a +server.js endpoint in `load`, the page's
* prerender option is inherited by the endpoint, unless overridden
* prerender option is inherited by the endpoint, unless overridden.
*/
prerender_default?: PrerenderOption;
read?: (file: string) => Buffer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @ts-expect-error we need both queries to prevent Vite from inlining the asset as base64 string on build
// see https://github.com/vitejs/vite/issues/19562
import asset from './example.json?url&no-inline';

export async function load({ fetch }) {
const res = await fetch(asset);
const data = await res.json();
return data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
export let data;
</script>

<p>{data.a}</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"a": "1"
}
5 changes: 5 additions & 0 deletions packages/kit/test/apps/basics/test/server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,11 @@ test.describe('Load', () => {
expect(await response.text()).toContain('status: 404');
});

test('fetch reads universal load assets on the server', async ({ page }) => {
await page.goto('/load/fetch-asset');
await expect(page.locator('p')).toHaveText('1');
});

test('includes origin header on non-GET internal request', async ({ page, baseURL }) => {
await page.goto('/load/fetch-origin-internal');
expect(await page.textContent('h1')).toBe(`origin: ${new URL(baseURL).origin}`);
Expand Down
Loading
Loading