你盼世界,我盼望你無bug
。Hello 你們好!我是霖呆呆!javascript
什麼?!你還想要"呆妹"
出來給你講webpack
?!小夥子,你的想法很危險❌啊。html
不可能的,下次想要見到"她"
可能要等到呆呆5000
粉的時候吧😒。在這以前我毫不可能再女裝👚了 😊。前端
(因此請醒醒吧,你看到的那麼可愛的萌妹是一個帥哥!這個帥哥他迷惑了你!固然我現實生活中不叫帥哥哈,由於我在廣東,因此他們通常都叫我靚仔)vue
另外關於「霖呆呆的webpack之路系列」的教材案例我更新了github的地址哦,以前那個太亂了我給刪了,如今全部的教材案例都是同一個項目,不過不一樣的分支上能夠下載單獨的案例,主幹上是全部的案例。具體下載方式請仔細閱讀github上的README。(github.com/LinDaiDai/w…)java
霖呆呆向你發起了多人學webpacknode
請選擇:☑️接受 ⭕️拒絕webpack
此係列記錄了我在webpack
上的學習歷程。若是你也和我同樣想要好好的掌握webpack
,,那麼我認爲它對你是有必定幫助的,由於教材中是以一名webpack
小白的身份進行講解, 案例demo
也都很詳細, 涉及到:git
建議先mark
再花時間來看。github
(其實這個系列在很早以前就寫了,一直沒有發出來,當時還寫了一大長串前言可把我感動的,想看廢話的能夠點這裏:GitHub地址,不過如今讓咱們正式開始學習吧)web
全部文章webpack
版本號^4.41.5
, webpack-cli
版本號^3.3.10
。
在webpack3
中,webpack
自己和它的CLI
都是在同一個包中,但在第4版中,二者分開來了,也是爲了讓咱們更好地管理它們。
經過閱讀本篇文章你能夠學習到:
每次要編譯代碼時,手動運行 npm run build
就會變得很麻煩。
不知道你有沒有使用過相似於vue-cli
這樣的腳手架工具, 在使用它們的時候, 每次只要執行npm run start
這樣的指令就能夠建立一個本地的web
服務器, 而後打開一個例如localhost:8080
這樣的端口頁面, 同時還有熱更新等功能.
其實這些功能的實現都是vue-cli
內部使用了webpack
.
webpack
中有幾個不一樣的選項,能夠幫助你在代碼發生變化後自動編譯代碼.
(第一節教材案例GitHub地址: LinDaidai/webpack-example/tree/webpack-server ⚠️:請仔細查看README說明)
觀察者模式, 只須要在package.json
裏配置一個腳本命令:
"scripts": {
"watch": "webpack --watch"
}
複製代碼
使用npm run watch
命令以後, 會看到編譯過程, 可是不會退出命令行, 而是實時監控文件.
好比你在從新修改了本地的代碼並保存後, 它會從新進行編譯, 不須要咱們手動再執行編譯指令, 缺點是你須要手動刷新頁面才能看到更改效果.
(--watch
也能夠簡寫爲-w
)
使用webpack-dev-server
會爲你提供一個簡單的web服務器, 它的做用就是監聽文件的改變並自動編譯, 同時會自動刷新頁面. 比觀察者模式厲害.
使用步驟:
安裝: $ npm i --save-dev webpack-dev-server
添加腳本命令: "start": "webpack-dev-server --open"
使用此指令效果:
不會生成dist
文件夾, 而是開啓了一個本地的web服務器localhost:8080
每次修改了本地代碼以後, 都會從新自動編譯, 並刷新頁面
其它配置項:
webpack-dev-server
也有不少配置項能在webpack.config.js
中配置
只須要在devServer
裏進行配置, 例如:
module.exports = {
devServer: {
contentBase: './dist', // 告訴服務器從哪裏提供內容
host: '0.0.0.0', // 默認是 localhost
port: 8000, // 端口號, 默認是8080
open: true, // 是否自動打開瀏覽器
hot: true, // 啓用 webpack 的模塊熱替換特性
hotOnly: true // 當編譯失敗以後不進行熱更新
}
}
複製代碼
若是你使用了這個功能以後, 你就會發現, 它就有點vue-cli
的樣子了.
更多關於devServer
的配置能夠查看這裏: 開發中Server。
webpack-dev-middleware
是一個容器(wrapper),它能夠把 webpack 處理後的文件傳遞給一個服務器(server)。
webpack-dev-server
可以開啓一個本地的web
服務器, 就是由於在內部使用了它,可是, 它也能夠做爲一個包來單獨使用.
這裏我就以官方的案例來進行講解.
使用webpack-dev-middleware
配合express server
來介紹它的功能.
(express
是一個很精簡的Node.js
開發框架,若是你以前沒用過也不要緊,使用起來很簡單。)
先來講下個人需求, 我想要實現一個這個功能:
script
指令讓它能運行一個本地web
服務器(也就是可以在localhost: 3000
中查看頁面)$ npm i --save-dev webpack-dev-middleware express
複製代碼
server.js
文件用來編寫本地服務:// server.js
const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const app = express()
const config = require('./webpack.config')
const compiler = webpack(config)
// 把 webpack 處理後的文件傳遞給一個服務器
app.use(webpackDevMiddleware(compiler))
app.listen(3000, function() {
console.log('Example app listening on port 3000!\n');
})
複製代碼
package.json
裏配置指令運行server.js
:{
"scripts": {
"server": "node server.js"
}
}
複製代碼
在學習這裏的時候, 我順便也瞭解到了webpack.config.js
中output
的另外一個屬性publicPath
.
開始看文檔 output.outputPath的時候沒太看懂.
後來我結合webpack-dev-middleware
來試了一下它.
首先修改一下webpack.config.js
的配置:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
devtool: 'inline-source-map', // 僅開發環境報錯追蹤
plugins: [
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['dist']
}),
new HtmlWebpackPlugin({
title: 'Webpack Output2',
filename: 'index.html',
template: 'src/index.html'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
+ publicPath: '/assets/'
}
}
複製代碼
而後修改一下server.js
:
// server.js
const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const app = express()
const config = require('./webpack.config')
const compiler = webpack(config)
// 把webpack 處理後的文件傳遞給一個服務器
app.use(webpackDevMiddleware(compiler
+ ,{
+ publicPath: config.output.publicPath
+ }
))
app.listen(3000, function() {
console.log('Example app listening on port 3000!\n');
})
複製代碼
保存上面👆兩個文件, 而後從新執行npm run server
, 打開localhost:3000
會發現頁面顯示的是:
Cannot GET /
複製代碼
你須要打開localhost:3000/assets/
才能看到正確的頁面.
而且若是項目裏有對資源的引用的話, 也會自動加上publicPath
的前綴:
icon.png => 變爲 /assets/icon.png
複製代碼
此選項指定在瀏覽器中所引用的「此輸出目錄對應的公開 URL」。
注⚠️:
若是沒有配置output.publicPath
和webpack-dev-middleware
的publicPath
, 則默認都會是""
,以根目錄做爲配置項。
若是配置了output.publicPath
, 則webpack-dev-middleware
中的publicPath
也要和它同樣才行。
開發環境和生產環境的構建目標差別是很是大的.
因此爲了遵循邏輯分離, 咱們能夠爲每一個環境編寫彼此獨立的webpack配置.
雖然說是想要編寫各自獨立的配置, 可是確定也有一些公用的配置項, 咱們能夠將這些公用的配置項提取出來, 而後不一樣的配置寫在不一樣的文件中.
(第二節教材案例GitHub地址: LinDaidai/webpack-example/webpak-merge ⚠️:請仔細查看README說明)
最終, 爲了將這些配置項合併在一塊兒, 咱們須要用到webpack-merge
工具.
首先安裝這個工具:
$ npm i --save-dev webpack-merge
複製代碼
而後讓咱們將本來的webpack.config.js
拆開, 編寫成三個不一樣的webpack配置文件:
webpack-demo
|- package.json
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
|- /dist
|- /src
|- index.js
|- math.js
|- /node_modules
複製代碼
webpack.common.js:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'webpack bundle'
})
]
}
複製代碼
webpack.dev.js:
const merge = require('webpack-merge')
const commonConfig = require('./webpack.common')
module.exports = merge(commonConfig, {
devtool: 'inline-source-map', // 錯誤追蹤
devServer: { // 設置 webpack-dev-server 監聽的文件
contentBase: './dist'
}
})
複製代碼
webpack.prod.js:
const merge = require('webpack-merge')
const commonConfig = require('./webpack.common')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
module.exports = merge(commonConfig, {
plugins: [
new UglifyJSPlugin() // 壓縮輸出
]
})
複製代碼
能夠看到, webpack-merge
的功能就是將多個webpack
的配置合併成一個.
如今讓咱們再來配置一下package.json
的腳本命令:
package.json:
{
"name": "webpack-bundle",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"html-webpack-plugin": "^3.2.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.3",
"webpack-merge": "^4.2.2"
}
}
複製代碼
npm run start
爲開發環境, 會自動打開localhost:8080
頁面而且有自動重載功能npm run build
爲生產環境, 會打包生成dist
文件夾, 且bundle
中js
爲壓縮事後的代碼.process.env.NODE_ENV
的做用主要是幫咱們判斷是開發環境(development)仍是生產環境(production).
技術上講,NODE_ENV
是一個由 Node.js 暴露給執行腳本的系統環境變量。
src
的本地代碼中引用到它:// print.js
export function print() {
console.log(process.env.NODE_ENV) // development 或者 prodution
}
複製代碼
webpack.config.js
中卻獲取不到它, 打印出來是undefined
.因此像如下代碼是不能像預期同樣實現的:process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js'
複製代碼
以前介紹過了, 咱們是不能在webpack.config.js
中獲取到process.env.NODE_ENV
的值的, 可是咱們可使用webpack
內置的DefinePlugin
插件來修改這個變量.
例如我在webpack.prod.js
中的配置:
+ const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const commonConfig = require('./webpack.common.js');
module.exports = merge(commonConfig, {
devtool: 'source-map',
plugins: [
new UglifyJSPlugin({
sourceMap: true
- })
+ }),
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify('production')
+ })
]
});
複製代碼
使用webpack.DefinePlugin()
方法修改了process.env.NODE_ENV
.
你能夠設置成JSON.stringify('production')
, 也能夠設置成:
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': `"production"`
}
})
複製代碼
除了使用webpack.DefinePlugin
插件來修改環境變量的模式, 還能夠在命令行中修改它:
webpack --mode=production
或者
webpack --mode=development
複製代碼
使用了--mode
設置環境變量模式, 在本地代碼上獲取到的process.env.NODE_ENV
的值就是mode
的值.
不過若是你同時在命令行中設置的--mode
, 又使用了webpac.definePlugin
插件, 後者的優先級高點.
若是咱們在命令行中經過--env
來設置一些變量值, 這些變量值能使咱們在webpack.config.js的配置中訪問到.
在webpack命令行配置中, 經過設置 --env
可使你根據須要,傳入儘量多的環境變量
例如我新建了一個命令行:
{
"scripts": {
"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
+ "local": "webpack --env.custom=local --env.production --progress --config webpack.local.js"
}
}
複製代碼
拆開來看:
--env.custom=local
給環境變量中設置一個自定義的屬性 custom
, 它的值爲local
--env.production
設置env.production == true
(這裏的env
並不會影響process.env
)--progress
打印出編譯進度的百分比值--config webpack.local.js
以webpack.local.js
中的內容執行webpack構建同時我在項目根目錄下建立一個wepack.local.js
:
const commonConfig = require('./webpack.common')
const merge = require('webpack-merge')
module.exports = env => {
console.log('custom: ', env.custom) // 'local'
console.log('Production: ', env.production) // true
return merge(commonConfig, {})
}
複製代碼
能夠看到它與廣泛的webpack.config.js
的區別在於, 它導出的是一個函數, 且這個函數中能訪問env
環境變量.
這樣咱們就能夠將在命令行中設置的變量獲取到了.
還記得咱們以前說, 在webpack.config.js
中是不能獲取到環境變量process.env.NODE_ENV
, 也就是不能作如下判斷:
process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js'
複製代碼
可是如今咱們在命令行裏傳遞一個變量進去, 好比叫作NODE_ENV
, 這樣就能夠在webpack.config.js
裏做區分了.
讓咱們在根目錄下建立一個名爲webpack.combine.js
的配置文件:
webpack.combine.js:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = env => {
return {
entry: './src/index.js',
output: {
filename: env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: '合併成同一個webpack配置'
})
]
}
}
複製代碼
咱們能夠看到ouput.filename
,能夠經過NODE_ENV
來判斷.
因此我須要在package.json
中進行參數的傳遞:
{
"name": "webpack-bundle",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
"local": "webpack --env.custom=local --env.production=false --mode=development --progress --config webpack.local.js",
+ "combine-dev": "webpack --env.NODE_ENV=development --config webpack.combine.js",
+ "combine-prod": "webpack --env.NODE_ENV=production --config webpack.combine.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"html-webpack-plugin": "^3.2.0",
"lodash": "^4.17.15",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.3",
"webpack-merge": "^4.2.2"
}
}
複製代碼
如今分別執行combine-dev
和combine-prod
, 能夠看到生成的bundle又不一樣的效果.
combine-dev
生成的js文件是main.bundle.js
combine-prod
生成的js文件是main.a79eb0c94212b905d48b.bundle.js
可是有一點須要注意的是這裏的env.NODE_ENV並非process.env.NODE_ENV, 因此它並不能改變process.env
.
也就是說無論你經過哪一種方式生成的頁面, 你在頁面中獲取到的process.env.NODE_ENV
都仍是production
.
webpack-merge
工具幫助咱們將多個配置文件合併成一個webpack.config.js
獲取不到環境變量process
webpack.DefinePlugin
插件幫助咱們修改process.env
的值CLI
中的 --mode
來修改環境變量的模式webpack.config.js
導出的是一個函數, 則容許咱們在命令行中用 --env
傳遞環境變量注意⚠️:其實「霖呆呆的webpack之路系列」全部的教材案例都是同一個項目,不過不一樣的分支上能夠下載單獨的案例,主分支上是全部的案例。具體下載方式請仔細閱讀github上的README。
知識無價,支持原創。
參考文章:
喜歡霖呆呆的小夥還但願能夠關注霖呆呆的公衆號 LinDaiDai
或者掃一掃下面的二維碼👇👇👇.
我會不定時的更新一些前端方面的知識內容以及本身的原創文章🎉
你的鼓勵就是我持續創做的主要動力 😊.
相關推薦:
《【建議星星】要就來45道Promise面試題一次爽到底(1.1w字用心整理)》
《【建議👍】再來40道this面試題酸爽繼續(1.2w字用手整理)》
《【何不三連】比繼承家業還要簡單的JS繼承題-封裝篇(牛刀小試)》