kit icon indicating copy to clipboard operation
kit copied to clipboard

sveltekit nodejs adapter: Allow passing config.kit.paths.assets dynamically from environment variable

Open VojtechVitek opened this issue 2 years ago • 3 comments

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

  1. A global CDN URL. This is not something our customer allows.
  2. Run sed replacement during the container boot time. This might work but feels too brittle.

Importance

would make my life easier

Additional Information

No response

VojtechVitek avatar Dec 01 '22 15:12 VojtechVitek

"\${process.env.CDN_URL}" Is this correct syntax?

mustofa-id avatar Dec 01 '22 23:12 mustofa-id

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 avatar Dec 20 '22 09:12 tcherokee

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

VojtechVitek avatar Dec 20 '22 14:12 VojtechVitek

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.

cslovell avatar Feb 10 '23 22:02 cslovell

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.

fehnomenal avatar Feb 11 '23 10:02 fehnomenal

This would be very helpful for us. Our deployment pipelines look like:

  1. Build/Test/Deploy Staging a. Build Docker image b. Run tests on container c. Deploy container to staging env
  2. 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.

ncvc avatar Apr 19 '23 15:04 ncvc