在 webpack 中传递环境相关变量
Passing environment-dependent variables in webpack
我正在尝试将 angular 应用程序从 gulp 转换为 webpack。在 gulp 中,我使用 gulp-preprocess 来根据 NODE_ENV 替换 html 页面中的一些变量(例如数据库名称)。使用 webpack 实现类似结果的最佳方法是什么?
有两种基本方法可以实现这一点。
定义插件
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
请注意,这只会“按原样”替换匹配项。这就是字符串采用原格式的原因。你可以有一个更复杂的结构,比如那里的一个对象,但你明白了。
环境插件
new webpack.EnvironmentPlugin(['NODE_ENV'])
EnvironmentPlugin
在内部使用 DefinePlugin
并将环境值映射到代码中。更简洁的语法。
别名
或者您可以通过 an aliased module 使用配置。从消费者的角度来看,它看起来像这样:
var config = require('config');
配置本身可能如下所示:
resolve: {
alias: {
config: path.join(__dirname, 'config', process.env.NODE_ENV)
}
}
假设 process.env.NODE_ENV
是 development
。然后它将映射到 ./config/development.js
。它映射到的模块可以像这样导出配置:
module.exports = {
testing: 'something',
...
};
只是另一种选择,如果你只想使用cli界面,只需使用webpack的define
选项。我在 package.json
中添加以下脚本:
"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"
所以我只需要 运行 npm run build-production
.
您可以直接使用 webpack
中可用的 EnvironmentPlugin
在编译过程中访问任何环境变量。
您只需在 webpack.config.js
文件中声明该插件:
var webpack = require('webpack');
module.exports = {
/* ... */
plugins = [
new webpack.EnvironmentPlugin(['NODE_ENV'])
]
};
请注意,您必须显式声明要使用的环境变量的名称。
我调查了几个关于如何设置特定于环境的变量的选项,结果是这样的:
我目前有 2 个 webpack 配置:
webpack.production.config.js
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': JSON.stringify('production'),
'API_URL': JSON.stringify('http://localhost:8080/bands')
}
}),
webpack.config.js
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': JSON.stringify('development'),
'API_URL': JSON.stringify('http://10.10.10.10:8080/bands')
}
}),
在我的代码中,我以这种(简短的)方式获得 API_URL 的值:
const apiUrl = process.env.API_URL;
编辑 2016 年 11 月 3 日
Webpack 文档有一个示例:https://webpack.js.org/plugins/define-plugin/#usage
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
BROWSER_SUPPORTS_HTML5: true,
TWO: "1+1",
"typeof window": JSON.stringify("object")
})
使用 ESLint 如果你有 no-undef
规则,你需要特别允许代码中的未定义变量。 http://eslint.org/docs/rules/no-undef 像这样:
/*global TWO*/
console.log('Running App version ' + TWO);
编辑 2017 年 9 月 7 日(特定于 Create-React-App)
如果您不喜欢配置太多,请查看 Create-React-App:Create-React-App - Adding Custom Environment Variables。在幕后,CRA 无论如何都使用 Webpack。
要添加到一堆答案中,我个人更喜欢以下内容:
const webpack = require('webpack');
const prod = process.argv.indexOf('-p') !== -1;
module.exports = {
...
plugins: [
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: prod? `"production"`: '"development"'
}
}
}),
...
]
};
使用它没有时髦的环境变量或跨平台问题(使用环境变量)。您所做的只是 运行 正常的 webpack
或 webpack -p
分别用于开发或生产。
参考:Github issue
你可以传递任何命令行参数无需额外的插件使用--env
自webpack 2:
webpack --config webpack.config.js --env.foo=bar
使用webpack.config.js中的变量:
module.exports = function(env) {
if (env.foo === 'bar') {
// do something
}
}
添加到一堆答案中:
使用 ExtendedDefinePlugin 而不是 DefinePlugin
npm install extended-define-webpack-plugin --save-dev.
ExtendedDefinePlugin 使用起来更简单并且有文档记录:-)
link
因为 DefinePlugin 缺乏 好的文档,我想帮忙,说它实际上像 #DEFINE in c# 一样工作。
#if (DEBUG)
Console.WriteLine("Debugging is enabled.");
#endif
因此,如果您想了解 DefinePlugin 的工作原理,请阅读 c# #define 文档。 link
我更喜欢为不同的环境使用 .env 文件。
- 使用 webpack.dev.config 将
env.dev
复制到 .env 到根文件夹
- 使用webpack.prod.config复制
env.prod
到.env
在代码中
使用
require('dotenv').config();
const API = process.env.API ## which will store the value from .env file
由于我在 上的编辑未获批准 ,请发布其他信息。
如果您想从 package.json 中选择值,就像定义的 版本号 并通过 Javascript 中的 DefinePlugin 访问它。
{"version": "0.0.1"}
然后,在各自的webpack.config中导入package.json,使用导入变量访问属性,然后使用 DefinePlugin.
中的属性
const PACKAGE = require('../package.json');
const _version = PACKAGE.version;//Picks the version number from package.json
例如 webpack.config 上的某些配置正在使用 DefinePlugin 的元数据:
const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
host: HOST,
port: PORT,
ENV: ENV,
HMR: HMR,
RELEASE_VERSION:_version//Version attribute retrieved from package.json
});
new DefinePlugin({
'ENV': JSON.stringify(METADATA.ENV),
'HMR': METADATA.HMR,
'process.env': {
'ENV': JSON.stringify(METADATA.ENV),
'NODE_ENV': JSON.stringify(METADATA.ENV),
'HMR': METADATA.HMR,
'VERSION': JSON.stringify(METADATA.RELEASE_VERSION)//Setting it for the Scripts usage.
}
}),
在任何打字稿文件中访问它:
this.versionNumber = process.env.VERSION;
最聪明的做法是这样的:
// webpack.config.js
plugins: [
new webpack.DefinePlugin({
VERSION: JSON.stringify(require("./package.json").version)
})
]
只是另一个类似于@zer0chain 的答案的答案。但是,有一个区别。
设置webpack -p
就足够了。
等同于:
--define process.env.NODE_ENV="production"
这与
相同
// webpack.config.js
const webpack = require('webpack');
module.exports = {
//...
plugins:[
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
};
所以你可能只需要在 package.json
节点文件中这样的东西:
{
"name": "projectname",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"debug": "webpack -d",
"production": "webpack -p"
},
"author": "prosti",
"license": "ISC",
"dependencies": {
"webpack": "^2.2.1",
...
}
}
来自 DefinePlugin 的一些提示:
The DefinePlugin allows you to create global constants which can be configured at compile time. This can be useful for allowing different behavior between development builds and release builds. For example, you might use a global constant to determine whether logging takes place; perhaps you perform logging in your development build but not in the release build. That's the sort of scenario the DefinePlugin facilitates.
这是为了让您检查是否输入 webpack --help
Config options:
--config Path to the config file
[string] [default: webpack.config.js or webpackfile.js]
--env Enviroment passed to the config, when it is a function
Basic options:
--context The root directory for resolving entry point and stats
[string] [default: The current directory]
--entry The entry point [string]
--watch, -w Watch the filesystem for changes [boolean]
--debug Switch loaders to debug mode [boolean]
--devtool Enable devtool for better debugging experience (Example:
--devtool eval-cheap-module-source-map) [string]
-d shortcut for --debug --devtool eval-cheap-module-source-map
--output-pathinfo [boolean]
-p shortcut for --optimize-minimize --define
process.env.NODE_ENV="production"
[boolean]
--progress Print compilation progress in percentage [boolean]
我发现以下解决方案最容易为 Webpack 2 设置环境变量:
比如我们有一个webpack设置:
var webpack = require('webpack')
let webpackConfig = (env) => { // Passing envirmonment through
// function is important here
return {
entry: {
// entries
},
output: {
// outputs
},
plugins: [
// plugins
],
module: {
// modules
},
resolve: {
// resolves
}
}
};
module.exports = webpackConfig;
在 Webpack 中添加环境变量:
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
]
定义插件变量并将其添加到plugins
:
new webpack.DefinePlugin({
'NODE_ENV': JSON.stringify(env.NODE_ENV || 'development')
}),
现在当 运行 webpack 命令时,将 env.NODE_ENV
作为参数传递:
webpack --env.NODE_ENV=development
// OR
webpack --env.NODE_ENV development
现在您可以在代码中的任何位置访问 NODE_ENV
变量。
这是一种对我有用的方法,它允许我通过重用 json 文件来保持环境变量干燥。
const webpack = require('webpack');
let config = require('./settings.json');
if (__PROD__) {
config = require('./settings-prod.json');
}
const envVars = {};
Object.keys(config).forEach((key) => {
envVars[key] = JSON.stringify(config[key]);
});
new webpack.DefinePlugin({
'process.env': envVars
}),
从 Webpack v4 开始,只需在 Webpack 配置中设置 mode
即可为您设置 NODE_ENV
(通过 DefinePlugin
)。 Docs here.
我不太喜欢...
new webpack.DefinePlugin({
'process.env': envVars
}),
...因为它不提供任何类型的安全性。相反,你最终会提升你的秘密内容,除非你将 webpack 添加到 gitignore ♀️ 有更好的解决方案。
基本上有了这个配置,一旦你编译你的代码,所有进程环境变量将从整个代码中删除,不会有一个 process.env.VAR 由于 babel 插件 transform-inline-environment-variables
PS 如果你不想以一大堆未定义结束,请确保在 webpack 调用 babel-loader 之前调用 env.js,这就是为什么它是 webpack 调用的第一件事。 babel.config.js 文件中的变量数组必须与 env.js 上的对象相匹配。现在只有一件事要做。
添加一个 .env
文件将所有环境变量放在那里,该文件必须位于项目的根目录,或者随意将它添加到任何你想要的地方,只需确保在 [=36= 上设置相同的位置] 文件并将其添加到 gitignore
const dotFiles = ['.env'].filter(Boolean);
if (existsSync(dotFiles)) {
require("dotenv-expand")(require("dotenv").config((dotFiles)));
}
如果你想看整个babel + webpack + ts 从heaw获取
https://github.com/EnetoJara/Node-typescript-babel-webpack.git
同样的逻辑适用于 React 和所有其他
config
---webpack.js
---env.js
src
---source code world
.env
bunch of dotFiles
env.js
"use strict";
/***
I took the main idea from CRA, but mine is more cooler xD
*/
const {realpathSync, existsSync} = require('fs');
const {resolve, isAbsolute, delimiter} = require('path');
const NODE_ENV = process.env.NODE_ENV || "development";
const appDirectory = realpathSync(process.cwd());
if (typeof NODE_ENV !== "string") {
throw new Error("falle and stuff");
}
const dotFiles = ['.env'].filter(Boolean);
if (existsSync(dotFiles)) {
require("dotenv-expand")(require("dotenv").config((dotFiles)));
}
process.env.NODE_PATH = (process.env.NODE_PATH || "")
.split(delimiter)
.filter(folder => folder && isAbsolute(folder))
.map(folder => resolve(appDirectory, folder))
.join(delimiter);
const ENETO_APP = /^ENETO_APP_/i;
module.exports = (function () {
const raw = Object.keys ( process.env )
.filter ( key => ENETO_APP.test ( key ) )
.reduce ( ( env, key ) => {
env[ key ] = process.env[ key ];
return env;
},
{
BABEL_ENV: process.env.ENETO_APP_BABEL_ENV,
ENETO_APP_DB_NAME: process.env.ENETO_APP_DB_NAME,
ENETO_APP_DB_PASSWORD: process.env.ENETO_APP_DB_PASSWORD,
ENETO_APP_DB_USER: process.env.ENETO_APP_DB_USER,
GENERATE_SOURCEMAP: process.env.ENETO_APP_GENERATE_SOURCEMAP,
NODE_ENV: process.env.ENETO_APP_NODE_ENV,
PORT: process.env.ENETO_APP_PORT,
PUBLIC_URL: "/"
} );
const stringyField = {
"process.env": Object.keys(raw).reduce((env, key)=> {
env[key]=JSON.stringify(raw[key]);
return env;
},{}),
};
return {
raw, stringyField
}
})();
没有插件 troll 的 webpack 文件
"use strict";
require("core-js");
require("./env.js");
const path = require("path");
const nodeExternals = require("webpack-node-externals");
module.exports = env => {
return {
devtool: "source-map",
entry: path.join(__dirname, '../src/dev.ts'),
externals: [nodeExternals()],
module: {
rules: [
{
exclude: /node_modules/,
test: /\.ts$/,
use: [
{
loader: "babel-loader",
},
{
loader: "ts-loader"
}
],
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: "file-loader",
},
],
},
],
},
node: {
__dirname: false,
__filename: false,
},
optimization: {
splitChunks: {
automaticNameDelimiter: "_",
cacheGroups: {
vendor: {
chunks: "initial",
minChunks: 2,
name: "vendor",
test: /[\/]node_modules[\/]/,
},
},
},
},
output: {
chunkFilename: "main.chunk.js",
filename: "name-bundle.js",
libraryTarget: "commonjs2",
},
plugins: [],
resolve: {
extensions: ['.ts', '.js']
} ,
target: "node"
};
};
babel.config.js
module.exports = api => {
api.cache(() => process.env.NODE_ENV);
return {
plugins: [
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-transform-classes", {loose: true}],
["@babel/plugin-external-helpers"],
["@babel/plugin-transform-runtime"],
["@babel/plugin-transform-modules-commonjs"],
["transform-member-expression-literals"],
["transform-property-literals"],
["@babel/plugin-transform-reserved-words"],
["@babel/plugin-transform-property-mutators"],
["@babel/plugin-transform-arrow-functions"],
["@babel/plugin-transform-block-scoped-functions"],
[
"@babel/plugin-transform-async-to-generator",
{
method: "coroutine",
module: "bluebird",
},
],
["@babel/plugin-proposal-async-generator-functions"],
["@babel/plugin-transform-block-scoping"],
["@babel/plugin-transform-computed-properties"],
["@babel/plugin-transform-destructuring"],
["@babel/plugin-transform-duplicate-keys"],
["@babel/plugin-transform-for-of"],
["@babel/plugin-transform-function-name"],
["@babel/plugin-transform-literals"],
["@babel/plugin-transform-object-super"],
["@babel/plugin-transform-shorthand-properties"],
["@babel/plugin-transform-spread"],
["@babel/plugin-transform-template-literals"],
["@babel/plugin-transform-exponentiation-operator"],
["@babel/plugin-proposal-object-rest-spread"],
["@babel/plugin-proposal-do-expressions"],
["@babel/plugin-proposal-export-default-from"],
["@babel/plugin-proposal-export-namespace-from"],
["@babel/plugin-proposal-logical-assignment-operators"],
["@babel/plugin-proposal-throw-expressions"],
[
"transform-inline-environment-variables",
{
include: [
"ENETO_APP_PORT",
"ENETO_APP_NODE_ENV",
"ENETO_APP_BABEL_ENV",
"ENETO_APP_DB_NAME",
"ENETO_APP_DB_USER",
"ENETO_APP_DB_PASSWORD",
],
},
],
],
presets: [["@babel/preset-env",{
targets: {
node: "current",
esmodules: true
},
useBuiltIns: 'entry',
corejs: 2,
modules: "cjs"
}],"@babel/preset-typescript"],
};
};
现在2020年了,我也面临着同样的问题,但是对于这个老问题,有很多新的答案,只列出其中的一些:
- 这是webpack.config.js
plugins: [
new HtmlWebpackPlugin({
// 1. title is the parameter, you can use in ejs template
templateParameters:{
title: JSON.stringify(someting: 'something'),
},
}),
//2. BUILT_AT is a parameter too. can use it.
new webpack.DefinePlugin({
BUILT_AT: webpack.DefinePlugin.runtimeValue(Date.now,"some"),
}),
//3. for webpack5, you can use global variable: __webpack_hash__
//new webpack.ExtendedAPIPlugin()
],
//4. this is not variable, this is module, so use 'import tt' to use it.
externals: {
'ex_title': JSON.stringify({
tt: 'eitentitle',
})
},
这4种方式只是基本的,我相信还有更多的方式。但是我觉得这4ways可能是最简单的。
我的 webpack 版本 "webpack": "^4.29.6"
的解决方法非常简单。
//package.json
{
...
"scripts": {
"build": "webpack --mode production",
"start": "webpack-dev-server --open --mode development"
},
}
你可以在你的 webpack 命令中传递 --mode 参数,然后在 webpack.config.js
// webpack.config.json
module.exports = (env,argv) => {
return {
...
externals: {
// global app config object
config: JSON.stringify({
apiUrl: (argv.mode==="production") ? '/api' : 'localhost:3002/api'
})
}
}
我在我的代码中像这样使用 baseurl
// my api service
import config from 'config';
console.log(config.apiUrl) // like fetch(`${config.apiUrl}/users/user-login`)
dotenv-webpack
A secure webpack plugin that supports dotenv and other environment variables and only exposes what you choose and use.
通过一些基于 defaults
选项的配置的解决方法来实现这一点,一旦包有 .env.defaults
文件作为环境变量的初始值,您就可以将它用于 development
和让.env
为您制作。
用法
- 安装包
npm install dotenv-webpack --save-dev
- 创建
.env.defaults
文件
API_URL='dev_url/api/'
- 创建一个
.env
文件留空,让 defaults
工作,在部署过程中更新它
- 配置
webpack
- webpack.config.js
new Dotenv({
defaults: true
})
- 开发环境测试
file.js
console.log(process.env.API_URL)
// Outputs: dev_url/api/
- 构建时,更新空
.env
文件
API_URL='prod_url/api/'
dotenv-webpack 将使用它来覆盖 env.defaults
- 产品环境测试
file.js
console.log(process.env.API_URL)
// Outputs: prod_url/api/
我正在尝试将 angular 应用程序从 gulp 转换为 webpack。在 gulp 中,我使用 gulp-preprocess 来根据 NODE_ENV 替换 html 页面中的一些变量(例如数据库名称)。使用 webpack 实现类似结果的最佳方法是什么?
有两种基本方法可以实现这一点。
定义插件
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
请注意,这只会“按原样”替换匹配项。这就是字符串采用原格式的原因。你可以有一个更复杂的结构,比如那里的一个对象,但你明白了。
环境插件
new webpack.EnvironmentPlugin(['NODE_ENV'])
EnvironmentPlugin
在内部使用 DefinePlugin
并将环境值映射到代码中。更简洁的语法。
别名
或者您可以通过 an aliased module 使用配置。从消费者的角度来看,它看起来像这样:
var config = require('config');
配置本身可能如下所示:
resolve: {
alias: {
config: path.join(__dirname, 'config', process.env.NODE_ENV)
}
}
假设 process.env.NODE_ENV
是 development
。然后它将映射到 ./config/development.js
。它映射到的模块可以像这样导出配置:
module.exports = {
testing: 'something',
...
};
只是另一种选择,如果你只想使用cli界面,只需使用webpack的define
选项。我在 package.json
中添加以下脚本:
"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"
所以我只需要 运行 npm run build-production
.
您可以直接使用 webpack
中可用的 EnvironmentPlugin
在编译过程中访问任何环境变量。
您只需在 webpack.config.js
文件中声明该插件:
var webpack = require('webpack');
module.exports = {
/* ... */
plugins = [
new webpack.EnvironmentPlugin(['NODE_ENV'])
]
};
请注意,您必须显式声明要使用的环境变量的名称。
我调查了几个关于如何设置特定于环境的变量的选项,结果是这样的:
我目前有 2 个 webpack 配置:
webpack.production.config.js
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': JSON.stringify('production'),
'API_URL': JSON.stringify('http://localhost:8080/bands')
}
}),
webpack.config.js
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': JSON.stringify('development'),
'API_URL': JSON.stringify('http://10.10.10.10:8080/bands')
}
}),
在我的代码中,我以这种(简短的)方式获得 API_URL 的值:
const apiUrl = process.env.API_URL;
编辑 2016 年 11 月 3 日
Webpack 文档有一个示例:https://webpack.js.org/plugins/define-plugin/#usage
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
BROWSER_SUPPORTS_HTML5: true,
TWO: "1+1",
"typeof window": JSON.stringify("object")
})
使用 ESLint 如果你有 no-undef
规则,你需要特别允许代码中的未定义变量。 http://eslint.org/docs/rules/no-undef 像这样:
/*global TWO*/
console.log('Running App version ' + TWO);
编辑 2017 年 9 月 7 日(特定于 Create-React-App)
如果您不喜欢配置太多,请查看 Create-React-App:Create-React-App - Adding Custom Environment Variables。在幕后,CRA 无论如何都使用 Webpack。
要添加到一堆答案中,我个人更喜欢以下内容:
const webpack = require('webpack');
const prod = process.argv.indexOf('-p') !== -1;
module.exports = {
...
plugins: [
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: prod? `"production"`: '"development"'
}
}
}),
...
]
};
使用它没有时髦的环境变量或跨平台问题(使用环境变量)。您所做的只是 运行 正常的 webpack
或 webpack -p
分别用于开发或生产。
参考:Github issue
你可以传递任何命令行参数无需额外的插件使用--env
自webpack 2:
webpack --config webpack.config.js --env.foo=bar
使用webpack.config.js中的变量:
module.exports = function(env) {
if (env.foo === 'bar') {
// do something
}
}
添加到一堆答案中:
使用 ExtendedDefinePlugin 而不是 DefinePlugin
npm install extended-define-webpack-plugin --save-dev.
ExtendedDefinePlugin 使用起来更简单并且有文档记录:-) link
因为 DefinePlugin 缺乏 好的文档,我想帮忙,说它实际上像 #DEFINE in c# 一样工作。
#if (DEBUG)
Console.WriteLine("Debugging is enabled.");
#endif
因此,如果您想了解 DefinePlugin 的工作原理,请阅读 c# #define 文档。 link
我更喜欢为不同的环境使用 .env 文件。
- 使用 webpack.dev.config 将
env.dev
复制到 .env 到根文件夹 - 使用webpack.prod.config复制
env.prod
到.env
在代码中
使用
require('dotenv').config();
const API = process.env.API ## which will store the value from .env file
由于我在
如果您想从 package.json 中选择值,就像定义的 版本号 并通过 Javascript 中的 DefinePlugin 访问它。
{"version": "0.0.1"}
然后,在各自的webpack.config中导入package.json,使用导入变量访问属性,然后使用 DefinePlugin.
中的属性const PACKAGE = require('../package.json');
const _version = PACKAGE.version;//Picks the version number from package.json
例如 webpack.config 上的某些配置正在使用 DefinePlugin 的元数据:
const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
host: HOST,
port: PORT,
ENV: ENV,
HMR: HMR,
RELEASE_VERSION:_version//Version attribute retrieved from package.json
});
new DefinePlugin({
'ENV': JSON.stringify(METADATA.ENV),
'HMR': METADATA.HMR,
'process.env': {
'ENV': JSON.stringify(METADATA.ENV),
'NODE_ENV': JSON.stringify(METADATA.ENV),
'HMR': METADATA.HMR,
'VERSION': JSON.stringify(METADATA.RELEASE_VERSION)//Setting it for the Scripts usage.
}
}),
在任何打字稿文件中访问它:
this.versionNumber = process.env.VERSION;
最聪明的做法是这样的:
// webpack.config.js
plugins: [
new webpack.DefinePlugin({
VERSION: JSON.stringify(require("./package.json").version)
})
]
只是另一个类似于@zer0chain 的答案的答案。但是,有一个区别。
设置webpack -p
就足够了。
等同于:
--define process.env.NODE_ENV="production"
这与
相同// webpack.config.js
const webpack = require('webpack');
module.exports = {
//...
plugins:[
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
};
所以你可能只需要在 package.json
节点文件中这样的东西:
{
"name": "projectname",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"debug": "webpack -d",
"production": "webpack -p"
},
"author": "prosti",
"license": "ISC",
"dependencies": {
"webpack": "^2.2.1",
...
}
}
来自 DefinePlugin 的一些提示:
The DefinePlugin allows you to create global constants which can be configured at compile time. This can be useful for allowing different behavior between development builds and release builds. For example, you might use a global constant to determine whether logging takes place; perhaps you perform logging in your development build but not in the release build. That's the sort of scenario the DefinePlugin facilitates.
这是为了让您检查是否输入 webpack --help
Config options:
--config Path to the config file
[string] [default: webpack.config.js or webpackfile.js]
--env Enviroment passed to the config, when it is a function
Basic options:
--context The root directory for resolving entry point and stats
[string] [default: The current directory]
--entry The entry point [string]
--watch, -w Watch the filesystem for changes [boolean]
--debug Switch loaders to debug mode [boolean]
--devtool Enable devtool for better debugging experience (Example:
--devtool eval-cheap-module-source-map) [string]
-d shortcut for --debug --devtool eval-cheap-module-source-map
--output-pathinfo [boolean]
-p shortcut for --optimize-minimize --define
process.env.NODE_ENV="production"
[boolean]
--progress Print compilation progress in percentage [boolean]
我发现以下解决方案最容易为 Webpack 2 设置环境变量:
比如我们有一个webpack设置:
var webpack = require('webpack')
let webpackConfig = (env) => { // Passing envirmonment through
// function is important here
return {
entry: {
// entries
},
output: {
// outputs
},
plugins: [
// plugins
],
module: {
// modules
},
resolve: {
// resolves
}
}
};
module.exports = webpackConfig;
在 Webpack 中添加环境变量:
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
]
定义插件变量并将其添加到plugins
:
new webpack.DefinePlugin({
'NODE_ENV': JSON.stringify(env.NODE_ENV || 'development')
}),
现在当 运行 webpack 命令时,将 env.NODE_ENV
作为参数传递:
webpack --env.NODE_ENV=development
// OR
webpack --env.NODE_ENV development
现在您可以在代码中的任何位置访问 NODE_ENV
变量。
这是一种对我有用的方法,它允许我通过重用 json 文件来保持环境变量干燥。
const webpack = require('webpack');
let config = require('./settings.json');
if (__PROD__) {
config = require('./settings-prod.json');
}
const envVars = {};
Object.keys(config).forEach((key) => {
envVars[key] = JSON.stringify(config[key]);
});
new webpack.DefinePlugin({
'process.env': envVars
}),
从 Webpack v4 开始,只需在 Webpack 配置中设置 mode
即可为您设置 NODE_ENV
(通过 DefinePlugin
)。 Docs here.
我不太喜欢...
new webpack.DefinePlugin({
'process.env': envVars
}),
...因为它不提供任何类型的安全性。相反,你最终会提升你的秘密内容,除非你将 webpack 添加到 gitignore ♀️ 有更好的解决方案。
基本上有了这个配置,一旦你编译你的代码,所有进程环境变量将从整个代码中删除,不会有一个 process.env.VAR 由于 babel 插件 transform-inline-environment-variables
PS 如果你不想以一大堆未定义结束,请确保在 webpack 调用 babel-loader 之前调用 env.js,这就是为什么它是 webpack 调用的第一件事。 babel.config.js 文件中的变量数组必须与 env.js 上的对象相匹配。现在只有一件事要做。
添加一个 .env
文件将所有环境变量放在那里,该文件必须位于项目的根目录,或者随意将它添加到任何你想要的地方,只需确保在 [=36= 上设置相同的位置] 文件并将其添加到 gitignore
const dotFiles = ['.env'].filter(Boolean);
if (existsSync(dotFiles)) {
require("dotenv-expand")(require("dotenv").config((dotFiles)));
}
如果你想看整个babel + webpack + ts 从heaw获取
https://github.com/EnetoJara/Node-typescript-babel-webpack.git
同样的逻辑适用于 React 和所有其他
config
---webpack.js
---env.js
src
---source code world
.env
bunch of dotFiles
env.js
"use strict";
/***
I took the main idea from CRA, but mine is more cooler xD
*/
const {realpathSync, existsSync} = require('fs');
const {resolve, isAbsolute, delimiter} = require('path');
const NODE_ENV = process.env.NODE_ENV || "development";
const appDirectory = realpathSync(process.cwd());
if (typeof NODE_ENV !== "string") {
throw new Error("falle and stuff");
}
const dotFiles = ['.env'].filter(Boolean);
if (existsSync(dotFiles)) {
require("dotenv-expand")(require("dotenv").config((dotFiles)));
}
process.env.NODE_PATH = (process.env.NODE_PATH || "")
.split(delimiter)
.filter(folder => folder && isAbsolute(folder))
.map(folder => resolve(appDirectory, folder))
.join(delimiter);
const ENETO_APP = /^ENETO_APP_/i;
module.exports = (function () {
const raw = Object.keys ( process.env )
.filter ( key => ENETO_APP.test ( key ) )
.reduce ( ( env, key ) => {
env[ key ] = process.env[ key ];
return env;
},
{
BABEL_ENV: process.env.ENETO_APP_BABEL_ENV,
ENETO_APP_DB_NAME: process.env.ENETO_APP_DB_NAME,
ENETO_APP_DB_PASSWORD: process.env.ENETO_APP_DB_PASSWORD,
ENETO_APP_DB_USER: process.env.ENETO_APP_DB_USER,
GENERATE_SOURCEMAP: process.env.ENETO_APP_GENERATE_SOURCEMAP,
NODE_ENV: process.env.ENETO_APP_NODE_ENV,
PORT: process.env.ENETO_APP_PORT,
PUBLIC_URL: "/"
} );
const stringyField = {
"process.env": Object.keys(raw).reduce((env, key)=> {
env[key]=JSON.stringify(raw[key]);
return env;
},{}),
};
return {
raw, stringyField
}
})();
没有插件 troll 的 webpack 文件
"use strict";
require("core-js");
require("./env.js");
const path = require("path");
const nodeExternals = require("webpack-node-externals");
module.exports = env => {
return {
devtool: "source-map",
entry: path.join(__dirname, '../src/dev.ts'),
externals: [nodeExternals()],
module: {
rules: [
{
exclude: /node_modules/,
test: /\.ts$/,
use: [
{
loader: "babel-loader",
},
{
loader: "ts-loader"
}
],
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: "file-loader",
},
],
},
],
},
node: {
__dirname: false,
__filename: false,
},
optimization: {
splitChunks: {
automaticNameDelimiter: "_",
cacheGroups: {
vendor: {
chunks: "initial",
minChunks: 2,
name: "vendor",
test: /[\/]node_modules[\/]/,
},
},
},
},
output: {
chunkFilename: "main.chunk.js",
filename: "name-bundle.js",
libraryTarget: "commonjs2",
},
plugins: [],
resolve: {
extensions: ['.ts', '.js']
} ,
target: "node"
};
};
babel.config.js
module.exports = api => {
api.cache(() => process.env.NODE_ENV);
return {
plugins: [
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-transform-classes", {loose: true}],
["@babel/plugin-external-helpers"],
["@babel/plugin-transform-runtime"],
["@babel/plugin-transform-modules-commonjs"],
["transform-member-expression-literals"],
["transform-property-literals"],
["@babel/plugin-transform-reserved-words"],
["@babel/plugin-transform-property-mutators"],
["@babel/plugin-transform-arrow-functions"],
["@babel/plugin-transform-block-scoped-functions"],
[
"@babel/plugin-transform-async-to-generator",
{
method: "coroutine",
module: "bluebird",
},
],
["@babel/plugin-proposal-async-generator-functions"],
["@babel/plugin-transform-block-scoping"],
["@babel/plugin-transform-computed-properties"],
["@babel/plugin-transform-destructuring"],
["@babel/plugin-transform-duplicate-keys"],
["@babel/plugin-transform-for-of"],
["@babel/plugin-transform-function-name"],
["@babel/plugin-transform-literals"],
["@babel/plugin-transform-object-super"],
["@babel/plugin-transform-shorthand-properties"],
["@babel/plugin-transform-spread"],
["@babel/plugin-transform-template-literals"],
["@babel/plugin-transform-exponentiation-operator"],
["@babel/plugin-proposal-object-rest-spread"],
["@babel/plugin-proposal-do-expressions"],
["@babel/plugin-proposal-export-default-from"],
["@babel/plugin-proposal-export-namespace-from"],
["@babel/plugin-proposal-logical-assignment-operators"],
["@babel/plugin-proposal-throw-expressions"],
[
"transform-inline-environment-variables",
{
include: [
"ENETO_APP_PORT",
"ENETO_APP_NODE_ENV",
"ENETO_APP_BABEL_ENV",
"ENETO_APP_DB_NAME",
"ENETO_APP_DB_USER",
"ENETO_APP_DB_PASSWORD",
],
},
],
],
presets: [["@babel/preset-env",{
targets: {
node: "current",
esmodules: true
},
useBuiltIns: 'entry',
corejs: 2,
modules: "cjs"
}],"@babel/preset-typescript"],
};
};
现在2020年了,我也面临着同样的问题,但是对于这个老问题,有很多新的答案,只列出其中的一些:
- 这是webpack.config.js
plugins: [
new HtmlWebpackPlugin({
// 1. title is the parameter, you can use in ejs template
templateParameters:{
title: JSON.stringify(someting: 'something'),
},
}),
//2. BUILT_AT is a parameter too. can use it.
new webpack.DefinePlugin({
BUILT_AT: webpack.DefinePlugin.runtimeValue(Date.now,"some"),
}),
//3. for webpack5, you can use global variable: __webpack_hash__
//new webpack.ExtendedAPIPlugin()
],
//4. this is not variable, this is module, so use 'import tt' to use it.
externals: {
'ex_title': JSON.stringify({
tt: 'eitentitle',
})
},
这4种方式只是基本的,我相信还有更多的方式。但是我觉得这4ways可能是最简单的。
我的 webpack 版本 "webpack": "^4.29.6"
的解决方法非常简单。
//package.json
{
...
"scripts": {
"build": "webpack --mode production",
"start": "webpack-dev-server --open --mode development"
},
}
你可以在你的 webpack 命令中传递 --mode 参数,然后在 webpack.config.js
// webpack.config.json
module.exports = (env,argv) => {
return {
...
externals: {
// global app config object
config: JSON.stringify({
apiUrl: (argv.mode==="production") ? '/api' : 'localhost:3002/api'
})
}
}
我在我的代码中像这样使用 baseurl
// my api service
import config from 'config';
console.log(config.apiUrl) // like fetch(`${config.apiUrl}/users/user-login`)
dotenv-webpack
A secure webpack plugin that supports dotenv and other environment variables and only exposes what you choose and use.
通过一些基于 defaults
选项的配置的解决方法来实现这一点,一旦包有 .env.defaults
文件作为环境变量的初始值,您就可以将它用于 development
和让.env
为您制作。
用法
- 安装包
npm install dotenv-webpack --save-dev
- 创建
.env.defaults
文件
API_URL='dev_url/api/'
- 创建一个
.env
文件留空,让defaults
工作,在部署过程中更新它 - 配置
webpack
-webpack.config.js
new Dotenv({
defaults: true
})
- 开发环境测试
file.js
console.log(process.env.API_URL)
// Outputs: dev_url/api/
- 构建时,更新空
.env
文件
API_URL='prod_url/api/'
dotenv-webpack 将使用它来覆盖 env.defaults
- 产品环境测试
file.js
console.log(process.env.API_URL)
// Outputs: prod_url/api/