#Runtime environment variables for configuration files (astro.config.mjs) on SSR

17 messages · Page 1 of 1 (latest)

cedar sigil
#

Hey guys, I have bumped into a problem with runtime variables in the Kubernetes infrastructure. I would like to have the same build (Docker image) but run it with different set of variables WITHOUT .env file. The Kubernetes manages to inject those.
It all works with

vite: {
  define: {
    'import.meta.env.MY_RUNTIME_VARIABLE': 'process.env.MY_RUNTIME_VARIABLE',
    ...
  },
}

So all in-app (.astro and the .js|ts files imported to astro files) are successfully runtime.

But...,
It does not work with the configuration files!
As official docs says, the configuration files are first even before other files being loaded https://docs.astro.build/en/guides/configuring-astro/#environment-variables, so VITE does not exist there yet.

Is there any way to make different configuration in a same build. Basically I need to achieve, that dist js files would have process.env.* instead of actual secret hardcoded during build time.. And I would like to avoid making 2 builds for different purposes.

Astro Documentation

Build faster websites with less client-side JavaScript.

earnest vortexBOT
#
No-one around right now?

It looks like no-one has responded to your question yet. People might not be available right now or don’t know how to answer your question. Want an answer while you wait? Try asking our experimental bot in #1095492539085230272.

cedar sigil
#

@clear cobalt super sorry for direct ping 🙏 I am curious is there any way to have runtime variables in the configuration files (astro.config.mjs) so we could use build for kubernetes without physical .env(which is not recommended) but with their native process.env.* variables injection.

It seems Astro evaluates configuration files and hardcodes the values in-place, so I cannot use those as runtime variables after I ship the build to docker. Is there any way to change evaluation step behaviour, something similar fashion as vite.define does?

Are there any plans in regards to making runtime variables possible in configuration files?

clear cobalt
cedar sigil
# clear cobalt I'm not totally sure I follow... The config file isn't bundled into the final bu...

Hey, yes, and it is, but the problem is that the process.envs are replaced during build time, so they do have final values, whereas we need them not to be replaced and left out to be runtime ones in the dist, because dist is used as docker image later where .env file does not exist at all. This can rasily be achieved with vite.define, but only for the source code, and not configuration files as neither Vite/Rollup nor any builder exists at that early stage.

#

Hope that makes sense 🙂

clear cobalt
#

Ah I am really struggling to grok this! Are you just asking for import.meta.env to always be replaced with the dynamic process.env values? I'm not getting where the config file comes into this

#

For the record, my coffee hasn't kicked in yet! 😆

cedar sigil
#

Huh, yeah, its a tricky bit to start the day 😀 To give a little more context, in the kube world having .env shipped with the image is not a good practice, we rather replace envs in runtime. The Docker usually replaces any occurencies like process.env.* with the actual values from its Secrets list passed externally from configuration, just right before starting a pod (server).
The challenge here is to make sure the Astro build code still contains the process.env.* placeholders and not the finalized values.
That is trully achievable in the .astro files as we have Vite available there so we can control the output of each code chunk.
Therefore it is not possible to do the same in astro.config.mjs and any other js configuration file imported to it.

After some more digging I came up with similar approach as Vite Define plugin does: https://github.com/vitejs/vite/blob/e3db7712657232fbb9ea2499a2c6f277d2bb96a3/packages/vite/src/node/plugins/define.ts#L65
What I do is basically the postprocessing after the Astro build output to replace the placeholders in the dist code, which is rather hacky solution to go with.
If there would be at least any kind of preprocessing in those configurstion files, maybe it would be possible to make this natively.
But its a challenge.

Hope this sheds some more light to the topic..

GitHub

Next generation frontend tooling. It's fast! Contribute to vitejs/vite development by creating an account on GitHub.

#

Alternative way to this whole thing would be to build as many builds as neede and use different one in different servers (review, staging, production) as it has slightly different configurations with storyblok/astro integration.
But building many images just for the sake of different configs is huge overhead tbh.

clear cobalt
#

Therefore it is not possible to do the same in astro.config.mjs and any other js configuration file imported to it.
This is the part I'm confused about! If you want the process.env.* placeholders in your code, why can't you just write process.env.* in your astro.config.mjs file?

#

I'm not sure why you need to preprocess/bundle those files, they are just plain JavaScript that runs in Node

cedar sigil
clear cobalt
#

Sounds like the values are just not on process.env? Those need to be handled during runtime somehow. MY_VALUE=secret astro build would work?

#

Ohhhh wait I think I understand. Rather than inlining undefined we should be in lining the process.env declaration

#

Sorry that took me so long to wrap my head around! I see the problem

cedar sigil
#

Ok, I found out some more stuff. There are limitations and showstoppers.
Apparently my solution would apply only to the "client" code (configuration values which are transferred to actual app code) which is included in the dist while there are quite many other decisions which are done ONLY during astro build, such as an integration logic whether to include some script (injectScript) or not.. and that decision-making could not be part of the deliverable for sure.. This seems the end of all this research 🙂 We can control the behaviour of the injected script as part of the app logic, but we cannot control the inclusion/exclusion of the script dynamically, because such decisions happens only during the build time, that forces us to do multiple builds.
Hope it rings a bell :))

It seems there is no other way to solve my usecase than doing couple separate dist with different setup.