diff --git a/.changeset/curvy-students-march.md b/.changeset/curvy-students-march.md new file mode 100644 index 000000000000..f413cf8e53c3 --- /dev/null +++ b/.changeset/curvy-students-march.md @@ -0,0 +1,10 @@ +--- +'@sveltejs/adapter-cloudflare': patch +'@sveltejs/adapter-cloudflare-workers': patch +'@sveltejs/adapter-netlify': patch +'@sveltejs/adapter-node': patch +'@sveltejs/adapter-vercel': patch +'@sveltejs/kit': patch +--- + +[feat] Moved hooks.js initialization from Server.respond into Server.init diff --git a/packages/adapter-cloudflare-workers/files/entry.js b/packages/adapter-cloudflare-workers/files/entry.js index 0646c7acc380..fe1c45a246ea 100644 --- a/packages/adapter-cloudflare-workers/files/entry.js +++ b/packages/adapter-cloudflare-workers/files/entry.js @@ -15,7 +15,7 @@ export default { * @param {any} context */ async fetch(req, env, context) { - server.init({ env }); + await server.init({ env }); const url = new URL(req.url); diff --git a/packages/adapter-cloudflare/src/worker.js b/packages/adapter-cloudflare/src/worker.js index 20993ee11beb..a31267aef944 100644 --- a/packages/adapter-cloudflare/src/worker.js +++ b/packages/adapter-cloudflare/src/worker.js @@ -9,7 +9,7 @@ const prefix = `/${manifest.appDir}/`; /** @type {import('worktop/cfw').Module.Worker<{ ASSETS: import('worktop/cfw.durable').Durable.Object }>} */ const worker = { async fetch(req, env, context) { - server.init({ env }); + await server.init({ env }); // skip cache if "cache-control: no-cache" in request let pragma = req.headers.get('cache-control') || ''; let res = !pragma.includes('no-cache') && (await Cache.lookup(req)); diff --git a/packages/adapter-netlify/src/serverless.js b/packages/adapter-netlify/src/serverless.js index aec29eef562a..f898796b8902 100644 --- a/packages/adapter-netlify/src/serverless.js +++ b/packages/adapter-netlify/src/serverless.js @@ -9,11 +9,16 @@ import { split_headers } from './headers'; export function init(manifest) { const server = new Server(manifest); - server.init({ + let init_promise = server.init({ env: process.env }); return async (event, context) => { + if (init_promise !== null) { + await init_promise; + init_promise = null; + } + const response = await server.respond(to_request(event), { platform: { context }, getClientAddress() { diff --git a/packages/adapter-node/src/handler.js b/packages/adapter-node/src/handler.js index e5e67bfa3af9..d90bce52d996 100644 --- a/packages/adapter-node/src/handler.js +++ b/packages/adapter-node/src/handler.js @@ -11,7 +11,7 @@ import { env } from './env.js'; /* global ENV_PREFIX */ const server = new Server(manifest); -server.init({ env: process.env }); +await server.init({ env: process.env }); const origin = env('ORIGIN', undefined); const xff_depth = parseInt(env('XFF_DEPTH', '1')); diff --git a/packages/adapter-node/tsconfig.json b/packages/adapter-node/tsconfig.json index 89ca95cf92bd..63ea97316689 100644 --- a/packages/adapter-node/tsconfig.json +++ b/packages/adapter-node/tsconfig.json @@ -6,7 +6,8 @@ "noImplicitAny": true, "allowSyntheticDefaultImports": true, "moduleResolution": "node", - "module": "es2020", + "module": "es2022", + "target": "es2017", "baseUrl": ".", "paths": { "@sveltejs/kit": ["../kit/types/index"] diff --git a/packages/adapter-vercel/files/serverless.js b/packages/adapter-vercel/files/serverless.js index 639275b9b7a1..c647fd8b1f9b 100644 --- a/packages/adapter-vercel/files/serverless.js +++ b/packages/adapter-vercel/files/serverless.js @@ -7,7 +7,7 @@ installPolyfills(); const server = new Server(manifest); -server.init({ +await server.init({ env: process.env }); diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js index a2cfbd79c118..410aa0e5bbc4 100644 --- a/packages/kit/src/core/prerender/prerender.js +++ b/packages/kit/src/core/prerender/prerender.js @@ -15,7 +15,7 @@ import { load_config } from '../config/index.js'; * @typedef {import('types').Logger} Logger */ -const [, , client_out_dir, results_path, manifest_path, verbose] = process.argv; +const [, , client_out_dir, results_path, manifest_path, verbose, env] = process.argv; prerender(); @@ -159,6 +159,7 @@ export async function prerender() { }); const server = new Server(manifest); + await server.init({ env: JSON.parse(env) }); const error = normalise_error_handler(log, config); diff --git a/packages/kit/src/vite/build/build_server.js b/packages/kit/src/vite/build/build_server.js index 793179b1c9f2..d2124e4f8308 100644 --- a/packages/kit/src/vite/build/build_server.js +++ b/packages/kit/src/vite/build/build_server.js @@ -84,7 +84,12 @@ export class Server { }; } - init({ env }) { + /** + * Take care: Some adapters may have to call \`Server.init\` per-request to set env vars, + * so anything that shouldn't be rerun should be wrapped in an \`if\` block to make sure it hasn't + * been done already. + */ + async init({ env }) { const entries = Object.entries(env); const prv = Object.fromEntries(entries.filter(([k]) => !k.startsWith('${ @@ -99,12 +104,6 @@ export class Server { set_public_env(pub); this.options.public_env = pub; - } - - async respond(request, options = {}) { - if (!(request instanceof Request)) { - throw new Error('The first argument to server.respond must be a Request object. See https://github.com/sveltejs/kit/pull/3384 for details'); - } if (!this.options.hooks) { const module = await import(${s(hooks)}); @@ -114,6 +113,12 @@ export class Server { externalFetch: module.externalFetch || fetch }; } + } + + async respond(request, options = {}) { + if (!(request instanceof Request)) { + throw new Error('The first argument to server.respond must be a Request object. See https://github.com/sveltejs/kit/pull/3384 for details'); + } return respond(request, this.options, options); } diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js index 7f6e74bc32fe..c6ecdb9ef889 100644 --- a/packages/kit/src/vite/index.js +++ b/packages/kit/src/vite/index.js @@ -411,7 +411,13 @@ function kit() { const child = fork( script, - [vite_config.build.outDir, results_path, manifest_path, '' + verbose], + [ + vite_config.build.outDir, + results_path, + manifest_path, + '' + verbose, + JSON.stringify({ ...env.private, ...env.public }) + ], { stdio: 'inherit' } diff --git a/packages/kit/src/vite/preview/index.js b/packages/kit/src/vite/preview/index.js index 56c47191360e..561d22cb1e36 100644 --- a/packages/kit/src/vite/preview/index.js +++ b/packages/kit/src/vite/preview/index.js @@ -45,7 +45,7 @@ export async function preview(vite, vite_config, svelte_config) { }); const server = new Server(manifest); - server.init({ + await server.init({ env: loadEnv(vite_config.mode, process.cwd(), '') }); diff --git a/packages/kit/test/apps/basics/src/hooks.js b/packages/kit/test/apps/basics/src/hooks.js index d6b9caa9d274..fe4b94752d81 100644 --- a/packages/kit/test/apps/basics/src/hooks.js +++ b/packages/kit/test/apps/basics/src/hooks.js @@ -1,6 +1,6 @@ import fs from 'fs'; import cookie from 'cookie'; -import { sequence } from '../../../../src/hooks'; +import { sequence } from '@sveltejs/kit/hooks'; /** @type {import('@sveltejs/kit').HandleError} */ export const handleError = ({ event, error }) => { diff --git a/packages/kit/test/prerendering/basics/.env b/packages/kit/test/prerendering/basics/.env new file mode 100644 index 000000000000..1597af1243ec --- /dev/null +++ b/packages/kit/test/prerendering/basics/.env @@ -0,0 +1,5 @@ +PRIVATE_STATIC="accessible to server-side code/replaced at build time" +PRIVATE_DYNAMIC="accessible to server-side code/evaluated at run time" + +PUBLIC_STATIC="accessible anywhere/replaced at build time" +PUBLIC_DYNAMIC="accessible anywhere/evaluated at run time" diff --git a/packages/kit/test/prerendering/basics/.gitignore b/packages/kit/test/prerendering/basics/.gitignore new file mode 100644 index 000000000000..1e18f275e97c --- /dev/null +++ b/packages/kit/test/prerendering/basics/.gitignore @@ -0,0 +1 @@ +!.env \ No newline at end of file diff --git a/packages/kit/test/prerendering/basics/src/routes/env/+page.server.js b/packages/kit/test/prerendering/basics/src/routes/env/+page.server.js new file mode 100644 index 000000000000..617a8542fd21 --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/env/+page.server.js @@ -0,0 +1,9 @@ +import { PRIVATE_STATIC } from '$env/static/private'; +import { env } from '$env/dynamic/private'; + +export function load() { + return { + PRIVATE_STATIC, + PRIVATE_DYNAMIC: env.PRIVATE_DYNAMIC + }; +} diff --git a/packages/kit/test/prerendering/basics/src/routes/env/+page.svelte b/packages/kit/test/prerendering/basics/src/routes/env/+page.svelte new file mode 100644 index 000000000000..4ee2f424da67 --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/env/+page.svelte @@ -0,0 +1,13 @@ + + +

PRIVATE_STATIC: {data.PRIVATE_STATIC}

+

PRIVATE_DYNAMIC: {data.PRIVATE_DYNAMIC}

+ +

PUBLIC_STATIC: {PUBLIC_STATIC}

+

PUBLIC_DYNAMIC: {env.PUBLIC_DYNAMIC}

diff --git a/packages/kit/test/prerendering/basics/test/test.js b/packages/kit/test/prerendering/basics/test/test.js index 280a862864a1..b38c6ab6503c 100644 --- a/packages/kit/test/prerendering/basics/test/test.js +++ b/packages/kit/test/prerendering/basics/test/test.js @@ -190,4 +190,19 @@ test('respects config.prerender.origin', () => { assert.ok(content.includes('

http://example.com

')); }); +test('$env - includes environment variables', () => { + const content = read('env.html'); + + assert.match( + content, + /.*PRIVATE_STATIC: accessible to server-side code\/replaced at build time.*/gs + ); + assert.match( + content, + /.*PRIVATE_DYNAMIC: accessible to server-side code\/evaluated at run time.*/gs + ); + assert.match(content, /.*PUBLIC_STATIC: accessible anywhere\/replaced at build time.*/gs); + assert.match(content, /.*PUBLIC_DYNAMIC: accessible anywhere\/evaluated at run time.*/gs); +}); + test.run(); diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index a38968f52634..260cdfc00350 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -264,7 +264,7 @@ export interface ResolveOptions { export class Server { constructor(manifest: SSRManifest); - init(options: ServerInitOptions): void; + init(options: ServerInitOptions): Promise; respond(request: Request, options: RequestOptions): Promise; } diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts index 1d870c4ba64f..5e8376edbbce 100644 --- a/packages/kit/types/internal.d.ts +++ b/packages/kit/types/internal.d.ts @@ -94,7 +94,7 @@ export interface ImportNode { } export class InternalServer extends Server { - init(options: ServerInitOptions): void; + init(options: ServerInitOptions): Promise; respond( request: Request, options: RequestOptions & {