Umakant Patil
Umakant Patil

Reputation: 2308

Webpack: How to inject process.env runtime on client(browser) side making build independent of environment

SHORT Question

I'm looking some way to tell Webpack that, do not do anything with process variable, just treat as like any other global variable (so it refers to window.process in client bundle). If not possible, then a way to inject variables in process.env of Webpack during runtime on client.

LONG Explaination

At the moment, I use Webpack to pack my React (SSR) application. I have 5 environments like dev1, dev2... staging and production. I want to re-use the same build and keep things configurable like say Google Analytics ID on each environment is different.

Backend Dot ENV module does the job. I can define all constants as KEY=value pair in .env file and load them run time and use as process.env.KEY in the code.

I was trying to replicate same behaviour for the front end side (or shared files). Say I have a baseService.js which makes call to fetch. It can be used from node + client as well. It uses variables like process.env.HOST. Until now I was creating separate build for each environment, therefore had this defined in Webpack using webpack.DefinePlugin plugin to be able to use this on client side bundle.

Now as I want to re-use the builds, I capture all constants in process.env see if any of them is usable on client side by matching them with PUBLIC_(.*) (It would match PUBLIC_KEY), if yes pack then in array and add in main html file as object as shown below:-

window.process = {ENV: { PUBLIC_GA_ID: '1235', PUBLIC_FOO: 'bar' }}

When I bundle my client using webpack and execute process.env.PUBLIC_GA_ID is undefined (although it is there in head html as global window.process variable). It is because webpack still injecting process variable from Node to the front end which has env object as blank {} object. I had it debugged below is the screenshot.

enter image description here

Above is console log of process variable in a baseService.js file. Obviously I cannot use window.process here because then it would fail when file is being used in Node.js

I'm looking some way to tell Webpack that, do not do anything with process variable, just treat as like any other global variable (so it refers to window.process in client bundle). If not possible, then a way to inject variables in process.env of Webpack during runtime on client.

Upvotes: 2

Views: 16953

Answers (5)

Luchux
Luchux

Reputation: 795

What I ended up doing is:

  • Use webpack to generate the bundle, that will be reused in dev, prod, stage.
  • Access the .env file in execution time, with your own code and not using dotenv, neither webpack-dotenv.
  • create a function getEnv() that uses const rawFile = new XMLHttpRequest(); and reads your .env file.
  • you don't use dotenv package, neither you require it. You just import { getEnv } and use it in your code in runtime.

Of course this is not the safest, but either dotenv or webpack-dotenv are since the keys are being injected to the client anyways and accessible.

And you can reuse your bundle, and create the file that your function reads in the docker, or anywhere.

Upvotes: 0

John Henry
John Henry

Reputation: 3223

Use "globalThis" in your code in place of "window" and use "globalThis.process" in place of "process".

Upvotes: 2

zq-jhon
zq-jhon

Reputation: 109

In fact, webpack preset 2 environment to build different app. Consider this config:

// package.json
"scripts": {
    "build:development": "cross-env NODE_ENV=development webpack",
    "build:production": "cross-env NODE_ENV=production  webpack",
 }
// webpack.config.js
const ENVIRONMENT = process.env.NODE_ENV;
module.exports = {
entry: { // ... },
output: { // ... },

// typeof mode =  "development" | "production" | "none";
mode: ENVIRONMENT

}

$ npm run build:development

After building, open browser, also output that you set current env is: development good luck

Upvotes: 0

gnorsilva
gnorsilva

Reputation: 640

I had a similar issue with webpack inlining the contents of process.env.NODE_ENV at compile time.

I was able to switch that off by adding the following to my server webpack config:

  optimization: {
    nodeEnv: 'production'
  }

See the optimization docs for more related info

Upvotes: 2

Umakant Patil
Umakant Patil

Reputation: 2308

I think instead playing with Webpack to do this job, I have settled with for the simplest solution. If anyone has any better answer, please do post.

I created a utility function as follows:-

export const getEnv = key => {
  if (typeof window === 'undefined') {
    // node
    return process.env[key]
  }
  // browser
  return window.process.env[key]
}

Now I call getEnv('PUBLIC_KEY') or getEnv('NODE_ENV') both in node and in browser and works perfectly fine.

Although I'd still prefer the better way Webpack supports option to take process.env run time or inject API for browser

Upvotes: 5

Related Questions