Should the browser consider an import.meta.env object?

I just noticed that Snowpack recently merged in support for import.meta.env being a replacement for the process.env global variable that is typically used in Node.js application workflows (and browser workflows through bundlers) to set environment state information.

I thought it would be interesting to discuss if the browser might consider something similar.

The most typical use case for this is the process.env.NODE_ENV === 'production' check which has become a JS idiom and not just a Node.js one. See for example React for the browser shipping this here - https://unpkg.com/react@16.13.1/index.js.

In the transition to ES modules, it would be nice for users not to try to maintain the same process global being “shimmed” for the browser, but instead to have an idiomatic way of doing this for ES modules.

The alternatives seem to be globals, an import env from 'env' module or always requiring a precompilation step like Snowpack has shipped which adds a line to the top of every module containing import.meta.env = env.

The alternatives do have the problem of not providing a pattern that can be used in portable code such that fragmentation or convergence on a pattern that won’t be supported in browsers seems to be a risk otherwise.

Perhaps giving the browser control over such a variable would provide a useful alignment for tools while continuing to allow idiomatic modular code to run in browsers without a build step being a mandatory prerequisite?

It would be great to hear thoughts further on this topic.

1 Like

This feels like a rather awkward use of import.meta. Right now it’s used for values that are contextual to the executing module (matching its scope, scoped to module). This seems to add data that is not at all specific to the module but more general about the runtime. A global or a shared module (import env from 'env') sounds like a much more appropriate API for that kind of information to me.

3 Likes

Agree, I don’t think this is the use case, what do you want to add in the browser version of import.meta.env?

To reiterate the problem, the best solution to environment data is an env.js:

export const mode = 'production';
export const serverName = 'blah';

sort of thing where you have import { mode } from 'env' all over the codebase.

The specific problem though is that most code executed by JS applications is library code - and that library code often needs to know environment information such as if you are running a development or production build.

The ecosystem will solve this problem in whatever way, regardless of any standards work.

The question then is if standards work might help find a solution that retains the specific guarantees of:

  • Code portability - when running code in different JS engines, do the assumptions of this “environment import” break workflows or do they work correctly. If all code did import env from 'env' we would be ok here, but laying that pattern down would require work.

  • Browser compatibility - with Snowpack shipping import.meta.env it is now encouraging library code to exist that will not work correctly in browsers. Hoepfully most users will check typeof import.meta.env !== 'undefined', but it just takes one library to skip that check and there is a compatibility gap in having a top-level undefined member expression error.

I think the two “standards approaches” to this problem would be:

  1. Specify that import.meta.env is a mutable object, that can be configured by runtimes during boot either directly or through an API.

  2. Specify a standard builtin module for std:env or similar to encourage a standard environment import pattern.

I’m not saying that either of the above are definitely things that should be done - I’m just saying that they are things that might be done to help solve these portability problems, and as such are exactly where being able to discuss these problems within a standards forum can be a useful exercise even if the result is a negative one.