share_this_document plugin page htmlwebpackplugin doc_page cannot body app javascript webpack

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.

  1. Utilice webpack.dev.config para copiar env.dev a .env en la carpeta raíz
  2. 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 } }

Source


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"'' } } }), ... ] };

Gracias a ross allen