0

The env:

  • sveltekit 1.20.4
  • svelte 4.0.5
  • vite
  • adapter-node

How do I run startup code, before the server starts handling requests? I need to start multiple services before a single request is handled, and for it to happen when I start the server, not when the first hook runs in hooks.server.js. I tried putting some init functions outside the handle hook but then they run during build because of ESmodules/tree shaking.

Edit: Elaborating a bit, since it isn't very obvious what the implications are. Assuming the goal is to have a DB class you can import and use anywhere in the project, so within a +server.js file for example, you'd import the class and init() it somewhere. If the startup script is meant to init(), then it can't be part of the build process, because the build will run the top level code and try to establish connections. It not being part of the build process means I can't just `import db from 'db'; because the output of the build generates dozens of chunk files which won't be in the correct locations, or have the same name as before.

hooks.server.js

import db from 'db';
import redis from 'redis';
import wss from 'websocket';

const runAllTheInitFunctions = async () => {
    await db.init();
    ...
}

await runAllTheInitFunctions(); // Can't go here, so... where?

/** @type {import('@sveltejs/kit').Handle} */
export const handle = async ({ event, resolve }) => {
    ...
}

I must be missing something obvious, so hopefully someone has found an elegant solution aside from checking init on every handle(). Thank you in advance.

LAZ
  • 402
  • 4
  • 15

2 Answers2

2

Somehow missed this in the docs after reading them over multiple times. Found a reference to it in a git issue.

https://kit.svelte.dev/docs/building-your-app#during-the-build

The answer is I run the code exactly like before, at the top of my hooks.server.js file, but adding a check to see if it's running within a build:

import db from 'db';
import redis from 'redis';
import wss from 'websocket';
import { building } from '$app/environment'; // <---- here

const runAllTheInitFunctions = async () => {
    await db.init();
    ...
}

if (!building) {                             // <---- here
    await runAllTheInitFunctions();
}

/** @type {import('@sveltejs/kit').Handle} */
export const handle = async ({ event, resolve }) => {
    ...
}
LAZ
  • 402
  • 4
  • 15
0

The Node adapter generates a middleware handler, so you could just set up a server script that contains your startup logic and uses the handler.

Abridged example from docs:

import { handler } from './build/handler.js';
import express from 'express';
 
const app = express();
app.use(handler); 
app.listen(3000, () => {
  console.log('listening on port 3000');
});
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • I might be misunderstanding, but doesn't this sidestep the polka server sveltekit ships with? And also if I want to import the DB and init for it to be accessible within the sveltekit app, I don't know what file that would be among the dozens of chunks generated by the build. Thinking along the lines of a DB singleton any part of the app can import and use. – LAZ Aug 22 '23 at 01:20
  • Side-stepping the default server is the whole point, so you can do whatever you want. All the SvelteKit logic is contained in the handler. As for making things available everywhere: Every module is a singleton, so if you export a value/class instance from one, you could initialize it in the startup script and should be able use it anywhere it just via importing. – H.B. Aug 22 '23 at 01:26
  • How do I import it though, the db class is in my sveltekit libs, it goes through the build process and comes out completely different. I can import it easily if the startup script is also part of the libs, but if I do that the startup script's top level code will run during build, and error because it can't create a connection pool during build. – LAZ Aug 22 '23 at 01:31
  • 1
    You could potentially build it into a separate package and import it both in the SvelteKit code itself and the server. The solution you found is definitely more straightforward. – H.B. Aug 22 '23 at 07:48
  • I like that idea since I could reuse my homebrew database package in other projects and have them versioned. So there's two elegant solutions. – LAZ Aug 22 '23 at 14:41