Webpack:使用DefinePlugin和DotEnv时process.env未定义

12

我希望能从我的.env文件中获取变量,但我总是得到undefined

这是我的js代码:

require('dotenv').config();
class Header extends React.Component{
    constructor(props){...}
    render(){
        console.log("NODE ENV", process.env.NODE_ENV);
        console.log("REACT_APP_MYAPP", process.env.REACT_APP_MYAPP);
        ...
   }
}

这将打印:

NODE_ENV development

REACT_APP_MYAPP undefined

在我的package.json文件中有:

"scripts":{
      "start" : "webpack-dev-server --config webpack.dev.js",
      "build" : "webpack --config webpack.prod.js"
 }

而在我的webpack.dev.js文件中:

const webpack = require("webpack");
const merge = require("webpack-merge");
const path = require("path");
const common = require("./webpack.common.js");

module.exports = merge.smart(common, {
    devServer: {
        contentBase: path.resolve(__dirname, "dist"),
        hot: true,
        overlay: {
            warnings: true,
            errors: true
        },
        inline :true,
        historyApiFallback: true,
        port: 8085
    },
    devtool: "inline-sourcemap",
    optimization: {
        namedModules: true
    },
    plugins: [
        new webpack.HotModulReplacementPlugin(),
        new webpack.DefinePlugin({
            "process.env.NODE_ENV": JSON.stringify("development"),
            "process.env.REACT_APP_MYAPP": JSON.stringify(process.env.REACT_APP_MYAPP)
        })
    ],
    mode: "development"
});

我把我的.env文件放在项目根目录下,与webpack.dev.js和package.json并列:

REACT_APP_MYAPP=http://localhost:8080/

所以我认为,它没有成功获取文件中的变量。

请问我如何在代码中获取REACT_APP_MYAPP的值?


可能是React + webpack:'process.env'未定义的重复问题。 - user7143559
不是重复的 - anais1477
4个回答

33
穿越深邃、黑暗的兔子洞会带领你了解以下事实:
  • Webpack 5不再提供process其他Node.js变量
  • DefinePlugin的角色需要重新定义。
  • 传递给DefinePlugin的值必须被字符串化, 即使它们是字符串。
  • 鉴于Webpack 5,EnvironmentPlugin让事情更加混乱。
  • process.env并不是你应该在前端使用的东西。
  • 你可以使用polyfills来重新添加process和其他内容,但这是有不再提供它的原因的。
  • dotenv-wepack既不必要也不可行。
  • 使用process.env的原因是为了全局访问变量。但它是错误航班上的乘客。我们可以放弃它,而是直接访问预期的变量:
plugins: [
    new DefinePlugin({
        // With dotenv (values must be stringified)
        ...Object.entries(dotenv.config().parsed).reduce((acc, curr) => ({...acc, [`${curr[0]}`]: JSON.stringify(curr[1]) }), {}),
        
        // Without dotenv 
        'myString': JSON.stringify('IAmAString')
    })
  ]

在前端:

declare var myString: string;
console.log(myString); // 'IAmAString'

如果您有多个带有变量的对象,抽象字符串化是有意义的:
// Create a function to stringify values
function stringifyValues(object: {[key: string]: any;}){
    return Object.entries(object).reduce((acc, curr) => ({...acc, [`${curr[0]}`]: JSON.stringify(curr[1]) }), {} as { [key: string]: string; });
}

// use with DefinePlugin
plugins: [
    new DefinePlugin({
      ...stringifyValues(dotenv.config().parsed),
      ...stringifyValues(dotenv.config({ path: '/.env.special' }).parsed),
      'myObject': stringifyValues({ 
            name: 'Object', 
            description: 'to be an object' 
      })
    })
  ]

如果您真正需要访问process.env
plugins: [
    new DefinePlugin({
        // this might expose confidential data about your environment
        'process.env': JSON.stringify(process.env),

        // the correct way
        'process.env.USERNAME': JSON.stringify('Donald Hump')
    })
  ]

在前端:

declare var process: any;
console.log(process) // will NOT work, because process hasn't been injected
console.log(process.env); // will work but risky
console.log(process.env.USERNAME); // correct: 'Donald Hump'

1
感谢您!对我来说问题是我在解构process.env时出现了问题:const { NODE_ENV } = process.env; 这个方法不起作用,而使用 const NODE_ENV = process.env.NODE_ENV;就可以了。 - Ville
new webpack.DefinePlugin({ 'process.env': JSON.stringify(dotenv.config().parsed) }) 也可以工作。 - Ridhwaan Shakeel
非常感谢您进行了深入的研究并给出了答案。然而,我仍然不确定最佳实践是什么。 - Tony

3
"最初的回答":在启动时添加 REACT_APP_MYAPP 的第一种解决方案没有起作用。但第二种解决方案起作用了。
解决方案:
在我的 webpack.dev.js 文件中添加 require('dotenv').config() 文件,并替换:
   new webpack.DefinePlugin({
        "process.env.NODE_ENV": JSON.stringify("development"),
        "process.env.REACT_APP_MYAPP": JSON.stringify(process.env.REACT_APP_MYAPP)
    })

使用

    new webpack.EnvironmentPlugin(['NODE_ENV', 'REACT_APP_MYAPP']);

感谢您!原始回答:最初的回答。

1

有几种方法可以使这个工作。

最容易测试的方法是将您的"start" : "webpack-dev-server --config webpack.dev.js",更改为"start" : "REACT_APP_MYAPP=http://localhost:8080/ node webpack-dev-server --config webpack.dev.js",

这将注入环境变量,并在Webpack构建过程中可用。每当使用npmnode运行命令时,都可以使用此技术。例如,NODE_ENV='development REACT_MY_APP=http://localhost:8080/ node myapp.js,两者都将在process.env上可用。

您还可以在webpack.dev.js中调用require('dotenv').config()文件。然后它将在您使用DefinePlugin时设置。

通常,您不会使用npm start命令运行开发服务器。

随着应用程序的发展,您应该查看 Webpack Environment Plugin。然后,您可以在生产 webpack.prod.js 中引用 .env 以使用“生产”构建设置,同时使用插件设置您的默认/回退环境变量。

1
为什么我不应该在我的开发服务器上使用npm start? - anais1477
在部署生产环境时,大多数默认解决方案会运行 npm start 来启动应用程序(在运行 npm build 之后)。这并不是强制性的。你可以创建一个 start:production,但它将作为 npm run start:production 运行...所以更多的是遵循“默认假设”。它也不需要在 npm 命令前面加上 run - adamrights
我会进行测试以确认,但看起来运行webpack-dev-server时没有将ENV_VARS传递到它运行webpack的进程中。我认为在前面添加node就可以解决这个问题。此外,如果您的应用程序只是客户端,并且您正在上传所有构建文件以进行静态服务,则让npm start运行devServer并不重要,因为您不会运行“生产”node.js服务器来启动构建。如果这是一个“服务器端渲染”(SSR)React应用程序,那么这将更加重要。 - adamrights
你绝对不应该在生产环境中使用.env文件,甚至不应该将它们包含在源代码控制中。遵循12因素应用程序开发原则:应用程序有时会将配置存储为代码中的常量。这违反了12因素的要求,即严格分离配置和代码。配置在部署过程中会有很大差异,而代码则不会。 - user-12410035
在工作中,严格的12因素的争论经常出现。现代的webpack构建应用程序需要一些奇怪的技巧,除非你允许每个环境进行构建。 - adamrights

0

在我的自定义React应用程序模型中,只有当我不在变量名称中包含'REACT_APP_'时,它才对我有效:

在webpack.config.js中:

// Node import
const path = require('path');

const webpack = require('webpack');

require('dotenv').config();

module.exports = [
   plugins: [
    new webpack.EnvironmentPlugin(['NODE_ENV', 'API'])
  ],
]

in .env:

NODE_ENV=development
API=http://localhost:5000

当我部署应用程序时(例如在Netlify上),我会从生产环境变量中排除NODE_ENV。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接