[英]Trying to pass gulp environment-dependent web-pack variables into angularjs app
[英]Passing environment-dependent variables in webpack
我正在尝试将 Angular 应用程序从 gulp 转换为 webpack。 在 gulp 中,我使用 gulp-preprocess 替换 html 页面中的一些变量(例如数据库名称),具体取决于 NODE_ENV。 使用 webpack 实现类似结果的最佳方法是什么?
有两种基本方法可以实现这一目标。
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
请注意,这只会“按原样”替换匹配项。 这就是为什么字符串是它的格式。 你可以有一个更复杂的结构,比如一个对象,但你明白了。
new webpack.EnvironmentPlugin(['NODE_ENV'])
EnvironmentPlugin
在内部使用DefinePlugin
并通过它将环境值映射到代码。 更简洁的语法。
或者,您可以通过别名模块使用配置。 从消费者方面来看,它看起来像这样:
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
。
我研究了几个关于如何设置环境特定变量的选项,最终得到了这个:
我目前有 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 - 添加自定义环境变量。 无论如何,CRA 在幕后使用 Webpack。
您可以使用--env
传递环境变量而无需其他插件
网页包2-4
webpack --config webpack.config.js --env.foo=bar
Webpack 5+ (没有.
)
webpack --config webpack.config.js --env foo=bar
然后,使用webpack.config.js
中的变量:
module.exports = function(env) {
if (env.foo === 'bar') {
// do something
}
}
进一步阅读: Webpack 2.0 不支持自定义命令行参数? #2254
您可以直接使用webpack
中提供的EnvironmentPlugin
在转译期间访问任何环境变量。
您只需在webpack.config.js
文件中声明插件:
var webpack = require('webpack');
module.exports = {
/* ... */
plugins: [
new webpack.EnvironmentPlugin(['NODE_ENV'])
]
};
请注意,您必须明确声明要使用的环境变量的名称。
为了个人添加到一堆答案中,我更喜欢以下内容:
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问题
由于我对thevangelist 的上述帖子的编辑未获批准,因此发布了其他信息。
如果您想从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的一些提示:
DefinePlugin 允许您创建可以在编译时配置的全局常量。 这对于允许开发构建和发布构建之间的不同行为很有用。 例如,您可以使用全局常量来确定是否发生日志记录; 也许您在您的开发版本中执行日志记录,而不是在发布版本中。 这就是 DefinePlugin 促成的那种场景。
这样你就可以检查你是否输入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
变量。
我更喜欢将 .env 文件用于不同的环境。
env.dev
复制到 .env 到根文件夹env.prod
复制到 .env并在代码中
利用
require('dotenv').config(); const API = process.env.API ## which will store the value from .env file
添加到一堆答案:
使用ExtendedDefinePlugin而不是 DefinePlugin
npm install extended-define-webpack-plugin --save-dev.
ExtendedDefinePlugin 使用起来更简单,并且有文档记录:-)链接
因为 DefinePlugin缺乏良好的文档,我想帮忙,说它实际上像c# 中的 #DEFINE一样工作。
#if (DEBUG)
Console.WriteLine("Debugging is enabled.");
#endif
因此,如果您想了解 DefinePlugin 的工作原理,请阅读 c# #define 文档。 关联
我对 webpack 版本"webpack": "^4.29.6"
的解决方法非常简单。
//package.json
{
...
"scripts": {
"build": "webpack --mode production",
"start": "webpack-dev-server --open --mode development"
},
}
您可以使用 webpack commnad 传递 --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`)
这是一种对我有用的方法,它允许我通过重用 json 文件来保持环境变量 DRY。
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
)。 文档在这里。
一个安全的 webpack 插件,支持 dotenv 和其他环境变量,只公开你选择和使用的内容。
通过基于defaults
选项的配置的一些解决方法来实现这一点,一旦包将.env.defaults
文件作为 env 变量的初始值,您就可以将其用于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/
我不是...的忠实粉丝
new webpack.DefinePlugin({
'process.env': envVars
}),
...因为它不提供任何类型的安全性。 相反,您最终会增加您的秘密内容,除非您将 webpack 添加到 gitignore 🤷♀️ 有更好的解决方案。
基本上有了这个配置,一旦你编译了你的代码,所有进程环境变量都将从整个代码中删除,由于 babel 插件transform-inline-environment-variables
PS if,不会有一个 process.env.VAR 了你不想以一大堆未定义结束,请确保在 webpack 调用 babel-loader 之前调用 env.js,这就是为什么它是 webpack 调用的第一件事。 babel.config.js 文件中的变量数组必须与 env.js 上的对象匹配。 现在只有一件事情要做。 添加一个.env
文件将所有环境变量放在那里,该文件必须位于项目的根目录下,或者随意添加它,只要确保在 env.js 文件上设置相同的位置并添加它到 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
获取
同样的逻辑适用于反应和所有其他💩
config
---webpack.js
---env.js
src
---source code world
.env
bunch of dotFiles
环境.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
}
})();
没有插件的 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 年,我面临同样的问题,但是对于这个老问题,有很多新答案,只列出一些:
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 是最简单的。
我不知道为什么,但是没有人真正提到最简单的解决方案。 这对我来说适用于nodejs和grunt。 对于许多人来说,Webpack可能会使您感到困惑,您只需使用以下行即可:
process.env.NODE_ENV = 'production';
使用上述解决方案,您实际上不需要使用envify或webpack。 有时,简单的硬编码解决方案可能对某些人有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.