ฉันพยายามแปลงแอพเชิงมุมจากอึกเป็น webpack ในอึกฉันใช้ gulp-preprocess เพื่อแทนที่ตัวแปรบางอย่างในหน้า html (เช่นชื่อฐานข้อมูล) ขึ้นอยู่กับ NODE_ENV วิธีที่ดีที่สุดในการบรรลุผลลัพธ์ที่คล้ายกันกับ webpack คืออะไร
ฉันพยายามแปลงแอพเชิงมุมจากอึกเป็น webpack ในอึกฉันใช้ 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
ภายในและแมปค่าสภาพแวดล้อมเพื่อให้รหัสผ่าน Terser ไวยากรณ์
หรือคุณสามารถใช้การกำหนดค่าผ่านโมดูล aliased จากด้านผู้บริโภคมันจะเป็นดังนี้:
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',
...
};
JSON.stringify()
'process.env.NODE_ENV': `"${process.env.NODE_ENV || 'development'}"`
JSON.stringify('development')
ตามที่อาจไม่เป็นประโยชน์จริงๆ แต่JSON.stringify(someVariable)
ค่อนข้างสามารถ!
NODE_ENV
ให้ทำเช่นนั้น วิธีการตั้งค่าที่ขึ้นอยู่กับแพลตฟอร์มของคุณ
process.env.NODE_ENV
รูปแบบและใช้งานได้
ตัวเลือกอื่นถ้าคุณต้องการใช้เฉพาะส่วนต่อประสาน cli ให้ใช้define
ตัวเลือกของ webpack ฉันเพิ่มสคริปต์ต่อไปนี้ในของฉันpackage.json
:
"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"
npm run build-production
ดังนั้นผมก็ต้องทำงาน
ฉันตรวจสอบสองสามตัวเลือกเกี่ยวกับวิธีการตั้งค่าตัวแปรเฉพาะสภาพแวดล้อมและจบลงด้วยสิ่งนี้:
ฉันมี 2 webpack configs อยู่ในขณะนี้:
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;
แก้ไข 3 พฤศจิกายน 2016
เอกสาร 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);
แก้ไขเมื่อวันที่ 7 ก.ย. 2017 (เฉพาะการสร้างแอป React)
หากคุณไม่ได้เป็นการกำหนดค่ามากเกินไปตรวจสอบสร้าง-React-App: สร้าง-React-App - การเพิ่มตัวแปรสภาพแวดล้อมที่กำหนดเอง ภายใต้ประทุน CRA ใช้ Webpack อยู่ดี
process.env
แล้วprocess.env.PORT
ตัวอย่างเช่นไม่สามารถแก้ไขได้undefined
ในระหว่างการสร้าง webpack ซึ่งหมายความว่าคุณจะไม่สามารถแทนที่พอร์ตจากสภาพแวดล้อมได้อีกต่อไป?
คุณสามารถส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่งใด ๆโดยไม่ต้องใช้ปลั๊กอินเพิ่มเติม--env
ตั้งแต่ webpack 2:
webpack --config webpack.config.js --env.foo=bar
การใช้ตัวแปรใน webpack.config.js:
module.exports = function(env) {
if (env.foo === 'bar') {
// do something
}
}
คุณสามารถใช้สิ่งที่EnvironmentPlugin
มีอยู่ในwebpack
เพื่อเข้าถึงตัวแปรสภาพแวดล้อมใด ๆ ในระหว่างการถ่ายโอน
คุณต้องประกาศปลั๊กอินใน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"'
}
}
}),
...
]
};
การใช้สิ่งนี้ไม่มีตัวแปร env ขี้ขลาดหรือปัญหาข้ามแพลตฟอร์ม (กับ env vars) สิ่งที่คุณทำคือเรียกใช้ปกติwebpack
หรือwebpack -p
สำหรับ dev หรือผลิตตามลำดับ
การอ้างอิง: ปัญหา Github
'process.env.NODE_ENV': JSON.stringify('production')
process: { env: { NODE_ENV: JSON.stringify('production') } }
การใช้หลังจะเขียนทับวัตถุกระบวนการซึ่งสามารถทำลายความเข้ากันได้กับบางโมดูลที่คาดว่าค่าอื่น ๆ บนวัตถุกระบวนการที่จะกำหนด
เนื่องจากการแก้ไขของฉันในการโพสต์ข้างต้นโดย thevangelistไม่ได้รับการอนุมัติการโพสต์ข้อมูลเพิ่มเติม
หากคุณต้องการเลือกค่าจากpackage.jsonเช่นหมายเลขรุ่นที่กำหนดและเข้าถึงผ่านDefinePluginภายใน Javascript
{"version": "0.0.1"}
จากนั้นนำเข้าpackage.jsonภายในแต่ละwebpack.configเข้าถึงแอตทริบิวต์ใช้ตัวแปรนำเข้าจากนั้นใช้แอตทริบิวต์ในDefinePlugin
const PACKAGE = require('../package.json');
const _version = PACKAGE.version;//Picks the version number from package.json
ตัวอย่างเช่นการกำหนดค่าบางอย่างบนwebpack.configกำลังใช้ METADATA สำหรับ 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.
}
}),
เข้าถึงสิ่งนี้ภายในไฟล์ typescript ใด ๆ :
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
ไฟล์ 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",
...
}
}
เพียงไม่กี่เคล็ดลับจาก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]
วิธีเพิ่มคำตอบ:
ใช้ExtendedDefinePluginแทน DefinePlugin
npm install extended-define-webpack-plugin --save-dev.
ExtendedDefinePlugin นั้นใช้ง่ายกว่ามากและมีลิงก์เอกสาร :-)
เพราะ DefinePlugin ขาดเอกสารที่ดีผมต้องการที่จะช่วยออกโดยบอกว่ามันใช้งานได้จริงเช่น#define ใน c #
#if (DEBUG)
Console.WriteLine("Debugging is enabled.");
#endif
ดังนั้นหากคุณต้องการเข้าใจวิธีการทำงานของ DefinePlugin ให้อ่าน c # #define doucmentation ลิงค์
ฉันชอบใช้ไฟล์. env สำหรับสภาพแวดล้อมที่แตกต่างกัน
env.dev
ไปยัง. env ลงในโฟลเดอร์ root env.prod
ไปยัง. envและในรหัส
ใช้
require('dotenv').config();
const API = process.env.API ## which will store the value from .env file
ฉันพบวิธีแก้ไขปัญหาต่อไปนี้เพื่อให้ง่ายที่สุดในการตั้งค่าตัวแปรสภาพแวดล้อมสำหรับ 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
ตัวแปรได้ทุกที่ในรหัสของคุณ
ตั้งแต่ Webpack v4 เพียงแค่ตั้งค่าmode
ใน Webpack config ของคุณจะตั้งค่าNODE_ENV
ให้คุณ (ผ่านDefinePlugin
) เอกสารที่นี่
นี่เป็นวิธีที่ใช้ได้ผลสำหรับฉันและอนุญาตให้ฉันเก็บตัวแปรสภาพแวดล้อมของฉันไว้ที่ DRY ด้วยการนำไฟล์ json กลับมาใช้ใหม่
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
}),
ฉันไม่ใช่แฟนตัวยงของ ...
new webpack.DefinePlugin({
'process.env': envVars
}),
... เนื่องจากไม่มีการรักษาความปลอดภัยทุกประเภท คุณจะเพิ่มความลับของคุณได้เว้นแต่คุณจะเพิ่ม webpack ใน gitignore 🤷♀️ มีทางออกที่ดีกว่า
โดยทั่วไปด้วยการตั้งค่านี้เมื่อคุณรวบรวมรหัสของคุณตัวแปร env กระบวนการทั้งหมดจะถูกลบออกจากรหัสทั้งหมดจะไม่เป็นกระบวนการเดียว env.VAR ขึ้นขอบคุณด้วยปลั๊กอิน babel transform-inline-environment-variables
PS ถ้าคุณไม่ต้องการที่จะจบลง ด้วย undefines ทั้งหมดให้แน่ใจว่าคุณเรียก env.js ก่อนที่ webpack จะเรียก babel-loader นั่นเป็นเหตุผลว่าทำไมมันเป็นสิ่งแรกที่ webpack เรียก อาร์เรย์ของ vars ในไฟล์ babel.config.js ต้องตรงกับวัตถุใน env.js ตอนนี้มีเพียงสิ่งเดียวที่ต้องทำ เพิ่ม.env
ไฟล์ใส่ตัวแปร 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
และตรรกะเดียวกันนี้จะใช้กับการตอบโต้และ other อื่น ๆ ทั้งหมด
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
}
})();
ไฟล์ 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"],
};
};
ฉันไม่รู้ว่าทำไม แต่ไม่มีใครพูดถึงวิธีแก้ปัญหาที่ง่ายที่สุด มันใช้งานได้สำหรับ nodejs และ grunt สำหรับหลาย ๆ คน webpack อาจสร้างความสับสนคุณสามารถใช้บรรทัดด้านล่าง:
process.env.NODE_ENV = 'production';
ด้วยวิธีการข้างต้นคุณไม่จำเป็นต้องใช้ envify หรือ webpack บางครั้งโซลูชัน hardcoded ที่เรียบง่ายอาจใช้งานได้สำหรับบางคน