trunk icon indicating copy to clipboard operation
trunk copied to clipboard

process.env vars

Open dakom opened this issue 1 year ago • 12 comments

is there a way to set and make these accessible via trunk serve ?

Prior art from NextJS:

In order to make the value of an environment variable accessible in the browser, Next.js can "inline" a value, at build time, into the js bundle that is delivered to the client

dakom avatar Jun 03 '24 13:06 dakom

Doesn't plain env! from Rust work for that?

ctron avatar Jun 03 '24 15:06 ctron

I don't think so, wasm in the browser can only access whatever the JS bindings can, and there's no environment to speak of really. It's not uncommon for bundlers to pass variables into a process.env object so that JS code can work the same as the browser and NodeJS environments. I have a little helper to extract it this way: https://docs.rs/awsm_web/latest/src/awsm_web/env.rs.html#10-18

No strong opinion from me about how Trunk might want to go about this... prior art isn't necessarily the only way to do it :)

for now I'm accomplishing the same thing via feature-gating, but, it would be nicer to be able to avoid that :)

dakom avatar Jun 03 '24 15:06 dakom

This works during compile time: https://doc.rust-lang.org/std/macro.env.html

So when you use:

fn my_foo() -> String {
  env!("MY_FOO").into()
}

And compile it with:

env MY_FOO=bar cargo build

Then my_foo() would return bar.

But that's a plain Rust functionality. I don't think Trunk interferes with that.

ctron avatar Jun 03 '24 15:06 ctron

ah, thanks for pointing that out - yeah I was thinking of env::var for runtime

it's hard to think of a very compelling use-case for needing to access process.env at runtime specifically, closing this issue for now. Thanks!

dakom avatar Jun 03 '24 19:06 dakom

in case anyone else lands here, just a tip -.env isn't loaded out of the box. Instead of having a separate trunk hook, you can load the .env as a cargo build script

Cargo.toml

[build-dependencies]
dotenvy = "0.15.7"

build.rs (next to Cargo.toml, not in src)

use dotenvy::from_filename_iter;

fn main() {
    // Attempt to read the .env file
    if let Ok(iter) = from_filename_iter(".env") {
        for item in iter {
            match item {
                Ok((key, value)) => {
                    // Set the environment variable for the compiler
                    println!("cargo:rustc-env={}={}", key, value);
                }
                Err(err) => {
                    // Handle parsing errors (e.g., invalid lines in .env)
                    eprintln!("Warning: Failed to parse .env entry: {}", err);
                }
            }
        }
    } else {
        // .env file is missing; this is not an error
        println!("cargo:warning=.env file not found. Skipping environment variable loading.");
    }
}

dakom avatar Sep 26 '24 15:09 dakom

@ctron after using this for a while, I think this is a worthwhile feature request, so re-opening for now.

The real-world problem is when I do nothing other than change the .env and re-run trunk serve, I run into cache problems. The answer to this, as far as I can tell, gets even nastier than the already-not-ideal stuff above: https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-env-changed

Altogether it would be MUCH nicer to not have to worry about any of this. As a user, I'd want Trunk to deal with injecting env vars, application code can just read it at runtime (yes by reaching out into JS like above) - that way I can just start/stop trunk and get the new vars without rebuilding any of the Rust stuff

As noted at the top of the issue, this is available in other frameworks such as NextJS, I think it's genuinely a lacking feature at the moment.

dakom avatar Oct 22 '24 08:10 dakom

Hm. I am still not sure I understand what trunk should exactly do here? Re-reading the .env file during runtime?

ctron avatar Oct 25 '24 09:10 ctron

My ideal would be for it to inject into a JS object (e.g. process.env). I think that's when Next/Vercel does.

Both serve and build would do this- effectively if you edit something in your environment vars, and restart the dev server (or rebuild the final bundle), you see the new vars, even if the Rust code didn't change/rebuild at all

For the sake of not accidentally exposing sensitive vars, the actual vars can be allowlisted in Trunk.toml, rather than just read from all env vars

In terms of getting from a .env file into the environment- yes, it would also be nice for Trunk to do this step, but they are two separate things (e.g. env vars could also be populated via CI or something)

dakom avatar Oct 25 '24 10:10 dakom

Ok, just summing this up, the idea is to:

  • Have trunk export the env-vars (possibly filtered) into a JSON struct
  • Having that JSON struct assigned in the index.html (e.g. to process.env)
  • Refresh that struct when doing trunk watch (or serve).

ctron avatar Oct 25 '24 10:10 ctron

yes, with the addition that it would be nice to point Trunk to a .env too.

this isn't as essential, since one can use a shell script or task runner of some sort to do that part - but it's nice to keep everything in Trunk

would be good to get more feedback on this issue, but I think it's a fairly common need

dakom avatar Oct 25 '24 13:10 dakom

Could you come up with a PR for this?

ctron avatar Oct 25 '24 13:10 ctron

sure, I'll put it on my local TODO list for myself, but tbh it's going to be a while until I get to it, most likely

dakom avatar Oct 28 '24 07:10 dakom

I'm not sure if this was ever implemented, but I just wanted to share my thoughts on how I would prefer to use .env files with Trunk, and why the above approach might not be ideal.

In tools like Vite (and others), there's a convention where only environment variables with a specific prefix—like VITE_—are exposed to the client. For example, with a .env file like this:

VITE_AUTH_ENDPOINT=https://example.com
SLACK_API_TOKEN=xyz

only VITE_AUTH_ENDPOINT would be included in the final bundle and accessible to the end user. This is really helpful when you have environment variables that are needed during the build process but shouldn't be exposed publicly, or when other tools also rely on the same .env file.

I may have misunderstood the intent, but if the implementation just exposes the entire .env file, that could catch some users off guard—especially if they have secrets or credentials in those files.

I hope this perspective is helpful!

emilbonnek avatar Jul 16 '25 13:07 emilbonnek

oh, I completely forgot about this... not on my personal radar at the moment. Imho an allowlist in Trunk.toml is a bit better than compiling in everything with a TRUNK_ prefix, since it prevents accidental contamination and also allows using global env vars without having to rename them

dakom avatar Jul 16 '25 13:07 dakom