Hi ~ 許久沒更新的小簡書蝇闭,自從換了新工作蕴侣,日夜掉發(fā)式的瘋狂加班泊交,一個半月的時間學(xué)到了不少東西,趁熱記錄一波吧~
一個月前宏浩,接到了一個需求知残,并且長期需要維護(hù)多個無關(guān)的活動頁或者場景頁,自以為簡單的我樂呵呵的接了需求比庄,心中已經(jīng)想好“用react來搭一個多頁面應(yīng)用就夠符合需求啦~”求妹,事實證明,我還是too young too simple ,sometimes naive...
實際開發(fā)工作中佳窑,react多頁面應(yīng)用的腳手架GitHub上有很多制恍,自己也可以根據(jù)官方的react腳手架就可以愉快的擼起來,但是目前遇到的比較頭疼的問題是神凑,怎么讓我的react應(yīng)用代碼壓縮模塊打包净神,這個時候就很有必要好好研究下webpack的使用了。
此次分享主要是針對多頁面的webpack4打包。
So鹃唯,咱們來聊一下爱榕,什么是webpack?
官網(wǎng)上的webpack相信所有前端開發(fā)童鞋都見過俯渤,webpack做的事情呆细,就是將我們的js應(yīng)用的各個文件按照模塊打包成多個bundle,是一個靜態(tài)模塊的打包器八匠。
webpack做的事情,就是分析項目結(jié)構(gòu)趴酣,找到j(luò)s模塊以及一些不能直接運行的語言梨树,并將其打包成合適的格式給瀏覽器執(zhí)行。
安裝webpack
npm install webpack-cli
了解webpack前需要知道webpack的四大核心概念岖寞,entry抡四、output、loader仗谆、plugins指巡。
Entry(入口)
entry是webpack的起點指示,告訴webpack從哪里開始入手打包任務(wù)隶垮,用來指定入口藻雪,默認(rèn)值是./src。
如果是做單頁面程序狸吞,單個入口勉耀。
//單個入口的寫法 entry: string|Array<string>
entry:{
main:'../src/component/my.js'
}
entry:'../src/component/my.js'
//如果傳數(shù)組形式,是注入多個入口以及多個依賴文件蹋偏。
如果是做多個頁面便斥,多個入口。
//多個入口的寫法威始,所有的文件會被打包到dist文件中枢纠。
entry:{
app:['./a.js','./b.js','./c.js']
}
//最終輸出 dist/a.js / dist/b.js dist/c.js
當(dāng)webpack在解析代碼時,每遇到import或者require引入的依賴黎棠,最終會被打包在最終構(gòu)建結(jié)果中晋渺。打包的最終結(jié)果只會引入該模塊引入的依賴。
output(輸出)
打包完后輸出的位置
output: {
filename: 'vendor.js',
path: '/home/index'
}
loader(加載器)
實際上webpack只能打包js文件葫掉,其他資源例如css和html是需要加載器來將資源轉(zhuǎn)化些举,加載進(jìn)來。
舉個栗子俭厚,如果項目中使用了sass的樣式語法户魏,是無法被瀏覽器所識別的,因此需要引用loader,將sass轉(zhuǎn)義成能被識別的css語法閱讀叼丑。
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
在該項目中关翎,react用的是jsx的語法,同樣無法被瀏覽器所識別鸠信,需要引用babel將jsx語法轉(zhuǎn)義成正常的js運行纵寝。
module:{
rules:[
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [
"@babel/preset-env",//可以根據(jù)配置的目標(biāo)瀏覽器或者運行環(huán)境來自動將2015+的代碼轉(zhuǎn)為es5
"@babel/preset-react",
{ "plugins": ["@babel/plugin-proposal-class-properties"] }//這句可以在項目中使用箭頭函數(shù)
],
}
},
]
}
loader的職責(zé)是單一的,一個loader相當(dāng)于一個翻譯官星立,只做翻譯某種語言爽茴,需要關(guān)心輸入和輸出。
一個項目里有多個翻譯官绰垂,在調(diào)用多個 Loader 去轉(zhuǎn)換一個文件時室奏,每個 Loader 會鏈?zhǔn)降捻樞驁?zhí)行, 第一個 Loader 將會拿到需處理的原內(nèi)容劲装,上一個 Loader 處理后的結(jié)果會傳給下一個接著處理胧沫,最后的 Loader 將處理后的最終結(jié)果返回給 Webpack。
plugins(插件)
常用的插件有
- webpack-dev-server
- copy-webpack-plugin
- uglifyjs-webpack-plugin
- webpack-spritesmith
- clean-webpack-plugin
- html-webpack-plugin
...還有好多好多
webpack-dev-server
非常常見占业,用于啟動本地開發(fā)模式绒怨,本身是一個express服務(wù)器,封裝了webpack-hot-middleware谦疾,實現(xiàn)了熱更新南蹂。
devServer:{
host:'0.0.0.0' || 'localhost',
post:9000,//打開的端口
open:true,//自動打開
contentBase:path.join(_dirname,'src')//不設(shè)置的話,默認(rèn)是當(dāng)前執(zhí)行的目錄餐蔬,一般是項目根目錄碎紊,會在項目根目錄查找index.html文件。
}
copy-webpack-plugin
在webpack相中拷貝文件或文件夾的方法樊诺。
new CopyWebpackPlugin({
from:'.....',//需要拷貝的源目標(biāo)文件
to:'',//拷貝后存放的文件位置
})
uglifyjs-webpack-plugin
用來壓縮優(yōu)化js文件仗考,webpack4+以上的版本可使用。
webpack4之前的版本是通過webpack.optimize.commonsChuckPlugin來壓縮js
module.exports={
optimization:{
minimizer:true,//默認(rèn)為true词爬,效果就是壓縮js代碼
splitChuncks:{
chunks:'async',//'async':分割異步打包的代碼,'all':同時分割同步和異步代碼
cacheGroups:{//默認(rèn)的規(guī)則不會打包秃嗜,需要單獨定義
vendors:{
test:/[\\/]node_modules[\\/]/,
name:'vendors'
},
commons:{
test:/commons\.js/,
name:'commons'
}
}
}
}
}
webpack-spritesmith
把零散的小圖生成一張雪碧圖,減少http請求
new SpritesmithPlugin({
// 目標(biāo)小圖標(biāo)
src: {
cwd: `src/assets/images/sprites`,
glob: '*.png'
},
// 輸出雪碧圖文件及樣式文件7
target: {
image: `dist/static/images/sprite-[hash].png`,
css: [
[
`dist/static/css/sprite.css`, {
formatOpts: {
cssSelector: (groupName) => `.icon-${groupName.name}` // 修改生成的sprite css中類名定義
}
}
]
]
},
// 樣式文件中調(diào)用雪碧圖地址寫法
apiOptions: {
cssImageRef: '../images/sprite-[hash].png'
},
spritesmithOptions: {
algorithm: 'top-down'
}
})
clean-webpack-plugin
用來清除文件
// 刪除文件 保留新文件
new CleanWebpackPlugin(['dist']),
html-webpack-plugin
為入口文件html加載js依賴顿膨,動態(tài)添加編譯后的hash值文件锅锨,防止引用緩存文件的問題。
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({ // 打包輸出HTML
minify: { // 壓縮HTML文件
removeComments: true, // 移除HTML中的注釋
collapseWhitespace: true, // 刪除空白符與換行符
minifyCSS: true// 壓縮內(nèi)聯(lián)css
},
filename: 'a.html',
template: 'a.html'
}),
new HtmlWebpackPlugin({ // 打包輸出HTML
minify: { // 壓縮HTML文件
removeComments: true, // 移除HTML中的注釋
collapseWhitespace: true, // 刪除空白符與換行符
minifyCSS: true// 壓縮內(nèi)聯(lián)css
},
filename: 'b.html',
template: 'b.html'
}),
]
項目是多頁的情況下恋沃,傳入的html入口文件設(shè)置多個即可必搞。
可以寫一個提取html的函數(shù),批量獲取囊咏,組合成數(shù)組形式恕洲。
resolve配置
webpack在啟動后會從配置的入口模塊出發(fā)去找尋所有依賴的模塊塔橡,resolve配置webpack如何找尋模塊所對應(yīng)的文件。
alias
resolve.alias配置項通過設(shè)置其他名字來將原路徑映射成新的路徑
resolve:{
extensions: ['.js', '.json','.css'],//導(dǎo)入的語句中如果沒帶文件后綴名霜第,webpack會自動帶上后綴名去嘗試文件是否存在葛家,用于配置在嘗試過程中用到的后綴列表。
alias:{
'api':utils.resolve('/src/common/api/'),//通過api關(guān)鍵字替換'/src/common/api/'
}
}
總結(jié)
歸結(jié)webpack在實際項目中做了哪些事情泌类?
1癞谒、webpack從context設(shè)置的文件位置開始找尋
2、尋找entry里的所有文件名
3刃榨、在js文件編譯過程中弹砚,遇到 import | require 引入的依賴文件,然后在依賴文件遞歸找尋所有依賴枢希,最終打包在最終編譯生成的文件迅栅。
4、webpack把所有生成的文件都輸出到output.path路徑中晴玖,以output.filename對應(yīng)命名的模塊來命名。
webpack之所以強(qiáng)大为流,是在于插件各式各樣呕屎,總能滿足你的需求。webpack4的新api大大的提高了Code Splitting 的體驗敬察,以上講的內(nèi)容還是淺顯了點秀睛,具體的一些細(xì)節(jié)還是需要靠同志們自己愉快的擼起來,只有實操才是檢驗?zāi)芰Φ奈ㄒ煌緩絶
最后莲祸,po上項目中的webpack相關(guān)依賴的版本情況
{
"@babel/core": "^7.1.2",
"@babel/plugin-proposal-class-properties": "^7.2.1",
"@babel/plugin-transform-runtime": "^7.3.4",
"@babel/preset-env": "^7.1.0",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.3.4",
"babel-loader": "^8.0.4",
"babel-preset-env": "^1.7.0",
"clean-webpack-plugin": "^2.0.0",
"copy-webpack-plugin": "^5.0.3",
"css-loader": "^1.0.0",
"file-loader": "^2.0.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^5.0.0",
"jsx-loader": "^0.13.2",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"script-loader": "^0.7.2",
"style-loader": "^0.23.0",
"uglifyjs-webpack-plugin": "^2.0.1",
"url-loader": "^1.1.2",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.9",
"webpack-spritesmith": "^0.5.4",
"clean-webpack-plugin": "^2.0.0",
"copy-webpack-plugin": "^5.0.3",
}