Hello TypeStaceans!
Here's a step by step process in how you can pass environment variables to a Rust WASM application framework using Yew, Dioxus, Leptos, Sycamore, or your favorite one.
GitHub Repo
TypeStacean - Learn Rust WASM from TypeScript
How you do it in TypeScript
Given a TypeScript React, Vue, Svelte, or Vanilla TypeScript app, you'd generally have an .env at the root level of your project:
APP_S3_URL="https://aws.amazon.com"
APP_AUTH0_ID="asdk211jrifenf"
APP_OTHER_NON_SENSIBLE_INFO="h123213"
And then, you could either augment it in a .d.ts file or create an object and expose it.
declare global {
namespace NodeJS {
interface ProcessEnv {
APP_S3_URL: string;
APP_AUTH0_ID: string;
APP_OTHER_NON_SENSIBLE_INFO: string;
}
}
}
This .env would then be injected at build time.
It isn't possible to pass it as runtime (unless you fetch it from an external resource) as you need to run a process for it do so.
In Web Assembly, things are the same.
Environment Variables in Rust Web Assembly (Yew, Dioxus, Leptos).
In WebAssembly we need to pass the environment variable at compile time.
Therefore we cannot use the dotenv
crate (similar to npm's dotenv) as it's only available in runtime.
We will leverage Rust's built-in build.rs script system to read the environment at build time and then generate a custom .rs file which we can read afterwards.
Never store server-sensitive information in your front-end .env files as these are accessible to the public
Using build.rs to inject the environment variables.
- Go to the root of your project and create an empty
build.rs
file and an empty .env file.
- Add
dotenv
to the build-dependencies part ofCargo.Toml
```toml
[package]
name = "typestacean-learn-rust-wasm-from-typescript"
version = "0.1.0"
edition = "2021"
Add these:
[build-dependencies]
dotenv = "0.15.0"
This will enable dotenv to be used in `build.rs`
3. Fill in the build.rs script
```rust
// build.rs
use dotenv::dotenv;
use std::env;
use std::fs::File;
use std::io::Write;
fn main() {
println!("cargo:rerun-if-changed=.env");
let dest_path = "./src/env.rs";
let mut f = File::create(&dest_path).unwrap();
// use the dotenv crate to get the .env values
dotenv().ok();
f.write_all(b"// This file is automatically generated by build.rs\n\n")
.unwrap()
for (key, value) in env::vars() {
if key.starts_with("APP_") {
let line = format!(
"pub const {}: &'static str = \"{}\";\n",
key,
value.replace("\"", "\\\"")
);
f.write_all(line.as_bytes()).unwrap();
}
}
}
Here's the breakdown:
- We define a main() function that will be used as the entry point
- The
println!("cargo:rerun-if-changed=.env");
tells cargo to prevent running the build.rs script if the.env
file hasn't changed. - We then set to generate
env.rs
insrc/env.rs
- We then call
dotenv().ok()
to load the environment from the .env to theenv::vars()
. - The
b""
means that the strings should be represented as a sequence of bytes. - We iterate the environment line per line, we process it so we can generate something like: ```
pub const APP_WASM_FRAMEWORK: &'static str = "leptos";
* This is then written in the env.rs file
Include the .env.rs file in your script
// Other imports omitted
mod env;
fn main() {
println!("{}", env::APP_WASM_FRAMEWORK);
}
</code></pre></div><h2>
<a name="feedback-appreciated" href="#feedback-appreciated">
</a>
Feedback appreciated
</h2>
<h2>
<a name="follow-to-learn-rust-wasm-as-an-experienced-typescript-developer" href="#follow-to-learn-rust-wasm-as-an-experienced-typescript-developer">
</a>
Follow to learn Rust WASM as an experienced TypeScript developer
</h2>
<p>I'm currently learning and sharing my knowledge with Rust's most popular WASM frameworks: Yew, Dioxus, Leptos.</p>
<p>I want to help TypeStaceans (TypeScript developers who want to learn Rust Web Assembly) to grasp Rust WASM as fast as possible by sharing the distilled knowledge.</p>
<p>Follow me on:</p>
<ul>
<li>dev.to - <a href="https://dev.to/javiasilis">https://dev.to/javiasilis</a>
</li>
<li>twitter - <a href="https://twitter.com/javiasilis">https://twitter.com/javiasilis</a>
</li>
<li>linkedin - <a href="https://linkedin.com/in/javiasilis">https://linkedin.com/in/javiasilis</a>
</li>
</ul>
Top comments (2)
Easier way is to use inline env vars:
and in code:
docs: doc.rust-lang.org/std/macro.env.html
Thanks for putting this together Jose, it was super useful.