介紹
1. 背景
最近和部門老大,一起在研究團(tuán)隊(duì)【EFT - 前端新手村】的建設(shè),目的在于:幫助新人快速了解和融入公司團(tuán)隊(duì)咨察,幫助零基礎(chǔ)新人學(xué)習(xí)和入門前端開發(fā)并且達(dá)到公司業(yè)務(wù)開發(fā)水平。
本文也是屬于【EFT - 前端新手村】的一部分呕臂,用來幫助新人快速入門 Webpack4
旦签,內(nèi)容偏基礎(chǔ)查坪,當(dāng)然也可以作為復(fù)習(xí)材料~~這里分享給各位小伙伴啦!
2. 文章概要
我將從最基礎(chǔ)的【項(xiàng)目初始化】開始介紹宁炫,到【處理 CSS / JS / 圖片】偿曙,到【熱更新,打包優(yōu)化】等等羔巢,一一介紹和實(shí)踐望忆。
文章共分為 18 章,關(guān)于最基礎(chǔ)的四個(gè)核心概念竿秆,可以到我整理的另一篇文章 《Webpack4 的四個(gè)核心概念》 中學(xué)習(xí)启摄。
3. 教程目錄
一、 項(xiàng)目初始化
1. 初始化 demo
新建并進(jìn)入文件夾 leo
:
mkdir leo
cd leo
然后本地安裝 webpack
和 webpack-cli
(在 Webpack 4.0以后需要單獨(dú)安裝):
npm install webpack webpack-cli --save-dev
初始化項(xiàng)目結(jié)構(gòu):
+ ├─package.json
+ ├─dist // 存放最終打包的文件
+ │ └─index.html
+ ├─src // 存放入口文件等開發(fā)文件
+ │ └─index.js
+ ├─webpack.config.js // webpack的配置文件
安裝 lodash
:
npm install lodash --save-dev
--save
可以簡寫為-S
, --save-dev
可以簡寫為-D
.
開發(fā) index.js
:
import _ from 'lodash';
function createElement(){
let div = document.createElement('div');
div.innerHTML = _.join(['my', 'name', 'is', 'leo'], '');
return div;
}
document.body.appendChild(createElement());
開發(fā) webpack.config.js
:
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: 'development',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
}
}
2. 打包測試
開始第一次打包任務(wù):
npx webpack
// 輸出:
Hash: 030b37b6b9a0b4344437
Version: webpack 4.39.1Time: 308ms
Built at: 2019-08-07 08:10:21
Asset Size Chunks Chunk Names
main.js 552 KiB main [emitted] main
Entrypoint main = main.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {main} [built][./src/index.js] 225 bytes {main} [built]
+ 1 hidden module
打包成功后袍辞,生成的文件會(huì)保存在 dist
目錄中鞋仍。
現(xiàn)在在 dist/index.html
中引入打包后的 main.js
,打開瀏覽器測試:
<script src="./main.js"></script>
二搅吁、 webpack 處理 CSS 模塊
這一部分威创,我們開始學(xué)著使用 webpack
去處理 css
相關(guān)的模塊落午。
1. 修改代碼
在項(xiàng)目 src
目錄中,新建 style
文件夾肚豺,并新建 index.css
文件:
├─package.json
├─dist // 存放最終打包的文件
│ └─index.html
├─src // 存放入口文件等開發(fā)文件
│ ├─index.js
+ │ └─style
+ │ └─index.css
├─webpack.config.js // webpack的配置文件
接著在 index.js
的新建元素方法中溃斋,添加 class
為 box
,這樣新建的元素就帶有 box
的 class
屬性:
// src/index.js
import _ from 'lodash';
import './style/index.css';// 引入樣式文件
function createElement(){
let div = document.createElement('div');
div.innerHTML = _.join(['my', 'name', 'is', 'leo'], '');
+ div.className = 'box';
return div;
}
document.body.appendChild(createElement());
然后在 index.css
文件為 box
:
// src/style/index.css
.box{
color: red;
}
注意:
這里使用 import './style/index.css';
引入我們的樣式文件吸申,是沒辦法解析使用梗劫,這時(shí)我們需要在 webpack
中使用到第三方 loader
插件,這里我們使用:
-
css-loader
: 用于處理css
文件截碴,使得能在 js 文件中引入使用残黑; -
style-loader
: 用于將css
文件注入到index.html
中的<style>
標(biāo)簽上颈娜;
2. 安裝配置插件
安裝插件:
npm install --save-dev style-loader css-loader
再到 webpack.config.js
中添加 css
解析的 loader
配置:
// webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
}
參數(shù)介紹:
test
:需要匹配的模塊后綴名;
use
:對應(yīng)處理的 loader 插件名稱(處理順序是從右往左)。
3. 打包測試
npx webpack
// 輸出:
Hash: 28b3965aa1b6a0047536
Version: webpack 4.39.1
Time: 482msBuilt at: 2019-08-09 07:45:25 Asset Size Chunks Chunk Names
main.js 565 KiB main [emitted] main
Entrypoint main = main.js
[./node_modules/_css-loader@3.2.0@css-loader/dist/cjs.js!./src/style/index.css] 190 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built][./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {main} [built][./src/index.js] 303 bytes {main} [built]
[./src/style/index.css] 447 bytes {main} [built]
+ 3 hidden modules
這時(shí)候可以看見 index.html
中雏亚,文本已經(jīng)變成紅色贬蛙,并且 css
代碼已經(jīng)添加到 <style>
標(biāo)簽上锦亦。
三马绝、 webpack 模塊介紹和處理 sass
在這一節(jié)中,我們會(huì)介紹 webpack
中的模塊束凑,并且介紹如何去處理 sass
文件晒旅。
1. webpack 模塊介紹
這里介紹的模塊(module)是指 webpack.config.js
文件中的 module
配置,它決定了如何處理項(xiàng)目中的不同類型模塊汪诉。
比如上一節(jié)介紹的废恋,使用 style-loader
、 css-loader
兩個(gè)插件去處理 css
文件摩瞎。
webpack
模塊支持如下語句:
- ES2015
import
語句拴签; - CommonJS
require()
語句; - AMD
define
和require
語句旗们; -
css/sass/less
文件中@import
語句蚓哩; - 樣式
(url(...))
或者 HTML 文件(<img src=...>)
中的圖片鏈接(image url)
;
這里建議使用 ES2015
的引入方法上渴,畢竟這是標(biāo)準(zhǔn)岸梨。
更多參數(shù)介紹,可訪問中文官網(wǎng)的介紹:
《webpack 配置選項(xiàng)》
2. 常用模塊
2.1 module.noParse
值的類型:RegExp | [RegExp] | function
防止 webpack
解析那些符合匹配條件的文件稠氮,忽略的文件夾中不應(yīng)該含有 import
曹阔、require
、define
的調(diào)用隔披,或任何其他導(dǎo)入機(jī)制赃份,忽略的 library
可以提高構(gòu)建效率。
// webpack.config.js
module: {
noParse: function(content){
return /jquery|lodash/.test(content);
}
}
2.2 module.rules
創(chuàng)建模塊時(shí),匹配請求的規(guī)則數(shù)組抓韩。按照規(guī)則為對應(yīng)模塊使用對應(yīng)的 loader
纠永,或修改解析器(parser)。
// webpack.config.js
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader']}
]
}
-
module.rules
參數(shù)有:
use
:為模塊使用指定 loader
谒拴,并且可以傳入一個(gè)字符串?dāng)?shù)組尝江,加載順序從右往左。
-
module.rules
匹配條件有:
{test : Condition}
:匹配特定條件英上,非必傳炭序,支持一個(gè)正則表達(dá)式或正則表達(dá)式數(shù)組;
{include : Condition}
:匹配特定條件苍日,非必傳惭聂,支持一個(gè)字符串或字符串?dāng)?shù)組;
{exclude : Condition}
:排除特定條件易遣,非必傳彼妻,支持一個(gè)字符串或字符串?dāng)?shù)組嫌佑;
{and : [Condition]}
:必須匹配數(shù)組中的所有條件豆茫;
{or : [Condition]}
:匹配數(shù)組中任一條件;
{not : [Condition]}
:必須排除這個(gè)條件屋摇;
更多參數(shù)介紹揩魂,可訪問中文官網(wǎng)的介紹:
《Rule》
// webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
include: [
path.resolve(__dirname, "app/style.css"),
path.resolve(__dirname, "vendor/style.css")
]
}
]
}
3. 加載 Sass 文件
需要使用到 sass-loader
的插件,這里先安裝:
npm install sass-loader node-sass --save-dev
在 src/style
目錄下添加 leo.scss
文件炮温,并添加內(nèi)容:
// leo.scss
$bg-color: #ee3;
.box{
background-color: $bg-color;
}
然后在 src/index.js
中引入 leo.scss
文件:
// src/index.js
import './style/leo.scss';
再 npx webpack
重新打包火脉,并打開 dist/index.html
可以看到背景顏色已經(jīng)添加上去:
4. 添加快捷打包命令
像 npx webpack
這個(gè)命令我們需要經(jīng)常使用,對于這種命令柒啤,我們可以把它寫成命令倦挂,方便每次使用。
我們在 package.json
的 scripts
中添加一個(gè)命令為 build
担巩,以后打包只要執(zhí)行 npm run build
即可:
"scripts": {
"build": "npx webpack -c webpack.config.js"
},
這里的 -c webpack.config.js
中方援,-c
后面跟著的是 webpack
配置文件的文件名,默認(rèn)可以不寫涛癌。
四犯戏、 webpack 開啟 SourceMap 和添加 CSS3 前綴
添加 SourceMap
是為了方便打包之后,我們在項(xiàng)目中調(diào)試樣式拳话,定位到樣式在源文件的位置先匪。
1. 開啟 SourceMap
在 css-loader
和 sass-loader
都可以通過設(shè)置 options
選項(xiàng)啟用 sourceMap
。
// webpack.config.js
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
"style-loader",
{
loader:"css-loader",
options:{ sourceMap: true }
},
{
loader:"sass-loader",
options:{ sourceMap: true }
},
]
}
]
再重新打包弃衍,看下 index.html
的樣式呀非,樣式已經(jīng)定位到源文件上了:
這樣我們在開發(fā)過程中,調(diào)試樣式就方便很多了镜盯。
2. 為樣式添加 CSS3 前綴
這里我們用到 PostCSS
這個(gè) loader
岸裙,它是一個(gè) CSS 預(yù)處理工具坦冠,可以為 CSS3 的屬性添加前綴,樣式格式校驗(yàn)(stylelint
)哥桥,提前使用 CSS
新特性辙浑,實(shí)現(xiàn) CSS
模塊化,防止 CSS
樣式?jīng)_突拟糕。
首先安裝 PostCSS
:
npm install postcss-loader autoprefixer --save-dev
另外還有:
postcss-cssnext
可以讓我們使用CSS4
的樣式判呕,并能配合autoprefixer
進(jìn)行瀏覽器部分兼容的補(bǔ)全,還支持嵌套語法送滞。precss
類似scss
語法侠草,如果我們只需要使用嵌套,就可以用它替換scss
犁嗅。postcss-import
讓我們可以在@import
CSS文件的時(shí)webpack
能監(jiān)聽并編譯边涕。
更多參數(shù)介紹,可訪問中文官網(wǎng)的介紹:
《postcss-loader》
開始添加 postcss-loader
并設(shè)置 autoprefixer
:
// webpack.config.js
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
"style-loader",
{
loader:"css-loader",
options:{ sourceMap: true }
},
{
loader:"postcss-loader",
options: {
ident: "postcss",
sourceMap: true,
plugins: loader => [
require('autoprefixer')(),
// 這里可以使用更多配置褂微,如上面提到的 postcss-cssnext 等
// require('postcss-cssnext')()
]
}
},
{
loader:"sass-loader",
options:{ sourceMap: true }
},
]
}
]
還需要在 package.json
中添加判斷瀏覽器版本:
// package.json
{
//...
"browserslist": [
"> 1%", // 全球?yàn)g覽器使用率大于1%功蜓,最新兩個(gè)版本并且是IE8以上的瀏覽器,加前綴
"last 2 versions",
"not ie <= 8"
]
}
為了做測試宠蚂,我們修改 src/style/leo.scss
中 .box
的樣式:
// src/style/leo.scss
.box{
background-color: $bg-color;
display: flex;
}
然后重新打包式撼,可以看見 CSS3 屬性的前綴已經(jīng)添加上去了:
五、 webpack 將 CSS 抽取成單獨(dú)文件
在之前學(xué)習(xí)中求厕,CSS 樣式代碼都是寫到 index.html
的 <style>
標(biāo)簽中著隆,這樣樣式代碼多了以后,很不方便呀癣。
于是我們需要將這些樣式打包成單獨(dú)的 CSS
文件美浦。
webpack4 開始使用 mini-css-extract-plugin
插件,而在 1-3 版本使用 extract-text-webpack-plugin
项栏。
注意:抽取樣式以后浦辨,就不能使用
style-loader
注入到 html 中。
安裝插件:
npm install mini-css-extract-plugin --save-dev
引入插件:
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
然后修改 rules
忘嫉,將 style-loader
荤牍,替換成 MiniCssExtractPlugin.loader
,然后添加 plugins
配置項(xiàng):
// webpack.config.js
module: {
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader:"css-loader",
options:{ sourceMap: true }
},
{
loader:"postcss-loader",
options: {
ident: "postcss",
sourceMap: true,
plugins: loader => [require('autoprefixer')()]
}
},
{
loader:"sass-loader",
options:{ sourceMap: true }
},
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css', // 最終輸出的文件名
chunkFilename: '[id].css'
})
]
然后重新打包庆冕,這時(shí)候可以看到我們 dist
目錄下就多了個(gè) main.css
文件:
因?yàn)楝F(xiàn)在已經(jīng)將 CSS 都抽取成單獨(dú)文件康吵,所以在 dist/index.html
中,我們需要手動(dòng)引入 main.css
了:
// index.html
<link rel="stylesheet" href="main.css">
六访递、 webpack 壓縮 CSS 和 JS
為了縮小打包后包的體積晦嵌,我們經(jīng)常做優(yōu)化的時(shí)候,將 CSS 和 JS 文件進(jìn)行壓縮,這里需要使用到不同的插件惭载。
1. 壓縮 CSS
使用 optimize-css-assets-webpack-plugin
壓縮 CSS 的插件旱函。
安裝插件:
npm install optimize-css-assets-webpack-plugin --save-dev
使用插件:
// webpack.config.js
// ... 省略
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
// ... 省略
plugins: [
// ... 省略
new OptimizeCssAssetsPlugin({})
],
}
重新打包,可以看到 main.css
已經(jīng)被壓縮成一行代碼描滔,即壓縮成功~
2. 壓縮 JS
使用 uglifyjs-webpack-plugin
壓縮 JS 的插件棒妨。
安裝插件:
npm install uglifyjs-webpack-plugin --save-dev
引入插件:
// webpack.config.js
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
使用插件:
// webpack.config.js
// ... 省略
module.exports = {
// ... 省略
plugins: [
// ... 省略
new OptimizeCssAssetsPlugin({}),
new UglifyJsPlugin({
cache: true, parallel: true, sourceMap: true
})
],
}
其中 UglifyJsPlugin
的參數(shù):
cache
:當(dāng) JS 沒有發(fā)生變化則不壓縮;
parallel
:是否啟用并行壓縮含长;
sourceMap
:是否啟用 sourceMap券腔;
然后重新打包,查看 main.js
拘泞,已經(jīng)被壓縮了:
七纷纫、webpack 為文件名添加 hash 值
由于我們打包出來的 css
、js
文件是靜態(tài)文件陪腌,就存在緩存問題辱魁,因此我們可以給文件名添加 hash
值,防止緩存诗鸭。
1. 添加 hash 值
直接在 webpack.config.js
中染簇,為需要添加 hash 值的文件名添加 [hash]
就可以:
// webpack.config.js
module.exports = {
// ... 省略其他
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css'
}),
],
}
配置完成后,重新打包只泼,就可以看到文件名中包含了 hash
值了:
2. 動(dòng)態(tài)引用打包后的文件
由于我們前面給打包的文件名添加了 hash
值剖笙,會(huì)導(dǎo)致 index.html
引用文件錯(cuò)誤,所以我們需要讓它能動(dòng)態(tài)引入打包后的文件请唱。
這里我們使用 HtmlWebpackPlugin
插件,它可以把打包后的 CSS 或者 JS 文件直接引用注入到 HTML 模版中过蹂,就不用每次手動(dòng)修改十绑。
安裝插件:
npm install html-webpack-plugin --save-dev
引入插件:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
使用插件:
// webpack.config.js
plugins: [
new HtmlWebpackPlugin({
title: "leo study!", // 生成的文件標(biāo)題
filename: "main.html", // 最終生成的文件名
minify: { // 壓縮選項(xiàng)
collapseWhitespace: true, // 移除空格
removeComments: true, // 移除注釋
removeAttributeQuotes: true, // 移除雙引號(hào)
}
})
],
關(guān)于 html-webpack-plugin
更多介紹可以《查看文檔》https://github.com/jantimon/html-webpack-plugin/。
接著我們打包以后酷勺,可以看見 dist
目錄下本橙,多了 main.html
的文件,格式化以后脆诉,可以看出甚亭,已經(jīng)動(dòng)態(tài)引入打包后的 CSS 文件和 JS 文件了:
八、 webpack 清理目錄插件
在之前击胜,我們每次打包都會(huì)生成新的文件亏狰,并且在添加 hash
值以后,文件名不會(huì)出現(xiàn)重復(fù)的情況偶摔,導(dǎo)致舊文件的冗余暇唾。
為了解決這個(gè)問題,我們需要在每次打包之前,將 /dist
目錄清空策州,再進(jìn)行打包瘸味。
這里我們使用 clean-webpack-plugin
插件來實(shí)現(xiàn)。
安裝插件:
npm install clean-webpack-plugin --save-dev
引入插件:
// webpack.config.js
const CleanWebpackPlugin = require('clean-webpack-plugin');
使用插件:
// webpack.config.js
plugins: [
new CleanWebpackPlugin()
],
參數(shù) cleanOnceBeforeBuildPatterns
是表示需要清除的文件夾够挂。
這樣我們每次打包之前旁仿,都會(huì)先將 /dist
目錄清空一次,再執(zhí)行打包孽糖。
更多參數(shù)介紹丁逝,可訪問中文官網(wǎng)的介紹:
《clean-webpack-plugin》
九、 webpack 圖片處理和優(yōu)化
1. 圖片處理
在項(xiàng)目中引入圖片:
// src/style/leo.scss
.box{
background-color: $bg-color;
display: flex;
background: url('./../assets/logo.jpg')
}
這時(shí)候我們?nèi)绻苯哟虬笮眨瑫?huì)報(bào)錯(cuò)霜幼。
我們需要使用 file-loader
插件來處理文件導(dǎo)入的問題。
安裝插件:
npm install file-loader --save-dev
使用插件:
// webpack.config.js
module: {
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
use: ["file-loader"]
}]
},
重新打包以后誉尖,發(fā)現(xiàn) dist
目錄下多了一個(gè)如 373e5e0e214390f8aa9e7abb4c7c635c.jpg
名稱的文件罪既,這就是我們打包后的圖片。
2. 圖片優(yōu)化
更進(jìn)一步铡恕,我們可以對圖片進(jìn)行壓縮和優(yōu)化琢感,這里我們用到 image-webpack-loader
插件來處理。
安裝插件:
npm install image-webpack-loader --save-dev
使用插件:
// webpack.config.js
module: {
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
include: [path.resolve(__dirname, 'src/')],
use: ["file-loader",{
loader: "image-webpack-loader",
options: {
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: '65-90', speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
}
},
]
}]
},
更多參數(shù)介紹探熔,可訪問中文官網(wǎng)的介紹:
《image-webpack-loader》
再重新打包驹针,我們可以看到圖片打包前后,壓縮了很大:
十诀艰、 webpack 圖片 base64 和字體處理
1. 圖片 base64 處理
url-loader
功能類似于 file-loader
柬甥,可以將 url 地址對應(yīng)的文件,打包成 base64 的 DataURL其垄,提高訪問效率苛蒲。
安裝插件:
npm install url-loader --save-dev
使用插件:
注意:這里需要將前面配置的
image-webpack-loader
先刪除掉,在使用url-loader
绿满。
// webpack.config.js
module: {
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
include: [path.resolve(__dirname, 'src/')],
use: [
{
loader: 'url-loader', // 根據(jù)圖片大小臂外,把圖片轉(zhuǎn)換成 base64
options: { limit: 10000 },
},
{
loader: "image-webpack-loader",
options: {
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: '65-90', speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
}
},
]
}]
},
更多參數(shù)介紹,可訪問中文官網(wǎng)的介紹:
《url-loader》
2. 字體處理
字體處理的方式和圖片處理方式是一樣的喇颁,只是我們在配置 rules
時(shí)的 test
值不相同:
// webpack.config.js
module: {
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
include: [path.resolve(__dirname, 'src/')],
use: [ 'file-loader' ]
}
},
十一漏健、 webpack 配置合并和提取公共配置
在開發(fā)環(huán)境(development)和生產(chǎn)環(huán)境(production)配置文件有很多不同,但也有部分相同橘霎,為了不每次更換環(huán)境的時(shí)候都修改配置蔫浆,我們就需要將配置文件做合并,和提取公共配置茎毁。
我們使用 webpack-merge
工具克懊,將兩份配置文件合并忱辅。
安裝插件:
npm install webpack-merge --save-dev
然后調(diào)整目錄結(jié)構(gòu),為了方便谭溉,我們將原來 webpack.config.js
文件修改名稱為 webpack.commen.js
墙懂,并復(fù)制兩份相同的文件出來,分別修改文件名為 webpack.prod.js
和 webpack.dev.js
扮念。
├─package.json
├─dist
├─src
- ├─webpack.config.js
+ ├─webpack.common.js // webpack 公共配置文件
+ ├─webpack.prod.js // webpack 生產(chǎn)環(huán)境配置文件
+ ├─webpack.dev.js // webpack 開發(fā)環(huán)境配置文件
由于我們文件調(diào)整了损搬,所以在 package.json
中,打包命令也需要調(diào)整柜与,并且配置 mode
模式巧勤。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "build": "npx webpack -c webpack.config.js",
+ "build": "npx webpack -c webpack.dev.js --mode development",
+ "dist": "npx webpack -c webpack.prod.js --mode production"
},
1. 調(diào)整 webpack.common.js
我們先調(diào)整 webpack.common.js
文件,將通用的配置保留弄匕,不是通用的配置刪除颅悉,結(jié)果如下:
// 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',
module: {
noParse: function (content) {return /jquery|lodash/.test(content);},
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
include: [path.resolve(__dirname, 'src/')],
use: [{
loader: 'url-loader', // 根據(jù)圖片大小,把圖片轉(zhuǎn)換成 base64
options: { limit: 10000 },
},{
loader: "image-webpack-loader",
options: {
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: '65-90', speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
}
}]
},{
test: /\.(woff|woff2|eot|ttf|otf)$/,
include: [path.resolve(__dirname, 'src/')],
use: [ 'file-loader' ]
}]
},
plugins: [
new HtmlWebpackPlugin({
title: "leo study!",
filename: "main.html",
template: path.resolve(__dirname, 'src/index.html'),
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true,
}
}),
new CleanWebpackPlugin()
],
}
2. 安裝 babel-loader
安裝 babel-loader
是為了將 ES6 及以上版本的 JS 代碼轉(zhuǎn)換成 ES5迁匠。
npm install babel-loader @babel/core @babel/preset-env --save-dev
使用插件:
// webpack.common.js
rules: [
// ... 省略其他
{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}],
exclude: /(node_modules|bower_components)/,
}
]
關(guān)于 babel-loader
更多介紹可以《查看文檔》https://webpack.js.org/loaders/babel-loader/剩瓶。
3. 調(diào)整 webpack.dev.js
這里我們就需要用到 merge-webpack
插件進(jìn)行配置合并了:
// webpack.dev.js
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
let devConfig = {
mode: 'development',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(sc|c|sa)ss$/,
use: [
'style-loader', {
loader: "css-loader",
options: { sourceMap: true }
}, {
loader: "postcss-loader",
options: {
ident: "postcss", sourceMap: true,
plugins: loader => [ require('autoprefixer')() ]
}
}, {
loader: "sass-loader",
options: { sourceMap: true }
}
]
}]
}
}
module.exports = merge(common, devConfig)
4. 調(diào)整 webpack.prod.js
同樣對于生產(chǎn)環(huán)境的配置,我們也需要用 merge-webpack
插件進(jìn)行配置合并:
// webpack.prod.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
let prodConfig = {
mode: 'production',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(sc|c|sa)ss$/,
use: [
MiniCssExtractPlugin.loader, {
loader: "css-loader",
options: { sourceMap: true }
}, {
loader: "postcss-loader",
options: {
ident: "postcss", sourceMap: true,
plugins: loader => [ require('autoprefixer')() ]
}
}, {
loader: "sass-loader",
options: { sourceMap: true }
}
]
}]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css'
}),
new OptimizeCssAssetsPlugin({}),
new UglifyJsPlugin({
cache: true, parallel: true, sourceMap: true
}),
],
}
module.exports = merge(common, prodConfig)
十二城丧、 webpack 監(jiān)控自動(dòng)編譯和啟用 js 的 sourceMap
1. 開啟 js 的 sourceMap
當(dāng) webpack 打包源代碼后延曙,就很難追蹤到錯(cuò)誤和警告在源代碼的位置。
如將三個(gè)源文件打包一個(gè) bundle
中亡哄,其中一個(gè)文件的代碼報(bào)錯(cuò)枝缔,那么堆棧追中就會(huì)指向 bundle
瘫想。
為了能方便定位錯(cuò)誤骤素,我們使用 inline-source-map
選項(xiàng),注意不要在生產(chǎn)環(huán)境中使用桅狠。
// webpack.dev.js
let devConfig = {
// ... 省略其他
+ devtool: 'inline-source-map'
}
2. 測試 sourceMap
為了測試是否成功拣挪,我們將 src/index.js
代碼中擦酌,在第 12 行上,添加一句日志打印菠劝。
// src/index.js
// ... 省略其他
+ console.log(111)
對比下開啟 sourceMap
前后的區(qū)別:
3. 開啟監(jiān)控自動(dòng)編譯
如果每次我們修改完代碼,都要手動(dòng)編譯睁搭,那是多累的一件事赶诊。
為此我們使用 --watch
命令,讓我們每次保存完园骆,都會(huì)自動(dòng)編譯舔痪。
為此,我們需要在 package.json
中的打包命令添加 --watch
命令:
// package.json
- "build": "npx webpack --config webpack.dev.js",
+ "build": "npx webpack --config webpack.dev.js --watch",
這里僅對開發(fā)環(huán)境開啟锌唾,生產(chǎn)環(huán)境不需要使用锄码。
十三夺英、 webpack 熱更新
上一節(jié)介紹監(jiān)控自動(dòng)編譯,當(dāng)我們保存文件后滋捶,會(huì)自動(dòng)編譯文件痛悯,但是我們還是需要手動(dòng)去刷新頁面,才能看到編譯后的結(jié)果重窟。
于是為了自動(dòng)編譯之后载萌,再自動(dòng)重新加載,我們就可以使用 webpack-dev-server
來啟動(dòng)一個(gè)簡單 web 服務(wù)器巡扇,實(shí)時(shí)重新加載扭仁。
1. 開啟熱更新
插件安裝:
npm install webpack-dev-server --save-dev
使用插件:
// webpack.dev.js
const webpack = require('webpack');
const webpack = require('webpack');
let devConfig = {
// ... 省略其他
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
hot: true,
overlay: true,
open:true,
publicPath: '/',
host: 'localhost',
port: '1200'
}
plugins: [
new webpack.NamedModulesPlugin(), // 更容易查看(patch)的以來
new webpack.HotModuleReplacementPlugin() // 替換插件
]
}
啟動(dòng)熱更新:
npx webpack-dev-server --config webpack.dev.js
常用配置:
contentBase: path.join(__dirname, 'dist'), //本地服務(wù)器所加載的頁面所在的目錄
clinetLogLevel: 'warning', // 可能值有 none, error, warning 或者 info (默認(rèn)值)
hot:true,//啟動(dòng)熱更新替換特性,需要配合 webpack.HotModuleReplacementPlugin 插件
host:'0.0.0.0', // 啟動(dòng)服務(wù)器的 host
port:7000, // 端口號(hào)
compress:true, // 為所有服務(wù)啟用gzip壓縮
overlay: true, // 在瀏覽器中顯示全屏覆蓋
stats: "errors-only" ,// 只顯示包中的錯(cuò)誤
open:true, // 啟用“打開”后厅翔,dev服務(wù)器將打開瀏覽器乖坠。
proxy: { // 設(shè)置代理
"/api": {
target: "http://localhost:3000",
pathRewrite: {"^/api" : ""}
}
}
這時(shí)候我們訪問 http://localhost:1200/main.html
就可以看到頁面,并且修改文件刀闷,頁面也會(huì)同時(shí)刷新熊泵。
2. 優(yōu)化命令
我們可以將 npx webpack-dev-server --config webpack.dev.js
寫到 package.json
中作為一個(gè)命令:
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npx webpack --config webpack.dev.js --watch",
"dist": "npx webpack --config webpack.prod.js",
+ "watch": "npx webpack-dev-server --config webpack.dev.js"
},
十四、 webpack 設(shè)置代理服務(wù)器和 babel 轉(zhuǎn)換及優(yōu)化
1. 設(shè)置代理服務(wù)器
接著上一節(jié)涩赢,接下來給 webpack 設(shè)置代理服務(wù)器:
// webpack.dev.js
let devConfig = {
// ... 省略其他
devServer: {
// ... 省略其他
proxy: {
"/api": { // 以 '/api' 開頭的請求戈次,會(huì)跳轉(zhuǎn)到下面的 target 配置
target: "http://192.168.30.33:8080",
pathRewrite: {
"^api": "/mock/api"
}
}
}
}
最后當(dāng)我們請求 /api/getuser
接口,就會(huì)轉(zhuǎn)發(fā)到 http://192.168.30.33:8080/mock/api
筒扒。
2. babel 轉(zhuǎn)換及優(yōu)化
babel-loader
插件的安裝怯邪,已經(jīng)提前介紹,在【十一花墩、 webpack 配置合并和提取公共配置】中悬秉。
這里講一下 babel-loader
的優(yōu)化。
babel-loader
可以配置 cacheDirectory
來提高打包效率:
-
cacheDirectory
:默認(rèn)值false
冰蘑,開啟后構(gòu)建時(shí)會(huì)緩存文件夾和泌,后續(xù)從緩存中讀取,將提高打包效率祠肥。
十五武氓、 webpack 開啟 Eslint
安裝插件:
npm install eslint eslint-loader --save-dev
另外還需要安裝 eslint 解釋器、校驗(yàn)規(guī)則等:
npm install babel-loader standard --save-dev
2. 添加 .eslintrc.js
在項(xiàng)目根目錄創(chuàng)建 .eslintrc.js
仇箱,指定 eslint 規(guī)則县恕。
這份配置內(nèi)容有點(diǎn)多,可以去 我的 gist 復(fù)制https://gist.github.com/pingan8787/8b9abe4e04bed85f9d7846e513ed2e11 剂桥。
3. 添加 .eslintignore
在項(xiàng)目根目錄創(chuàng)建 .eslintignore
忠烛,指定 eslint 忽略一些文件不校驗(yàn),比如內(nèi)容可以是:
/dist/
/node_modules/
十六权逗、 webpack 解析模塊拓展名和別名
在 webpack 配置中美尸,我們使用 resolve
來配置模塊解析方式冤议。
這是非常重要的,比如 import _ from 'lodash'
师坎,其實(shí)是加載解析了 lodash.js
文件恕酸。
該配置就是用來設(shè)置加載和解析的方式。
在解析過程中屹耐,我們可以進(jìn)行配置:
1. resolve.alias
當(dāng)我們引入一些文件時(shí)尸疆,需要寫很長的路徑,這樣使得代碼更加復(fù)雜惶岭。
為此我們可以使用 resolve.alias
寿弱,創(chuàng)建 import
或 require
的別名,使模塊引入更加簡單按灶。
使用配置:
// webpack.common.js
module.exports = {
entry: './src/index.js',
+ resolve: {
+ alias: {
+ '@' : path.resolve(__dirname, 'src/')
+ }
+ }
// 省略其他
}
alias
參數(shù)的含義:
使用 @
來替代 path.resolve(__dirname, 'src/')
這個(gè)路徑症革,接下來我們測試看看。
我們在 src/
目錄下新增 leo.js
:
// leo.js
export let name = 'pingan';
再到 src/index.js
中引入:
// index.js
import { name } from '@/leo.js';
這樣就能正常引入鸯旁。
當(dāng)然噪矛,我們也可以根據(jù)實(shí)際情況,為不同路徑設(shè)置不同別名:
// webpack.common.js
alias: {
'@' : path.resolve(__dirname, 'src/')
+ 'assets' : path.resolve(__dirname, 'src/assets/')
}
更多參數(shù)介紹铺罢,可訪問中文官網(wǎng)的介紹:
《resolve》
2. resolve.extensions
resolve.extensions
用來自動(dòng)解析確定的擴(kuò)展艇挨,讓我們在引入模塊的時(shí)候,可以不用設(shè)置拓展名韭赘,默認(rèn)值為:
extensions: [".js", ".json"]
使用配置:
// webpack.common.js
import { name } from '@/leo';
十七缩滨、 webpack 配置外部拓展
當(dāng)我們使用 CDN 引入 jquery
時(shí),我們并不想把它也打包到項(xiàng)目中泉瞻,我們就可以配置 externals
外部拓展的選項(xiàng)脉漏,來將這些不需要打包的模塊從輸出的 bundle 中排除:
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
配置 externals
:
// webpack.common.js
module.exports = {
// ... 省略其他
+ externals: {
+ jquery: 'jQuery'
+ },
}
通過上面配置,我們就不會(huì)把不需要打包的模塊打包進(jìn)來袖牙。并且下面代碼正常運(yùn)行:
import $ from 'jquery';
$('.leo').show();
更多參數(shù)介紹侧巨,可訪問中文官網(wǎng)的介紹:
《externals》
十八、 webpack 打包分析報(bào)表及優(yōu)化總結(jié)
1. 生成報(bào)表
這里我們使用 webpack-bundle-analyzer
插件鞭达,來對打包后的文件進(jìn)行數(shù)據(jù)分析司忱,從來找到項(xiàng)目優(yōu)化的方向。
webpack-bundle-analyzer
使用交互式可縮放樹形圖可視化 webpack 輸出文件的大小畴蹭。
安裝插件:
npm install webpack-bundle-analyzer --save-dev
這個(gè)我們只有在開發(fā)環(huán)境中使用烘贴。
使用插件:
// webpack.dev.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
// ...
]
}
配置完成以后,我們執(zhí)行 npm run build
打包撮胧,打包完成后,會(huì)自動(dòng)打開一個(gè)數(shù)據(jù)報(bào)表分析的頁面老翘,地址是 http://127.0.0.1:8888/
:
webpack-bundle-analyzer
將幫助我們:
- 看清楚我們包內(nèi)都包含什么模塊芹啥;
- 準(zhǔn)確看出每個(gè)模塊的組成锻离;
- 最后優(yōu)化它!
我們經(jīng)常將報(bào)表中區(qū)域最大的模塊進(jìn)行優(yōu)化墓怀!
2. 通過報(bào)表優(yōu)化項(xiàng)目
我們可以看出汽纠,打包后的項(xiàng)目中 lodash.js
占了非常大的內(nèi)存,我們就針對 lodash.js
進(jìn)行優(yōu)化傀履。
我們將 lodash.js
改為 CDN 引入:
// index.html
<script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.js"></script>
然后去設(shè)置上一節(jié)講到的 externals
:
// webpack.common.js
externals: {
jquery: 'jQuery',
+ lodash: '_'
},
再打包以后虱朵,可以看到 lodash.js
已經(jīng)不在包里面了:
并且打包后的文件,也能正常運(yùn)行:
更多參數(shù)介紹钓账,可訪問中文官網(wǎng)的介紹:
《webpack-bundle-analyzer》
參考資料
總結(jié)
本文是根據(jù) 《2019最新Webpack4.0教程4.x 成仙之路》 學(xué)習(xí)總結(jié)下來的學(xué)習(xí)之路碴犬,適合入門,涉及范圍較多梆暮,內(nèi)容比較長服协,需要能靜下心來學(xué)習(xí)。
內(nèi)容如果有誤啦粹,歡迎留言指點(diǎn)偿荷,我會(huì)及時(shí)修改。
本文代碼最終托管在我的 github 上唠椭,點(diǎn)擊查看(https://github.com/pingan8787/Leo-JavaScript/blob/master/Cute-Webpack/introduction/README.md)跳纳。
希望自己的文章會(huì)對各位有所幫助,也歡迎各位大佬指點(diǎn)贪嫂。
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | https://github.com/pingan8787/Leo_Reading/issues |
ES小冊 | js.pingan8787.com |