kit icon indicating copy to clipboard operation
kit copied to clipboard

feat: Introduce SSR context

Open secondfry opened this issue 1 year ago • 3 comments

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 with pnpm lint and pnpm 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 be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

secondfry avatar May 30 '23 17:05 secondfry

🦋 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

changeset-bot[bot] avatar May 30 '23 17:05 changeset-bot[bot]

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 avatar May 30 '23 20:05 benmccann

@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.

secondfry avatar May 31 '23 13:05 secondfry

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.

dummdidumm avatar Jul 04 '23 08:07 dummdidumm