【问题标题】:Undefined .env variables when webpack goes into production modewebpack 进入生产模式时未定义的 .env 变量
【发布时间】:2021-09-11 07:44:55
【问题描述】:

我正在使用 dot-env NPM 包将简单的变量传递给我的 webpack/express 应用程序。

当我在 webpack 的 PRODUCTION 模式下运行时,我来自 .env 的所有变量都未定义。

我正在构建一个开发和生产 webpack 配置文件,目前有以下设置。

任何关于我所犯的错误以及为什么我的 .env 变量被删除的建议将不胜感激。

  • package.json(脚本)

     "buildDev": "rm -rf dist && webpack --mode development --config webpack.server.config.js && webpack --mode development --config webpack.dev.config.js",
    
      "buildProd": "rm -rf dist && webpack --mode production --config webpack.server.config.js && webpack --mode production --config webpack.prod.config.js",
    
  • webpack.dev

    const path = require("path");
    const webpack = require("webpack");
    const HtmlWebPackPlugin = require("html-webpack-plugin");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const paths = require("./config/paths");
    const isDevelopment = false;
    const Dotenv = require('dotenv-webpack');
    
    require('dotenv').config()
    module.exports = {
      entry: {
        main: [
         "webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000",
         paths.appIndexJs,
       ],
      },
      output: {
        path: path.join(__dirname, "dist"),
        publicPath: "/",
        filename: "[name].js",
      },
      devServer: {
        historyApiFallback: true,
      },
      mode: "production",
      target: "web",
      devtool: "#source-map",
      module: {
        rules: [
          {
            enforce: "pre",
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            loader: "eslint-loader",
            options: {
              emitWarning: true,
              failOnError: false,
              failOnWarning: false,
            },
          },
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            include: path.resolve(paths.appSrc),
            loader: "babel-loader",
          },
          {
          // Loads the javacript into html template provided.
          // Entry point is set below in HtmlWebPackPlugin in Plugins
            test: /\.html$/,
            include: path.resolve(paths.appSrc),
            use: [
              {  
                loader: "html-loader",
              },
            ],
          },
          {
            test: /\.css$/,
            include: path.resolve(paths.appSrc),
            use: ["style-loader", "css-loader"],
          },
          {
            test: /\.css$/,
            include: /node_modules/,
            use: ["style-loader", "css-loader"],
          },
          {
            test: /\.scss$/,
            use: ["style-loader", "css-loader", "sass-loader"],
          },
          {
            test: /\.(png|svg|jpg|gif|eot|woff|woff2|ttf)$/,
            use: ["file-loader"],
          },
        ],
      },
      resolve: {
        extensions: [".js", ".jsx"],
      },
      plugins: [
        new HtmlWebPackPlugin({
          favicon: "./src/assets/img/favicons/favicon.ico",
          template: "./src/html/index.html",
          filename: "./index.html",
          excludeChunks: ["server"],
       }),
       new webpack.HotModuleReplacementPlugin(),
       new webpack.NoEmitOnErrorsPlugin(),
       new Dotenv()
     ],
    };
    
  • webpack.prod

    const path = require("path");
    const webpack = require("webpack");
    const HtmlWebPackPlugin = require("html-webpack-plugin");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const paths = require("./config/paths");
    const isDevelopment = false;
    const Dotenv = require('dotenv-webpack');
    
    require('dotenv').config()
    module.exports = {
      entry: {
        main: [
         "webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000",
         paths.appIndexJs,
       ],
      },
      output: {
        path: path.join(__dirname, "dist"),
        publicPath: "/",
        filename: "[name].js",
      },
      devServer: {
        historyApiFallback: true,
      },
      mode: "production",
      target: "web",
      devtool: "#source-map",
      module: {
        rules: [
          {
            enforce: "pre",
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            loader: "eslint-loader",
            options: {
              emitWarning: true,
              failOnError: false,
              failOnWarning: false,
            },
          },
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            include: path.resolve(paths.appSrc),
            loader: "babel-loader",
          },
          {
            // Loads the javacript into html template provided.
            // Entry point is set below in HtmlWebPackPlugin in Plugins
            test: /\.html$/,
            include: path.resolve(paths.appSrc),
            use: [
              {
                loader: "html-loader",
              },
            ],
          },
          {
            test: /\.css$/,
            include: path.resolve(paths.appSrc),
            use: ["style-loader", "css-loader"],
          },
          {
            test: /\.css$/,
            include: /node_modules/,
            use: ["style-loader", "css-loader"],
          },
          {
            test: /\.scss$/,
            use: ["style-loader", "css-loader", "sass-loader"],
          },
        /*{
            test: /\.scss$/,
            use: [
              { loader: 'css-loader', options: { url: false, sourceMap: true } },
              { loader: 'sass-loader', options: { sourceMap: true } 
              },                    
            ]
           },*/
         /*{
             test: /\.css$/,
             include: path.resolve(paths.appSrc),
             use: ["style-loader", "css-loader"],
           },
           {
             test: /\.sass$/,
             use: [
               MiniCssExtractPlugin.loader,
               { loader: 'css-loader', options: { url: false, sourceMap: true } },
               { loader: 'sass-loader', options: { sourceMap: true } },                    
             ]
           },
           {
             test: /\.css$/,
             include: /node_modules/,
             loader: [
               isDevelopment ? "style-loader" : MiniCssExtractPlugin.loader,
                 {
                   loader: "css-loader",
                   options: {
                      modules: true,
                      sourceMap: isDevelopment,
                   },
                 },
              ],
            },
            {
              test: /\.(scss)$/,                
              use: [
                MiniCssExtractPlugin.loader, { loader: 'css-loader', 
                  options: { url: false, sourceMap: 
                  true } }, { loader: 'sass-loader', options: { sourceMap: true } },                    
              ]
            },*/
            {
              test: /\.(png|svg|jpg|gif|eot|woff|woff2|ttf)$/,
              //include: path.resolve(paths.appSrc),
              use: ["file-loader"],
            },
          ],
        },
        resolve: {
          extensions: [".js", ".jsx"],
        },
        plugins: [
          new webpack.DefinePlugin({
            'process.env': { 'NODE_ENV': JSON.stringify('production') }
          }),
          new HtmlWebPackPlugin({
            favicon: "./src/assets/img/favicons/favicon.ico",
            template: "./src/html/index.html",
            filename: "./index.html",
            excludeChunks: ["server"],
          }),
          new webpack.NoEmitOnErrorsPlugin(),
          new Dotenv()
       ],
    };
    
  • webpack.server

    const path = require("path");
    const webpack = require("webpack");
    const nodeExternals = require("webpack-node-externals");
    const HtmlWebPackPlugin = require("html-webpack-plugin");
    
    module.exports = (env, argv) => {
      const SERVER_PATH =
        argv.mode === "production" ? "./src/server/server-prod.js" : "./src/server/server-dev.js";
    
     return {
       entry: {
        server: SERVER_PATH,
       },
       output: {
         path: path.join(__dirname, "dist"),
         publicPath: "/",
         filename: "[name].js",
       },
       mode: argv.mode,
       target: "node",
       node: {
         // Need this when working with express, otherwise the build fails
         __dirname: false, // if you don't put this is, __dirname
         __filename: false, // and __filename return blank or /
       },
       externals: [nodeExternals()], // Need this to avoid error when working with Express
       devServer: {
         historyApiFallback: true,
       },
       module: {
        rules: [
          {
            // Transpiles ES6-8 into ES5
       test: /\.js$/,
       exclude: /node_modules/,
       use: {
         loader: "babel-loader",
       },
     }
     ],
     },
    };
    };
    

【问题讨论】:

    标签: node.js express webpack dotenv


    【解决方案1】:

    如果您在其插件部分查看 yow webpack.prod,您就会喜欢它。 新的 webpack.DefinePlugin({ 'process.env': { 'NODE_ENV': JSON.stringify('production') } 所以基本上你将 process.env 设置为等于 What Eva is there

    解决方案

    首先你需要安装两个模块

    • dotenv-expand
    • dotenv
    $ npm i -D dotenv-expand dotenv
    

    下一步

    创建一个名为env.js 的新文件,我的意思是名称由您决定。将文件放在你的 webpack 所在的地方

    env.js

    'use strict';
    
    const fs = require('fs');
    const path = require('path');
    
    const {NODE_ENV} = process.env.NODE_ENV;
    
    const dotenvFile = `.env.${NODE_ENV}`;
    
    require('dotenv-expand')(
          require('dotenv').config({
            path: dotenvFile,
          }));
      
    
    const appDirectory = fs.realpathSync(process.cwd());
    process.env.NODE_PATH = (process.env.NODE_PATH || '')
      .split(path.delimiter)
      .filter(folder => folder && !path.isAbsolute(folder))
      .map(folder => path.resolve(appDirectory, folder))
      .join(path.delimiter);
    
    // set your own prefix
    const PREFIX = /^ENETO_/i;
    
    function getEnvironment() {
      const raw = Object.keys(process.env)
        .filter(key => PREFIX.test(key))
        .reduce(
          (env, key) => {
            env[key] = process.env[key];
    
            return env;
          },
          {
            NODE_ENV: process.env.NODE_ENV || 'development',
            PORT: process.env.PORT||3000,
          }
        );
      const stringified = {
        'process.env': Object.keys(raw).reduce((env, key) => {
          env[key] = JSON.stringify(raw[key]);
          return env;
        }, {}),
      };
    
      console.log("stringified", stringified);
    
      return { raw, stringified };
    }
    
    module.exports = getEnvironment();
    
    

    注意

    确保添加前缀,以便所有前缀都以 PREFIX 开头 你可以设置自己的前缀

    现在在每个 webpack 上添加它;

    webpack.server.js

    /**
     webpack server
    */
    "use strict";
    
    const path = require("path");
    const nodeExternals = require("webpack-node-externals");
    const webpack = require("webpack");
    /**
     * HERE IS IMPORTED ALL THE WAY TO THE BOTTOM YOU'LL SEE IT
     */
    const vars = require("./env");
    const { NODE_ENV } = process.env;
    
    const entry = [path.join(__dirname, NODE_ENV === "production" ? `../src/prod.ts` : `../src/dev.ts`)];
    module.exports = {
        target: "node",
        name: "server",
        externals: [nodeExternals()],
        entry: [
            require.resolve("@babel/register"),
            require.resolve("core-js/proposals"),
            require.resolve("core-js"),
            require.resolve("@babel/runtime-corejs3/regenerator"),
            require.resolve("es6-promise/auto"),
            ...entry,
        ],
        devtool: false,
        mode: process.env.NODE_ENV,
        output: {
            filename: "[name]-bundle.js",
            chunkFilename: "[name].chunk.js",
            path: path.resolve(__dirname, "../bundle"),
            publicPath: "/",
            libraryTarget: "commonjs2",
        },
        resolve: {
            extensions: [".ts", ".tsx", ".js"],
        },
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    exclude: /node_modules/,
                    use: [
                        {
                            loader: "babel-loader",
                        },
                    ],
                },
                {
                    test: /\.(js|mjs)$/,
                    exclude: /@babel(?:\/|\\{1,2})runtime/,
                    loader: require.resolve("babel-loader"),
                    options: {
                        babelrc: false,
                        configFile: false,
                        compact: false,
                        presets: [[require.resolve("@babel/preset-env")]],
                        cacheDirectory: true,
                        cacheCompression: false,
                        sourceMaps: false,
                        inputSourceMap: false,
                    },
                },
                {
                    test: /\.(png|jpg|gif)$/,
                    use: [
                        {
                            loader: "file-loader",
                        },
                    ],
                },
            ],
        },
        plugins: [new webpack.DefinePlugin(vars.stringified)],
    };
    

    对你的客户做同样的事情,就是这样:3

    【讨论】:

    • 谢谢欧内斯特。但即使删除了那条线,它仍然会取消一切。我正在进一步调查根本原因是什么。我已经更新了我的问题以包含 webpack.server 文件。
    猜你喜欢
    • 2019-11-19
    • 2019-01-03
    • 2018-06-29
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 2020-05-06
    • 2019-08-17
    • 1970-01-01
    相关资源
    最近更新 更多