kit
kit copied to clipboard
feat: Introduce SSR context
Closes #10070
Sometimes you need a function defined only in server context – i.e. to log errors inside of SSR. This PR allows one to define context in RequestEvent
as follows:
hooks.server.ts
const handle: Handle = async ({ event, resolve }) => {
const logger = new Logger();
event.context = new Map();
event.context.set('logger', logger);
return await resolve(event);
});
some +page.svelte
import { browser } from '$app/environment';
const logger = browser ? new ClientLogger() : getContext('logger');
logger.info('yes');
Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it solves.
- [ ] Ideally, include a test that fails without this PR but passes with it.
Tests
- [x] Run the tests with
pnpm test
and lint the project withpnpm lint
andpnpm check
Changesets
- [x] If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running
pnpm changeset
and following the prompts. Changesets that add features should beminor
and those that fix bugs should bepatch
. Please prefix changeset messages withfeat:
,fix:
, orchore:
.
🦋 Changeset detected
Latest commit: 0e8fe5f1974dbda27ee1b89b6f2e4f2d4d05d016
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 1 package
Name | Type |
---|---|
@sveltejs/kit | Minor |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
const logger = browser ? new ClientLogger() : getContext('logger');
I feel like there's not enough context here to understand this PR and there should probably be an associated issue. Why can you do new ClientLogger()
but can't do new ServerLogger()
?
@benmccann in case of very simple logging requirements, yes, maybe one can do that. But the moment you will need to transfer such logs to i.e. Sentry, with request context, timings, etc., you will question yourself: why can't you just pass already initialized logger from server side?
Expanding on the example you would have something like this:
hooks.server.ts
const initLogger = async ({ event, resolve }) => {
event.locals.logger = new QuiteComplicatedServerLogger({ endpoint, format, ... });
return await resolve(event);
};
const quiteComplicatedThingWhichRequiresLoggerA = async ({ event, resolve }) => {
try { await explode(); } catch (cause) { event.locals.logger(new Error('Unexpected explosion', { cause })); }
return await resolve(event);
};
const quiteComplicatedThingWhichRequiresLoggerB = ...;
const quiteComplicatedThingWhichRequiresLoggerC = ...;
const handle: Handle = sequence(
initLogger,
quiteComplicatedThingWhichRequiresLoggerA,
quiteComplicatedThingWhichRequiresLoggerB,
quiteComplicatedThingWhichRequiresLoggerC,
async ({ event, resolve }) => {
event.context = new Map();
event.context.set('logger', event.locals.logger);
return await resolve(event);
}
);
Otherwise one would have to pass all options of QuiteComplicatedServerLogger
to svelte code.
So as Svelte has Server-side component API which allows passing context it seemed to us as the most logical choice. If there are other ways to pass functions and/or objects with associated methods into client code during SSR, I'm would gladly learn that.
Coming back to this I still don't know how I feel about this. It's a interesting idea/solution, but it only gets you halfway to where you want - you'd still need to make sure the you setup everything correctly in the caller site. Wondering if there's more that should be added to make this a more complete feature, or if this is a nice low-level building block.