Webpack:如何在客户端(浏览器)端注入 process.env 运行时,使构建独立于环境

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

简短问题

我正在寻找一些方法来告诉 Webpack,不要对 process 变量做任何事情,就像对待任何其他全局变量一样对待(所以它指的是客户端包中的 window.process) .如果不可能,那么一种在客户端 运行 时间期间在 Webpack process.env 中注入变量的方法。

详细说明

目前,我使用 Webpack 来打包我的 React (SSR) 应用程序。我有 5 个环境,例如 dev1、dev2...暂存和生产。我想重复使用相同的构建并保持可配置性,比如 Google 每个环境的 Analytics ID 都不同。

后端 Dot ENV 模块完成这项工作。我可以在 .env 文件中将所有常量定义为 KEY=value 对并加载它们 运行 时间并在代码中用作 process.env.KEY

我试图为前端(或共享文件)复制相同的行为。假设我有一个 baseService.js 调用 fetch。它也可以从节点+客户端使用。它使用像 process.env.HOST 这样的变量。到目前为止,我一直在为每个环境创建单独的构建,因此使用 webpack.DefinePlugin 插件在 Webpack 中定义了它,以便能够在客户端包中使用它。

现在我想重新使用构建,我捕获了 process.env 中的所有常量,通过将它们与 PUBLIC_(.*) 匹配(它将匹配 PUBLIC_KEY),如果是,则打包到数组中并添加到主html文件中作为对象,如下所示:-

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

当我使用 webpack 捆绑我的客户端并执行时 process.env.PUBLIC_GA_ID 是未定义的(尽管它作为全局 window.process 变量存在于头部 html 中)。这是因为 webpack 仍然从 Node 向前端注入进程变量,该前端具有 env 对象作为空白 {} 对象。下面是我调试的截图。

以上是 baseService.js 文件中 process 变量的控制台日志。显然我不能在这里使用 window.process 因为当文件在 Node.js

中使用时它会失败

我正在寻找一些方法来告诉 Webpack,不要对 process 变量做任何事情,就像对待任何其他全局变量一样对待(所以它指的是客户端包中的 window.process) .如果不可能,那么一种在客户端 运行 时间期间在 Webpack process.env 中注入变量的方法。

我认为我已经选择了最简单的解决方案,而不是使用 Webpack 来完成这项工作。如果有人有更好的答案,请post.

我创建了一个效用函数如下:-

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

现在我在节点和浏览器中调用 getEnv('PUBLIC_KEY')getEnv('NODE_ENV') 并且工作得很好。

尽管我仍然更喜欢 Webpack 支持选项的更好方式来占用 process.env 运行 时间或为浏览器注入 API

我在 webpack 在编译时内联 process.env.NODE_ENV 的内容时遇到了类似的问题。

我可以通过将以下内容添加到我的服务器 webpack 配置中来关闭它:

  optimization: {
    nodeEnv: 'production'
  }

See the optimization docs 了解更多相关信息

其实webpack预置了2个环境来搭建不同的app。 考虑这个配置:

// 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

构建完成后,打开浏览器,同样输出你设置的内容current env is: development 祝你好运

使用“globalThis" in your code in place of "window" and use "globalThis.process”代替“process”。

我最后做的是:

  • 使用 webpack 生成包,将在开发、生产、阶段重复使用。
  • 在执行时访问 .env 文件,使用您自己的代码而不使用 dotenv,既不 webpack-dotenv。
  • 创建一个使用 const rawFile = new XMLHttpRequest(); 并读取您的 .env 文件的函数 getEnv()。
  • 您不使用 dotenv 包,也不需要它。您只需导入 { getEnv } 并在运行时在您的代码中使用它。

当然这不是最安全的,但是 dotenv 或 webpack-dotenv 是因为密钥无论如何都被注入到客户端并且可以访问。

并且您可以重复使用您的包,并创建您的函数在 docker 或任何地方读取的文件。