admin管理员组文章数量:1126446
I'm trying to convert an angular app from gulp to webpack. in gulp I use gulp-preprocess to replace some variables in the html page (e.g. database name) depending on the NODE_ENV. What is the best way of achieving a similar result with webpack?
I'm trying to convert an angular app from gulp to webpack. in gulp I use gulp-preprocess to replace some variables in the html page (e.g. database name) depending on the NODE_ENV. What is the best way of achieving a similar result with webpack?
Share Improve this question edited Jun 4, 2017 at 16:38 Jeff Puckett 40.7k19 gold badges124 silver badges173 bronze badges asked May 4, 2015 at 12:20 kpgkpg 7,9467 gold badges36 silver badges71 bronze badges 8- 1 Did alias work for you? – Juho Vepsäläinen Commented May 4, 2015 at 16:38
- 1 @bebraw: before I was able to get my head around aliases, I implemented the other solution you suggested based on DefinePlugin(). I do now see that alias would be a better solution and will probably refactor sometime - thanks. If you would like to include your two solutions in an answer I'll happily accept it. – kpg Commented May 5, 2015 at 11:00
- 2 Was directed here via console message. How to fix this in Browserify? – GN. Commented Nov 30, 2016 at 23:32
- 3 Is this question trying to configure the SPA at build time or load time? I note two types of configuration for SPAs: 1) development or production mode, and 2) deployment environment, e.g. development, staging, production. I think NODE_ENV can be used to configure for (1) at build time but how do we configure for (2) at deployment, e.g. configuring a production mode for different deployment environments. I hope this is relevant to this question. – Ashley Aitken Commented Dec 3, 2016 at 18:17
- 1 @AshleyAitken Great question of which I couldn't find an answer on this thread (maybe i missed it), but posted this new thread: stackoverflow.com/questions/44464504/… – David Tesar Commented Jun 9, 2017 at 18:29
18 Answers
Reset to default 499There are two basic ways to achieve this.
DefinePlugin
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
Note that this will just replace the matches "as is". That's why the string is in the format it is. You could have a more complex structure, such as an object there but you get the idea.
EnvironmentPlugin
new webpack.EnvironmentPlugin(['NODE_ENV'])
EnvironmentPlugin
uses DefinePlugin
internally and maps the environment values to code through it. Terser syntax.
Alias
Alternatively you could consume configuration through an aliased module. From consumer side it would look like this:
var config = require('config');
Configuration itself could look like this:
resolve: {
alias: {
config: path.join(__dirname, 'config', process.env.NODE_ENV)
}
}
Let's say process.env.NODE_ENV
is development
. It would map into ./config/development.js
then. The module it maps to can export configuration like this:
module.exports = {
testing: 'something',
...
};
Just another option, if you want to use only a cli interface, just use the define
option of webpack. I add the following script in my package.json
:
"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"
So I just have to run npm run build-production
.
I investigated a couple of options on how to set environment-specific variables and ended up with this:
I have 2 webpack configs currently:
// 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')
}
}),
In my code I get the value of API_URL
in this way:
const apiUrl = process.env.API_URL;
Webpack docs have an example:
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
BROWSER_SUPPORTS_HTML5: true,
TWO: "1+1",
"typeof window": JSON.stringify("object")
})
With ESLint you need to specifically allow undefined variables in code, if you have no-undef
rule on. Like this:
/*global TWO*/
console.log('Running App version ' + TWO);
If you're not into configuring too much, check out Create React App: Adding Custom Environment Variables. Under the hood CRA uses Webpack anyway.
You can pass environment variables without additional plugins using --env
Webpack 2-4
webpack --config webpack.config.js --env.foo=bar
Webpack 5+ (without.
)
webpack --config webpack.config.js --env foo=bar
Then, use the variable in webpack.config.js
:
module.exports = function(env) {
if (env.foo === 'bar') {
// do something
}
}
Further Reading: Webpack 2.0 doesn't support custom command line arguments? #2254
You can directly use the EnvironmentPlugin
available in webpack
to have access to any environment variable during the transpilation.
You just have to declare the plugin in your webpack.config.js
file:
var webpack = require('webpack');
module.exports = {
/* ... */
plugins: [
new webpack.EnvironmentPlugin(['NODE_ENV'])
]
};
Note that you must declare explicitly the name of the environment variables you want to use.
To add to the bunch of answers personally I prefer the following:
const webpack = require('webpack');
const prod = process.argv.indexOf('-p') !== -1;
module.exports = {
...
plugins: [
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: prod? `"production"`: '"development"'
}
}
}),
...
]
};
Using this there is no funky env variable or cross-platform problems (with env vars). All you do is run the normal webpack
or webpack -p
for dev or production respectively.
Reference: Github issue
Since my Edit on the above post by thevangelist wasn't approved, posting additional information.
If you want to pick value from package.json like a defined version number and access it through DefinePlugin inside Javascript.
{"version": "0.0.1"}
Then, Import package.json inside respective webpack.config, access the attribute using the import variable, then use the attribute in the DefinePlugin.
const PACKAGE = require('../package.json');
const _version = PACKAGE.version;//Picks the version number from package.json
For example certain configuration on webpack.config is using METADATA for 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.
}
}),
Access this inside any typescript file:
this.versionNumber = process.env.VERSION;
The smartest way would be like this:
// webpack.config.js
plugins: [
new webpack.DefinePlugin({
VERSION: JSON.stringify(require("./package.json").version)
})
]
Thanks to Ross Allen
Just another answer that is similar to @zer0chain's answer. However, with one distinction.
Setting webpack -p
is sufficient.
It is the same as:
--define process.env.NODE_ENV="production"
And this is the same as
// webpack.config.js
const webpack = require('webpack');
module.exports = {
//...
plugins:[
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
};
So you may only need something like this in package.json
Node file:
{
"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",
...
}
}
Just a few tips from the 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.
That this is so you can check if you type 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]
I found the following solution to be easiest to setup environment variable for Webpack 2:
For example we have a webpack settings:
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;
Add Environment Variable in Webpack:
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
]
Define Plugin Variable and add it to plugins
:
new webpack.DefinePlugin({
'NODE_ENV': JSON.stringify(env.NODE_ENV || 'development')
}),
Now when running webpack command, pass env.NODE_ENV
as argument:
webpack --env.NODE_ENV=development
// OR
webpack --env.NODE_ENV development
Now you can access NODE_ENV
variable anywhere in your code.
I prefer using .env file for different environment.
- Use webpack.dev.config to copy
env.dev
to .env into root folder - Use webpack.prod.config to copy
env.prod
to .env
and in code
use
require('dotenv').config();
const API = process.env.API ## which will store the value from .env file
My workaround for the webpack version "webpack": "^4.29.6"
is very simple.
//package.json
{
...
"scripts": {
"build": "webpack --mode production",
"start": "webpack-dev-server --open --mode development"
},
}
you can pass --mode parameter with your webpack commnad then in 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'
})
}
}
And I use baseurl in my code like this
// my api service
import config from 'config';
console.log(config.apiUrl) // like fetch(`${config.apiUrl}/users/user-login`)
To add to the bunch of answers:
Use ExtendedDefinePlugin instead of DefinePlugin
npm install extended-define-webpack-plugin --save-dev.
ExtendedDefinePlugin is much simpler to use and is documented :-) link
Because DefinePlugin lacks good documentation, I want to help out, by saying that it actually works like #DEFINE in c#.
#if (DEBUG)
Console.WriteLine("Debugging is enabled.");
#endif
Thus, if you want to understand how DefinePlugin works, read the c# #define doucmentation. link
dotenv-webpack
A secure webpack plugin that supports dotenv and other environment variables and only exposes what you choose and use.
with some workaround with configuration based on defaults
option to achieve that, once the package has .env.defaults
file to as initial values for env variables you can use it for development
and let .env
for your production.
Usage
- install the package
npm install dotenv-webpack --save-dev
- Create a
.env.defaults
file
API_URL='dev_url/api/'
- create a
.env
file leave it empty, letdefaults
works, update it on your deploy process - config
webpack
-webpack.config.js
new Dotenv({
defaults: true
})
- dev environement test
file.js
console.log(process.env.API_URL)
// Outputs: dev_url/api/
- on build, update empty
.env
file
API_URL='prod_url/api/'
dotenv-webpack will use this to and override env.defaults
- prod environement test
file.js
console.log(process.env.API_URL)
// Outputs: prod_url/api/
dotenv-webpack
dotenv-defaults
Since Webpack v4, simply setting mode
in your Webpack config will set the NODE_ENV
for you (via DefinePlugin
). Docs here.
Here is a way that has worked for me and has allowed me keep my environment variables DRY by reusing a json file.
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
}),
I'm not a huge fan of...
new webpack.DefinePlugin({
'process.env': envVars
}),
...as it does not provides any type of security. instead, you end up boosting your secret stuff, unless you add a webpack to gitignore
本文标签: javascriptPassing environmentdependent variables in webpackStack Overflow
版权声明:本文标题:javascript - Passing environment-dependent variables in webpack - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736689904a1947865.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论