node.js - Undefined .env variables when webpack goes into production mode
问题描述
I'm using the dot-env NPM package in order to pass simple variables to my webpack/express application.
When I run in PRODUCTION mode for webpack, all my variables from .env become undefined.
I'm building up a development and production webpack config files and currently have the following setup.
Any advise on the mistakes I'm making and why my .env variables are being dropped would be greatly appreciated.
package.json (Scripts)
"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", }, } ], }, }; };
解决方案
如果您在其插件部分查看 yow webpack.prod,您就会喜欢它。new 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 相同的位置
环境.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();
笔记
确保添加一个前缀,以便所有这些都以 a 开头,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
推荐阅读
- qt - 哪个是 Key_F13
- python - 从特定行开始读取,然后在该行内循环
- intellij-idea - 来自 ID(intellij) 的 JAvaFX 模块化worksnonmodular:错误:JavaFX 运行时组件丢失,并且是运行此应用程序所必需的
- c# - 具有自定义功能的多级循环
- python - 将N个数字提取到Python中的新列中
- javascript - Azure Function 中的 npm themeparks 模块中的“无法创建第二个实例”错误
- python - 提取特定单元格的值并将其填充以代替 pyspark 数据框中的 NA 值
- nginx - Nginx 导致访问Adminer SQL web 管理员出现问题
- reactjs - 如何从纱线工作区中删除 CRA?
- html - 边缘 - 无法水平和垂直居中文本