【Svelte】如何实现多个钩子?
在 src/hooks.server.ts 中如何实现多个钩子?答案是使用sequence,具体如下:
In SvelteKit 5, the recommended way to combine multiple handle hooks is to use the sequence helper from @sveltejs/kit/hooks.
Here’s how you can combine your two hooks:
- Import
sequence: Addimport { sequence } from '@sveltejs/kit/hooks';to your file. - Rename individual hooks: Give your existing
handlefunctions unique names (e.g.,handleParaglideandhandleTheme). - Export the sequence: Use
export const handle = sequence(hook1, hook2, ...);
Here’s the combined src/hooks.server.ts file:
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks'; // Import the sequence helper// --- Imports for your existing hooks ---
import { paraglideMiddleware } from '$lib/paraglide/server';
import { themes } from '$lib/themes';
// ---------------------------------------// Hook 1: Paraglide Internationalization
const handleParaglide: Handle = async ({ event, resolve }) => {// paraglideMiddleware takes the original request and a callback.// The callback receives the modified request and the detected locale.// It's crucial to update `event.request` here if `paraglideMiddleware` modifies it.return paraglideMiddleware(event.request, ({ request, locale }) => {event.request = request; // Update the event.request for subsequent hooks or SvelteKit itself// Resolve the request, applying the paraglide-specific HTML transformationreturn resolve(event, {transformPageChunk: ({ html }) => html.replace('%paraglide.lang%', locale)});});
};// Hook 2: Theme Handling
const handleTheme: Handle = async ({ event, resolve }) => {const theme = event.cookies.get('theme');// If no theme is set or it's an invalid theme, just proceed without transformationif (!theme || !themes.includes(theme)) {return await resolve(event);}// If a valid theme is found, resolve with the theme-specific HTML transformationreturn await resolve(event, {transformPageChunk: ({ html }) => {// Replace the data-theme attribute in the HTMLreturn html.replace('data-theme=""', `data-theme="${theme}"`);},});
};// Combine the hooks using `sequence`.
// The order matters:
// - `handleParaglide` should come first because it modifies `event.request`
// and sets the locale, which might be needed by other parts of your app.
// - `transformPageChunk` from `handleParaglide` will be applied BEFORE `handleTheme`'s
// transform, which generally makes sense (replace a generic placeholder first, then
// apply a more specific dynamic attribute).
export const handle: Handle = sequence(handleParaglide, handleTheme);
Explanation:
sequenceHelper: This utility function from SvelteKit allows you to chain multipleHandlefunctions together. It makes sure each hook runs in the specified order.event.requestModification: YourhandleParaglidehook modifiesevent.request = request;. When usingsequence, if a hook modifiesevent.request(orevent.locals), those changes are passed down to subsequent hooks in the sequence. This is whyhandleParaglideshould come first if it modifies the request object.resolveandtransformPageChunk:- Each hook in the sequence receives a
resolvefunction. Thisresolvefunction will either call the next hook in the sequence or, if it’s the last hook, the default SvelteKit page renderer. - When you pass
transformPageChunktoresolve, SvelteKit intelligently chains these transformations. IfhandleParaglideprovides atransformPageChunkand thenhandleThemeprovides one, the HTML will first be processed byhandleParaglide’s transformer, and then the result will be processed byhandleTheme’s transformer. This is generally the desired behavior.
- Each hook in the sequence receives a
- Order of Hooks: I’ve placed
handleParaglidefirst. This is crucial because it modifiesevent.request(which containsevent.url,event.headers, etc.) based on the locale. Any subsequent hooks that might read fromevent.request(likehandleThemereading cookies, though cookies aren’t usually affected by locale detection itself) will then receive the potentially updatedevent.request. ThetransformPageChunkorder also aligns with this: generic placeholder replacement, then dynamic attribute replacement.
