Webpack-前端工程化的基石

在以前,為了減少 HTTP 請求屠缭,通常地箍鼓,我們都會把所有的代碼都打包成一個單獨的 JS 文件。但是呵曹,如果這個 JS 文件體積很大的話款咖,那就得不償失了。

就拿咱們產(chǎn)品來說奄喂,都是 SPA 單頁面應(yīng)用铐殃,我們不可能在首屏加載所有的 JS 和 CSS 代碼。

這時跨新,我們不妨把所有代碼分成一塊一塊富腊,需要某塊代碼的時候再去加載它;還可以利用瀏覽器的緩存域帐,下次用到它的話赘被,直接從緩存中讀取。很顯然肖揣,這種做法可以加快我們網(wǎng)頁的加載速度民假,webpack 剛好可以幫助我們。

1许饿、什么是 webpack

webpack
  • WebPack可以看做是模塊打包機:它做的事情是阳欲,分析你的項目結(jié)構(gòu),找到 JavaScript 模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript 等)球化,并將其打包為合適的格式以供瀏覽器使用秽晚。

2、為什么要使用 webpack

  • 現(xiàn)在的很多網(wǎng)頁其實可以看做是功能豐富的應(yīng)用筒愚,它們擁有著復(fù)雜的 JavaScript 代碼和一大堆依賴包赴蝇。為了簡化開發(fā)的復(fù)雜度,前端社區(qū)涌現(xiàn)出了很多好的實踐方法

    • 模塊化巢掺,讓我們可以把復(fù)雜的程序細化為小的文件

    • 類似于 TypeScript 這種在 JavaScript 基礎(chǔ)上拓展的開發(fā)語言:使我們能夠?qū)崿F(xiàn)目前版本的 JavaScript 不能直接使用的特性句伶,并且之后還能轉(zhuǎn)換為 JavaScript 文件使瀏覽器可以識別

    • scss,less等CSS預(yù)處理器

  • 這些改進確實大大的提高了我們的開發(fā)效率陆淀,但是利用它們開發(fā)的文件往往需要進行額外的處理才能讓瀏覽器識別, 而手動處理又是非常繁瑣的考余,這就為 WebPack 類的工具的出現(xiàn)提供了需求

3、webpack 入門

  • 創(chuàng)建項目目錄如下:
 webpack-demo
 |- package.json
+ |- index.html
+ |- /src
+   |- index.js
  • 安裝 webpack npm install webpack webpack-cli --save-dev

  • 執(zhí)行 npx webpack

4轧苫、配置 webpack.config.js

  • 基礎(chǔ)配置 mode楚堤、entry、output
const path = require('path')
?
module.exports = {
 mode: 'development',
 entry: path.resolve(__dirname, 'src/index'),
 output: {
 filename: 'main.js',
 path: path.resolve(__dirname, 'bundle')
 }
}

5含懊、plugins

  • Plugin (插件) 是 webpack 生態(tài)的的一個關(guān)鍵部分身冬。它為社區(qū)提供了一種強大的方法來擴展 webpack 和開發(fā) webpack 的編譯過程

  • 在特定的時刻,做特定的事情

  • 在 webpack 運行的生命周期中會廣播出許多的事件岔乔,plugin 可以監(jiān)聽這些事件酥筝,在合適的時機通過 webpack 提供的 API 改變輸出的結(jié)果

  • clean-webpack-plugin、html-webpack-plugin 實例

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
?
const HtmlPlugin = new HtmlWebpackPlugin({
 template: path.resolve(__dirname, 'index.html')
})
?
module.exports = {
 mode: 'development',
 entry: path.resolve(__dirname, 'src/index'),
 output: {
 filename: '[name].[chunkHash:8].js',
 path: path.resolve(__dirname, 'dist')
 },
 plugins: [
 new CleanWebpackPlugin(),
 HtmlPlugin
 ]
}

6雏门、loader

  • loader 就是一個打包的方案嘿歌。對于特定的非 js 模塊告訴 webpack 該如何打包。

  • webpack 根據(jù)正則表達式剿配,來確定應(yīng)該查找哪些文件搅幅,并將其提供給指定的 loader。在這種情況下呼胚,以 .css 結(jié)尾的全部文件茄唐,都將被提供給 style-loader 和 css-loader。

  • loader 執(zhí)行順序:從上到下蝇更,從右到左

  • style-loader沪编、css-loader、less-loader 實例

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
?
const HtmlPlugin = new HtmlWebpackPlugin({
 template: path.resolve(__dirname, 'index.html')
})
?
module.exports = {
 mode: 'development',
 entry: path.resolve(__dirname, 'src/index'),
 output: {
 filename: '[name].[chunkHash:8].js',
 path: path.resolve(__dirname, 'dist')
 },
 module:{
 rules: [{
 test: /\.js$/,
 use: ['babel-loader']
 }, {
 test: /\.css$/,
 use: ['style-loader', 'css-loader']
 }, {
 test: /\.less$/,
 use: ['style-loader', 'css-loader', 'less-loader']
 }]
 },
 plugins: [
 new CleanWebpackPlugin(),
 HtmlPlugin
 ]
}

7年扩、webpack-dev-server

  • --inline 刷新頁面 --hot 熱更新

  • --progress 顯示進度條

  • --color 顏色

  • --open 打開瀏覽器

  • --port 8001 端口

// package.json "start": "webpack-dev-server --inline --progress --color --open --port 8001"

8蚁廓、 webpack 構(gòu)建流程

  • 初始化參數(shù),從配置文件和 shell 語句中讀到的參數(shù)合并厨幻,得到最后的參數(shù)

  • 開始編譯:用合并得到的參數(shù)初始化 complier 對象相嵌,加載所有配置的插件腿时,執(zhí)行 run 方法開始編譯

  • 確定入口,通過 entry 找到入口文件

  • 編譯模塊饭宾,從入口文件出發(fā)批糟,調(diào)用所有配置的 loader 對模塊進行解析翻譯,遞歸找到該模塊依賴的模塊進行處理

  • 完成模塊編譯看铆,得到每個模塊被翻譯之后的最終的內(nèi)容和依賴關(guān)系

  • 輸出資源徽鼎,根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個個包含多個模塊的 chunk弹惦,在把每個 chunk 轉(zhuǎn)換成一個單獨的文件加載到輸出列表(這一步是修改輸出內(nèi)容的最后機會)

  • 輸出完成否淤,根據(jù)配置中輸出的路徑和文件名,把內(nèi)容寫到文件系統(tǒng)中

  • 在以上過程中棠隐,webpack會在特定的時間點廣播出特定的事件石抡,插件在監(jiān)聽事件后會執(zhí)行特定的邏輯,改變 webpack 的運行結(jié)果

9宵荒、優(yōu)化 Webpack 的構(gòu)建

  • 使用高版本的 Webpack 和 Node.js汁雷, 多進程/多實例構(gòu)建:HappyPack(不維護了)净嘀、thread-loader

    • 壓縮代碼

    • webpack-parallel-uglify-plugin

    • uglifyjs-webpack-plugin 開啟 parallel 參數(shù) (不支持ES6)

    • terser-webpack-plugin 開啟 parallel 參數(shù)报咳,多進程并行壓縮

    • 通過 mini-css-extract-plugin 提取 Chunk 中的 CSS 代碼到單獨文件,通過 css-loader 的 minimize 選項開啟 cssnano 壓縮 CSS挖藏。

    • 使用基于 Node 庫的 imagemin (很多定制選項暑刃、可以處理多種圖片格式)

    • 配置 image-webpack-loader 圖片壓縮

  • 縮小打包作用域:

    • exclude/include (確定 loader 規(guī)則范圍)

    • resolve.modules 指明第三方模塊的絕對路徑 (減少不必要的查找)

    • resolve.mainFields 只采用 main 字段作為入口文件描述字段 (減少搜索步驟,需要考慮到所有運行時依賴的第三方模塊的入口文件描述字段)

    • resolve.extensions 盡可能減少后綴嘗試的可能性

    • noParse 對完全不需要解析的庫進行忽略 (不去解析但仍會打包到 bundle 中膜眠,注意被忽略掉的文件里不應(yīng)該包含 import岩臣、require、define 等模塊化語句)

    • IgnorePlugin (完全排除模塊)忽略本地化內(nèi)容之打包核心模塊

    • 合理使用 alias

  • 提取頁面公共資源:

    • 使用 html-webpack-externals-plugin宵膨,將基礎(chǔ)包通過 CDN 引入架谎,不打入 bundle 中

    • 使用 SplitChunksPlugin 進行(公共腳本、基礎(chǔ)包辟躏、頁面公共文件)分離(Webpack4內(nèi)置) 谷扣,替代了 CommonsChunkPlugin 插件

  • 基礎(chǔ)包分離:

    • 使用 DllPlugin 進行分包,使用 DllReferencePlugin(索引鏈接) 對 manifest.json 引用捎琐,讓一些基本不會改動的代碼先打包成靜態(tài)資源会涎,避免反復(fù)編譯浪費時間。

    • HashedModuleIdsPlugin 可以解決模塊數(shù)字 id 問題

  • 充分利用緩存提升二次構(gòu)建速度:

    • babel-loader 開啟緩存

    • terser-webpack-plugin 開啟緩存

    • 使用 cache-loader 或者 hard-source-webpack-plugin

  • Tree shaking

    • 打包過程中檢測工程中沒有引用過的模塊并進行標記瑞凑,在資源壓縮時將它們從最終的bundle中去掉(只能對ES6 Modlue生效) 開發(fā)中盡可能使用ES6 Module的模塊末秃,提高 tree shaking 效率

    • purgecss-webpack-plugin 和 mini-css-extract-plugin配合使用(建議)

    • 禁用 babel-loader 的模塊依賴解析,否則 Webpack 接收到的就都是轉(zhuǎn)換過的 CommonJS 形式的模塊籽御,無法進行 tree-shaking

    • 使用 PurifyCSS(不在維護) 或者 uncss 去除無用 CSS 代碼

  • Scope Hoisting

    • 構(gòu)建后的代碼會存在大量閉包练慕,造成體積增大惰匙,運行代碼時創(chuàng)建的函數(shù)作用域變多,內(nèi)存開銷變大铃将。Scope hoisting 將所有模塊的代碼按照引用順序放在一個函數(shù)作用域里徽曲,然后適當?shù)闹孛恍┳兞恳苑乐棺兞棵麤_突

    • 必須是ES6的語法,因為有很多第三方庫仍采用 CommonJS 語法麸塞,為了充分發(fā)揮 Scope hoisting 的作用秃臣,需要配置 mainFields 對第三方模塊優(yōu)先采用 jsnext:main 中指向的ES6模塊化語法

    • webpack.optimize.ModuleConcatenationPlugin 開啟 Scope Hoisting 作用域提升,提升代碼在瀏覽器中的執(zhí)行速度

10哪工、vue-cli 腳手架簡析

npm install @vue/cli
vue create myApp
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奥此,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雁比,更是在濱河造成了極大的恐慌稚虎,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偎捎,死亡現(xiàn)場離奇詭異蠢终,居然都是意外死亡,警方通過查閱死者的電腦和手機茴她,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門寻拂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人丈牢,你說我怎么就攤上這事祭钉。” “怎么了己沛?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵慌核,是天一觀的道長。 經(jīng)常有香客問我申尼,道長垮卓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任师幕,我火速辦了婚禮粟按,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘们衙。我一直安慰自己钾怔,他們只是感情好,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布蒙挑。 她就那樣靜靜地躺著宗侦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪忆蚀。 梳的紋絲不亂的頭發(fā)上矾利,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天姑裂,我揣著相機與錄音,去河邊找鬼男旗。 笑死舶斧,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的察皇。 我是一名探鬼主播茴厉,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼什荣!你這毒婦竟也來了矾缓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤稻爬,失蹤者是張志新(化名)和其女友劉穎嗜闻,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桅锄,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡琉雳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了友瘤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翠肘。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖商佑,靈堂內(nèi)的尸體忽然破棺而出锯茄,到底是詐尸還是另有隱情,我是刑警寧澤茶没,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站晚碾,受9級特大地震影響抓半,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜格嘁,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一笛求、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧糕簿,春花似錦探入、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至殃恒,卻和暖如春植旧,著一層夾襖步出監(jiān)牢的瞬間辱揭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工病附, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留问窃,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓完沪,卻偏偏與公主長得像域庇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子覆积,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容