[VERY EXTREMELY CURSED] How can I access process.env (at start time)
Ahoy! I need .env to instantiate my jwt server. I've spent so much time of my life reading minified code and dealing with build tools, BUT I HAVE NO IDEA WHATS GOING ON!!! Solid start somehow uses vite, rollup, esbuild, vinxi, and nitro. and then I suppose cf is doing its own polyfills Has javascript gone too far???? But anyway
My first attempt is
but this didn't work, process.env is undefined despite node.js compat being enabled. Looking inside the bundled code, I see
.use(jwt({secret:J.env.JWT_SECRET
, what is J? const J=H.process
. Ok lets zoom out
ok so nitro is being "helpful" and injecting unenv into the game. Ok so its looking at globalThis.
Whats in globalThis? console.log(globalThis)
OH LAWDY WHAT IS THIS (hahah globalThis get it puns?)
1/?48 Replies
Ok so it should be
console.log(globalThis.process?.env || globalThis.__env__)
maybe like unenv does right?
Well that just gives me [Object: null prototype] {} [Object: null prototype] {}
[Object: null prototype] {}
, so there's obviously nothing there, right?
Ok so I saw https://developers.cloudflare.com/workers/runtime-apis/nodejs/process/
Which says
In the Workers implementation, there is no process-level environment, so env is an empty objectSo maybe we can directly acess it, but I think this is saying that I don't get this :( Still, lets try:
console.log(globalThis.process?.env.JWT_SECRET)
gives undefined
when the server starts. Not looking good. But wait! When I do a request, I see it! Wait, so what if I directly acess process?.env.JWT_SECRET
? OH LAWD WOULD YOU LOOK AT THAT! IT WORKS!
But it doesn't work outside of that request.
When the server boots up, it throws an error because process.env.JWT is undefined and it needs that to start.
Ok, so what other ways do we have? Well you can see import { env, nextTick } from "node:process";
in that doc page above. Does anything change?
Ow. Ok, Solid provides getRequestEvent()?.nativeEvent.context.cloudflare.env.JWT_SECRET
, and again this is undefined in the initialization as expected because there's no request event when initializing.Cloudflare Docs
process · Cloudflare Workers docs
To use Node.js APIs in your Worker, add the nodejs_compat compatibility flag to your wrangler.toml file.
next-on-cloudlare
How does
next-on-cloudflare
do it with getRequestContext().env
?
Woah, __cloudflare-request-context__
, we're in some deep stuff, but why is it undefined? Oooh, next on pages does... I don't even want to know:
Now this is JavaScript
So we're looking in
globalThis
for __cloudflare-request-context__
. But this still doesn't explain how env is being populated
- https://github.com/cloudflare/next-on-pages/blob/main/internal-packages/next-dev/src/shared.ts
But tbh maybe it doesn't even matter, I don't have any reason to believe this works outside of a request, given that its... requestContext.
---
So yeah, the ultimate question is is it possible to access env outside of a request context?GitHub
next-on-pages/internal-packages/next-dev/src/shared.ts at main · cl...
CLI to build and develop Next.js apps for Cloudflare Pages - cloudflare/next-on-pages
So no, I don't believe that you can get environment variables outside of a request context because they're only passed into the actual request handler by the runtime itself (i.e. global code can't access them).
Frameworks like
next-on-pages
use a somewhat-hacky method of putting the environment variables into the global context but I believe it's very much next-on-pages-specific and has a lot of moving parts (i.e. probably not something that would be easy to do yourself for Solid Start).
@Better James (hope the ping is OK) would probably have more info on how next-on-pages do it specifically, I'm not well-versed with the internals of that framework.I believe too that only works because those scripts are loaded when a Request Context has already been initialized
next-on-pages runs your requests inside an AyncLocalStorage that holds the values for the env vars, and process.env is overridden with a proxy object to interact with the ALS. And request context is done in a similar way.
Outside of a request context is not possible. How does code run outside of a request context? It doesn't, everything should be run within the context of a request if it is supposed to depend on that request's context. Maybe you're trying to do something build-time related, in which case it will be up to how your framework does things at build-time. But run-time, everything runs within the lifecycle of a request.
How does code run outside of a request context?This would make sense, but when I start miniflare it crashes instantly. The command run was
pnpm build && wrangler pages dev dist/ --compatibility-flags nodejs_compat
![No description](https://cdn.answeroverflow.com/1243182789273321472/image.png)
so maybe there's a bug with miniflare, because I agree that it makes sense that code shouldn't be running outside of a request context
How are you ensuring that this code isn't running outside of the request context?
Well 1. Wouldn't all code technically be running inside of a request context as cloudflare doesn't have long running processes?
but more importantly
2. The specific answer is I'm not ensuring this. Its plainly imported
import client from "../../../server/queries/index";
which causes this code to run on import. But the thing is that its running again whenever I get a req, as I would expect because workers isn't long running![No description](https://cdn.answeroverflow.com/1243185740381163682/image.png)
for all I know this is a miniflare problem and doesn't happen in prod
A Worker is given a few milliseconds to boot up before an event is actually passed in. In this case, the outcome is expected, as the variables are not available in the bootup phase
but the miliseconds to bootup you describe never happened. When the server started, this code ran without a request, and caused the entire server to crash. Subsequent requests, despite theoretically running before being passed an event, correctly have the env set
That sounds right. The bootup runs once, so it fails on the first request, but on subsequent ones it passes