javascript - plugin - Pasar variables dependientes del entorno en webpack
webpack html css js (15)
Estoy tratando de convertir una aplicación angular de gulp a webpack. en gulp utilizo gulp-preprocess para reemplazar algunas variables en la página html (por ejemplo, nombre de la base de datos) dependiendo del NODE_ENV. ¿Cuál es la mejor manera de lograr un resultado similar con webpack?
Aquí hay una forma que me ha funcionado y me ha permitido mantener SECAS mis variables de entorno reutilizando un archivo json.
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
}),
Desde Webpack v4, simplemente configurando el
mode
en su configuración de Webpack configurará el
NODE_ENV
por usted (a través de
DefinePlugin
).
Documentos aquí.
Encontré que la siguiente solución es la más fácil de configurar variable de entorno para Webpack 2:
Por ejemplo, tenemos una configuración de paquete web:
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;
Agregar variable de entorno en Webpack:
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: ''development'',
}),
]
Defina la variable del complemento y agréguelo a los
plugins
:
new webpack.DefinePlugin({
''NODE_ENV'': JSON.stringify(env.NODE_ENV || ''development'')
}),
Ahora, cuando ejecute el comando webpack, pase
env.NODE_ENV
como argumento:
webpack --env.NODE_ENV=development
// OR
webpack --env.NODE_ENV development
Ahora puede acceder a la variable
NODE_ENV
en cualquier parte de su código.
Hay dos formas básicas de lograr esto.
DefinePlugin
new webpack.DefinePlugin({
''process.env.NODE_ENV'': JSON.stringify(process.env.NODE_ENV || ''development'')
}),
Tenga en cuenta que esto solo reemplazará las coincidencias "tal cual". Es por eso que la cadena tiene el formato que tiene. Podría tener una estructura más compleja, como un objeto allí, pero se entiende la idea.
Medio ambiente
new webpack.EnvironmentPlugin([''NODE_ENV''])
EnvironmentPlugin
utiliza
DefinePlugin
internamente y asigna los valores del entorno para codificarlos.
Sintaxis Terser.
Alias
Alternativamente, podría consumir la configuración a través de un módulo con alias . Desde el lado del consumidor se vería así:
var config = require(''config'');
La configuración en sí misma podría verse así:
resolve: {
alias: {
config: path.join(__dirname, ''config'', process.env.NODE_ENV)
}
}
Digamos que
process.env.NODE_ENV
es
development
.
Entonces se
./config/development.js
en
./config/development.js
.
El módulo al que se asigna puede exportar configuraciones como esta:
module.exports = {
testing: ''something'',
...
};
Investigué un par de opciones sobre cómo establecer variables específicas del entorno y terminé con esto:
Tengo 2 configuraciones webpack actualmente:
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'')
}
}),
En mi código obtengo el valor de API_URL de esta manera (breve):
const apiUrl = process.env.API_URL;
EDITAR 3 de noviembre de 2016
Webpack docs tiene un ejemplo: 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")
})
Con
ESLint
, debe permitir específicamente variables indefinidas en el código, si tiene
no-undef
regla
no-undef
.
http://eslint.org/docs/rules/no-undef
así:
/*global TWO*/
console.log(''Running App version '' + TWO);
EDITAR 7 de septiembre de 2017 (Crear-Reaccionar-Aplicación específica)
Si no está interesado en configurar demasiado, consulte Crear-Reaccionar-Aplicación: Crear-Reaccionar-Aplicación - Agregar variables de entorno personalizadas . Debajo del capó, CRA usa Webpack de todos modos.
No sé por qué, pero nadie menciona realmente la solución más simple. Esto funciona para mí para nodejs y gruñido. Como para muchas personas, el paquete web puede ser confuso, simplemente puede usar la siguiente línea:
process.env.NODE_ENV = ''production'';
Con la solución anterior, realmente no necesita usar envify o webpack. A veces, la solución simple codificada puede funcionar para algunas personas.
No soy un gran admirador de ...
new webpack.DefinePlugin({
''process.env'': envVars
}),
... ya que no proporciona ningún tipo de seguridad. en cambio, terminas aumentando tus cosas secretas, a menos que agregues un paquete web a gitignore 🤷♀️ hay una mejor solución.
Básicamente con esta configuración, una vez que compila su código, todas las variables env del proceso se eliminarán de todo el código, no habrá un solo proceso.env.VAR gracias al complemento babel
transform-inline-environment-variables
PS si no desea terminar con un montón de indefinidos, asegúrese de llamar a env.js antes de que webpack llame a babel-loader, por eso es lo primero que llama webpack.
la matriz de vars en el archivo babel.config.js debe coincidir con el objeto en env.js.
ahora solo hay una cosa para cortar.
agregue un archivo
.env
coloque todas sus variables env allí, el archivo debe estar en la raíz del proyecto o siéntase libre de agregarlo donde lo desee, solo asegúrese de establecer la misma ubicación en el archivo env.js y también agregue a gitignore
const dotFiles = [''.env''].filter(Boolean);
if (existsSync(dotFiles)) {
require("dotenv-expand")(require("dotenv").config((dotFiles)));
}
Si desea ver todo el babel + webpack + ts, consígalo en heaps
https://github.com/EnetoJara/Node-typescript-babel-webpack.git
y la misma lógica se aplica para reaccionar y todos los demás 💩
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
}
})();
archivo webpack sin complementos troll
"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"],
};
};
Para agregar al conjunto de respuestas:
Use ExtendedDefinePlugin en lugar de DefinePlugin
npm install extended-define-webpack-plugin --save-dev.
ExtendedDefinePlugin es mucho más simple de usar y está documentado :-) link
Debido a que DefinePlugin carece de buena documentación, quiero ayudar, diciendo que en realidad funciona como #DEFINE en c # .
#if (DEBUG)
Console.WriteLine("Debugging is enabled.");
#endif
Por lo tanto, si desea comprender cómo funciona DefinePlugin, lea la documentación de c # #define. link
Para agregar al grupo de respuestas personalmente, prefiero lo siguiente:
{"version": "0.0.1"}
Al usar esto, no hay variables funky env o problemas multiplataforma (con env vars).
Todo lo que debe hacer es ejecutar el
webpack
normal o el
webpack -p
para desarrollo o producción respectivamente.
Referencia: problema de Github
Prefiero usar el archivo .env para diferentes entornos.
-
Utilice webpack.dev.config para copiar
env.dev
a .env en la carpeta raíz -
Use webpack.prod.config para copiar
env.prod
a .env
y en código
utilizar
require(''dotenv'').config(); const API = process.env.API ## which will store the value from .env file
Puede pasar
cualquier
argumento de línea de comandos
sin complementos adicionales
usando
--env
desde webpack 2:
webpack --config webpack.config.js --env.foo=bar
Usando la variable en webpack.config.js:
module.exports = function(env) {
if (env.foo === ''bar'') {
// do something
}
}
Puede usar directamente el
EnvironmentPlugin
disponible en el
webpack
para tener acceso a cualquier variable de entorno durante la transpilación.
Solo tiene que declarar el complemento en su archivo
webpack.config.js
:
var webpack = require(''webpack'');
module.exports = {
/* ... */
plugins = [
new webpack.EnvironmentPlugin([''NODE_ENV''])
]
};
Tenga en cuenta que debe declarar explícitamente el nombre de las variables de entorno que desea utilizar.
Solo otra opción, si desea usar solo una interfaz cli, simplemente use la opción de definición de webpack.
Agrego el siguiente script en mi
package.json
:
"build-production": "webpack -p --define process.env.NODE_ENV=''/"production/"'' --progress --colors"
Entonces solo tengo que ejecutar
npm run build-production
.
Solo otra respuesta que es similar a la respuesta de @ zer0chain. Sin embargo, con una distinción.
Configurar
webpack -p
es suficiente.
Es lo mismo que:
--define process.env.NODE_ENV="production"
Y esto es lo mismo que
// webpack.config.js
const webpack = require(''webpack'');
module.exports = {
//...
plugins:[
new webpack.DefinePlugin({
''process.env.NODE_ENV'': JSON.stringify(''production'')
})
]
};
Por lo tanto, es posible que solo necesite algo como esto en el archivo
package.json
Node:
{
"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",
...
}
}
Solo algunos consejos de DefinePlugin :
DefinePlugin le permite crear constantes globales que se pueden configurar en tiempo de compilación. Esto puede ser útil para permitir un comportamiento diferente entre las compilaciones de desarrollo y las de lanzamiento. Por ejemplo, puede usar una constante global para determinar si se realiza el registro; quizás realice el inicio de sesión en su compilación de desarrollo pero no en la compilación de lanzamiento. Ese es el tipo de escenario que facilita el DefinePlugin.
Que esto es para que pueda verificar si escribe
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]
Como mi edición en la publicación anterior de thevangelist no fue aprobada , publico información adicional.
Si desea elegir el valor de package.json como un número de versión definido y acceder a él a través de DefinePlugin dentro de Javascript.
const PACKAGE = require(''../package.json'');
const _version = PACKAGE.version;//Picks the version number from package.json
Luego, importe package.json dentro del respectivo webpack.config , acceda al atributo usando la variable de importación, luego use el atributo en 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.
}
}),
Por ejemplo, cierta configuración en webpack.config está utilizando METADATA para DefinePlugin:
this.versionNumber = process.env.VERSION;
Acceda a esto dentro de cualquier archivo mecanografiado:
// webpack.config.js
plugins: [
new webpack.DefinePlugin({
VERSION: JSON.stringify(require("./package.json").version)
})
]
La forma más inteligente sería así:
const webpack = require(''webpack'');
const prod = process.argv.indexOf(''-p'') !== -1;
module.exports = {
...
plugins: [
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: prod? `"production"`: ''"development"''
}
}
}),
...
]
};