J'essaie de convertir une application angular de gulp à Webpack. J'utilise gulp-preprocess pour remplacer certaines variables de la page HTML (nom de la base de données, par exemple) en fonction de NODE_ENV. Quel est le meilleur moyen d'obtenir un résultat similaire avec webpack?
Il y a deux façons de base pour y parvenir.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
Notez que cela ne fera que remplacer les allumettes "telles quelles". C'est pourquoi la chaîne est dans le format qu'elle est. Vous pourriez avoir une structure plus complexe, comme un objet là-bas, mais vous avez l’idée.
new webpack.EnvironmentPlugin(['NODE_ENV'])
EnvironmentPlugin
utilise DefinePlugin
en interne et mappe les valeurs d'environnement sur lesquelles coder. Syntaxe Terser.
Sinon, vous pouvez utiliser la configuration via n module aliasé . Du côté du consommateur, cela ressemblerait à ceci:
var config = require('config');
La configuration elle-même pourrait ressembler à ceci:
resolve: {
alias: {
config: path.join(__dirname, 'config', process.env.NODE_ENV)
}
}
Disons que process.env.NODE_ENV
est development
. Il serait alors mappé dans ./config/development.js
. Le module auquel il correspond peut exporter la configuration de la manière suivante:
module.exports = {
testing: 'something',
...
};
Juste une autre option, si vous souhaitez utiliser uniquement une interface CLI, utilisez simplement l'option define
de webpack. J'ajoute le script suivant dans mon package.json
:
"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"
Donc, je dois juste exécuter npm run build-production
.
J'ai étudié quelques options sur la façon de définir des variables spécifiques à l'environnement et je me suis retrouvé avec ceci:
J'ai 2 config webpack actuellement:
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')
}
}),
Dans mon code, j'obtiens la valeur de API_URL de cette manière (brève):
const apiUrl = process.env.API_URL;
EDIT du 3 nov 2016
Les documents Webpack ont un exemple: 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")
})
Avec ESLint , vous devez autoriser spécifiquement les variables non définies dans le code, si vous avez la règle no-undef
. http://eslint.org/docs/rules/no-undef comme ceci:
/*global TWO*/
console.log('Running App version ' + TWO);
EDIT du 7 septembre 2017 (spécifique à Create-React-App)
Si vous n’aimez pas trop configurer, consultez Create-React-App: Create-React-App - Ajout de variables d’environnement personnalisées . Sous le capot, l'ARC utilise quand même Webpack.
Vous pouvez passer n’importe quel argument de ligne de commande sans plugins supplémentaires en utilisant --env
depuis le webpack 2:
webpack --config webpack.config.js --env.foo=bar
En utilisant la variable dans webpack.config.js:
module.exports = function(env) {
if (env.foo === 'bar') {
// do something
}
}
Vous pouvez directement utiliser le EnvironmentPlugin
disponible dans webpack
pour avoir accès à n’importe quelle variable d’environnement pendant la transpilation.
Il vous suffit de déclarer le plug-in dans votre fichier webpack.config.js
:
var webpack = require('webpack');
module.exports = {
/* ... */
plugins = [
new webpack.EnvironmentPlugin(['NODE_ENV'])
]
};
Notez que vous devez déclarer explicitement le nom des variables d'environnement que vous souhaitez utiliser.
Depuis mon édition sur le post ci-dessus par thevangelist n'a pas été approuvé , affichant des informations supplémentaires.
Si vous voulez choisir une valeur dans package.json comme un numéro de version défini et y accéder par DefinePlugin dans Javascript.
{"version": "0.0.1"}
Ensuite, Importez package.json à l'intérieur webpack.config respectif, accédez au attribuez en utilisant la variable import, puis utilisez-le dans DefinePlugin .
const PACKAGE = require('../package.json');
const _version = PACKAGE.version;//Picks the version number from package.json
Par exemple, certaines configurations sur webpack.config utilisent METADATA pour 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.
}
}),
Accédez à ceci dans n’importe quel fichier TypeScript:
this.versionNumber = process.env.VERSION;
Le moyen le plus intelligent serait comme ceci:
// webpack.config.js
plugins: [
new webpack.DefinePlugin({
VERSION: JSON.stringify(require("./package.json").version)
})
]
Pour ajouter personnellement aux réponses, je préfère ce qui suit:
const webpack = require('webpack');
const prod = process.argv.indexOf('-p') !== -1;
module.exports = {
...
plugins: [
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: prod? `"production"`: '"development"'
}
}
}),
...
]
};
En utilisant cela, il n’ya pas de variable funky env ou de problèmes multi-plateformes (avec env vars). Tout ce que vous faites est d'exécuter le webpack
ou webpack -p
normal pour le développement ou la production, respectivement.
Référence: numéro de Github
Juste une autre réponse similaire à celle de @ zer0chain. Cependant, avec une distinction.
webpack -p
est suffisant.C'est la même chose que:
--define process.env.NODE_ENV="production"
Et c'est pareil que
// webpack.config.js
const webpack = require('webpack');
module.exports = {
//...
plugins:[
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
};
Vous n’avez donc besoin que de quelque chose comme cela dans le fichier 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",
...
}
}
Quelques astuces de DefinePlugin :
DefinePlugin vous permet de créer des constantes globales pouvant être configurées lors de la compilation. Cela peut être utile pour autoriser un comportement différent entre les versions de développement et les versions de version. Par exemple, vous pouvez utiliser une constante globale pour déterminer si la journalisation a lieu ou non. peut-être que vous vous connectez dans votre version de développement, mais pas dans la version de publication. C'est le genre de scénario que DefinePlugin facilite.
Pour que vous puissiez vérifier si vous tapez 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]
Pour ajouter au tas de réponses:
Utilisez ExtendedDefinePlugin au lieu de DefinePlugin
npm install extended-define-webpack-plugin --save-dev.
ExtendedDefinePlugin est beaucoup plus simple à utiliser et est documenté :-) link
Parce que DefinePlugin manque une bonne documentation, je veux aider en disant que cela fonctionne réellement comme # DEFINE en c # .
#if (DEBUG)
Console.WriteLine("Debugging is enabled.");
#endif
Ainsi, si vous voulez comprendre le fonctionnement de DefinePlugin, lisez la documentation relative à c # #define. lien
J'ai trouvé la solution suivante plus facile à configurer pour la variable d'environnement pour Webpack 2:
Par exemple, nous avons un paramétrage 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;
Ajouter une variable d'environnement dans Webpack:
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
]
Définir une variable de plug-in et l'ajouter à plugins
:
new webpack.DefinePlugin({
'NODE_ENV': JSON.stringify(env.NODE_ENV || 'development')
}),
Maintenant, lors de l'exécution de la commande webpack, passez env.NODE_ENV
en tant qu'argument:
webpack --env.NODE_ENV=development
// OR
webpack --env.NODE_ENV development
Vous pouvez maintenant accéder à la variable NODE_ENV
n'importe où dans votre code.
Depuis Webpack v4, il vous suffit de définir mode
dans votre configuration Webpack pour configurer le NODE_ENV
(via DefinePlugin
). Docs here.
Je préfère utiliser le fichier .env pour différents environnements.
env.dev
dans .env dans le dossier racine.env.prod
dans .envet en code
utilisation
require('dotenv').config(); const API = process.env.API ## which will store the value from .env file
Voici une méthode qui a fonctionné pour moi et qui m'a permis de conserver mes variables d'environnement DRY en réutilisant un fichier 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
}),
Je ne suis pas un grand fan de ...
new webpack.DefinePlugin({
'process.env': envVars
}),
... car il ne fournit aucun type de sécurité. Au lieu de cela, vous finissez par renforcer vos données secrètes, à moins d’ajouter un pack Web à gitignore. Il existe une meilleure solution.
En gros, avec cette configuration, une fois que vous avez compilé votre code, toutes les variables d’environnement de processus seront supprimées de tout le code. Il n’y aura pas un seul processus.env.VAR grâce au plugin babel transform-inline-environment-variables
PS si vous le faites. Si vous ne voulez pas vous retrouver avec un tas d’indéfinis, assurez-vous d’appeler env.js avant que Webpack appelle babel-loader, c’est pourquoi il s’agit en premier lieu des appels de webpack. le tableau de vars dans le fichier babel.config.js doit correspondre à l'objet sur env.js. maintenant, il n'y a plus qu'une chose à faire. ajoutez un fichier .env
mettez toutes vos variables env ici, le fichier doit être à la racine du projet ou n'hésitez pas à l'ajouter où vous le souhaitez, assurez-vous de définir le même emplacement sur le fichier env.js et aussi l'ajouter à gitignore
const dotFiles = ['.env'].filter(Boolean);
if (existsSync(dotFiles)) {
require("dotenv-expand")(require("dotenv").config((dotFiles)));
}
Si vous voulez voir la totalité de babel + webpack +, obtenez-le de la façon suivante https://github.com/EnetoJara/Node-TypeScript-babel-webpack.git
et la même logique s'applique pour réagir et tous les autres ????
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
}
})();
fichier webpack sans plugin 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"],
};
};