The easiest way of using Svelte for SSR in Node is by using svelte/register
. This allows to require .svelte
files without any bundling and render HTML, CSS, etc.
This is the example from the docs:
require('svelte/register');
const App = require('./App.svelte').default;
const { html, css, head } = App.render({ answer: 42 });
If you do this in a Vercel serverless function it will work great locally while using vercel dev
. However, once you deploy your function, it will break.
I'm not a Vercel expert, but this is how I've solved it.
It seems Vercel does some optimizations to reduce the size of the deployed functions so that only the required dependencies are bundled. It seems when doing require('svelte/register')
Vercel will not bundle the complete svelte
module and only the svelte/register
folder. You function will break with this error:
Cannot find module '/var/task/node_modules/svelte/internal/index.js'
The solution is to do a dumb require of the whole module so that it gets bundled with your function:
require('svelte');
require('svelte/register');
Vercel will include all the .svelte
files that you require in your functions, but it will ignore all the subsequent imports in your .svelte
files. Svelte sub components that are not directly required in your serverless functions will not be bundled and your function will break.
The solution is simply to use the includeFiles
directive in your vercel.json
file:
{
"functions": {
"api/svelte-render.js": {
"includeFiles": "api/_svelte/**"
}
}
}
require('svelte');
require('svelte/register');
const Page = require('./_svelte/Page.svelte').default;
module.exports = async (request, response) => {
const { html, css, head } = Page.render({});
const fullHtml = `
<!DOCTYPE html>
<html>
<body>
${html}
</body>
</html>
`;
response.setHeader('content-type', 'text/html; charset=UTF-8');
response.send(fullHtml);
}
Any reason not to just use SvelteKit? This works zero-config 😄
https://vercel.com/changelog/sveltekit-projects-can-now-be-deployed-with-zero-configuration