kit
kit copied to clipboard
sveltekit nodejs adapter: Allow passing config.kit.paths.assets dynamically from environment variable
Describe the problem
Hi,
We're building SvelteKit app into a Docker image using SvelteKit Node.js adapter.
We'd like to use a single Docker image in all environments but set a different CDN URL (config.kit.paths.assets) based on where it runs (dev/staging/production; different production AWS regions around the World).
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: preprocess(),
kit: {
paths: {
assets: "\${process.env.CDN_URL}",
},
adapter: node({
out: 'build',
precompress: true,
envPrefix: '',
}),
},
};
When we tried to set config.kit.paths.assets to a dynamic value like this, the build failed on validation
Error: config.kit.paths.assets option must be an absolute path, if specified. See https://kit.svelte.dev/docs/configuration#paths
Describe the proposed solution
We'd like to relax config.kit.paths.assets validation (https://kit.svelte.dev/docs/configuration#paths) to allows dynamic values like "${process.env.CDN_URL}", that can be resolved in the runtime by Node.
We'd like to pass this CDN_URL environment variable to the Docker (Kubernetes) container in the runtime based on where it runs.
Alternatives considered
- A global CDN URL. This is not something our customer allows.
- Run
sedreplacement during the container boot time. This might work but feels too brittle.
Importance
would make my life easier
Additional Information
No response
"\${process.env.CDN_URL}" Is this correct syntax?
You may have to use dotenv to pull in your env variables in the svelteconfig file
so something like this
/** @type {import('@sveltejs/kit').Config} */
import * as dotenv from 'dotenv'
dotenv.config()
const config = {
preprocess: preprocess(),
kit: {
paths: {
assets: `${process.env.CDN_URL}`,
},
adapter: node({
out: 'build',
precompress: true,
envPrefix: '',
}),
},
};
@tcherokee this would still compile Svelte app with the value of the ${process.env.CDN_URL}, if I understand correctly.
What I'm asking for is to let Svelte read the value from env var in the runtime (rather than in build time).
This is a pattern I’ve seen used frequently at it seems pretty fundamental from an ops perspective. Otherwise anytime we redeploy the app with different configuration, we need to rebuild the release. That’s a hard regression. 12 factor app has a principle devoted to this. It helps accelerate the dev to ops handoff on our team. Please consider this a priority if possible… this was a source of lots of head scratching today. We use this pattern to facilitate OIDC client secrets and AES encryption keys on the server. Super important these are never added to the build and are always configured at runtime.
Can't you set paths.assets: '__assets__', and do transformPageChunk: ({ html }) => html.replace('__assets__', env.CDN_URL) in handle?
I'm doing something similar but I'm loading the handle middleware from the node adapter into an existing express app and apply the string-replace-middleware to replace the placeholder with an actual value.
This would be very helpful for us. Our deployment pipelines look like:
- Build/Test/Deploy Staging a. Build Docker image b. Run tests on container c. Deploy container to staging env
- Deploy Production a. Deploy container to production env
This ensures that what we're deploying to production is exactly what we see on staging, with environment variables specifying any environment-specific differences in app behavior.
We're able to work around this with a custom vite plugin and vite's experimental renderBuiltUrl option to set the asset path dynamically, but it's quite hacky ad prone to breakage on sveltekit/vite version updates. Using string-replace-middleware or similar doesn't work for us because the assets path is present in some of the built client assets that we're serving via CDN.
The option to set the assets path using an environment variable at runtime, allowing us to specify a function that returns an asset path at runtime, etc. would all be good solutions for our use-case.