概念
不像大多數(shù)的模塊打包機(jī),webpack是會(huì)把項(xiàng)目當(dāng)作一個(gè)整體,通過(guò)一個(gè)給定的的主文件,webpack將從這個(gè)文件開(kāi)始找到你的項(xiàng)目的所有依賴文件,使用loaders處理它們,最后打包成一個(gè)或多個(gè)瀏覽器可識(shí)別的bundle.js文件
組成
- entry 用來(lái)寫(xiě)入口文件,它將是整個(gè)依賴關(guān)系的根
var baseConfig = {
entry: {
main: './src/index.js'
}
}
- output 輸出配置
- Loader
loader用于加載某些資源文件。因?yàn)閣ebpack本身只能打包c(diǎn)ommon.js規(guī)范的js文件,對(duì)于其他資源如css,img等,是沒(méi)有辦法加載的,這時(shí)就需要對(duì)應(yīng)的loader將資源轉(zhuǎn)化,從而進(jìn)行加載。 - Plugins
plugin用于擴(kuò)展webpack的功能。不同于loader,plugin的功能更加豐富,比如壓縮打包,優(yōu)化,不只局限于資源的加載 - bundle
是由webpack打包出來(lái)的文件 - chunk
是指webpack在進(jìn)行模塊依賴分析的時(shí)候,代碼分割出來(lái)的代碼塊 - module
是開(kāi)發(fā)中的單個(gè)模塊
常見(jiàn)問(wèn)題
webpack與grunt、gulp的不同?
grunt和gulp是基于任務(wù)和流(Task、Stream)的。類似jQuery,找到一個(gè)(或一類)文件,對(duì)其做一系列鏈?zhǔn)讲僮?,更新流上的?shù)據(jù), 整條鏈?zhǔn)讲僮鳂?gòu)成了一個(gè)任務(wù),多個(gè)任務(wù)就構(gòu)成了整個(gè)web的構(gòu)建流程。
webpack是基于入口的。webpack會(huì)自動(dòng)地遞歸解析入口所需要加載的所有資源文件,然后用不同的Loader來(lái)處理不同的文件,用Plugin來(lái)擴(kuò)展webpack功能。
有哪些常見(jiàn)的Loader?他們是解決什么問(wèn)題的?
file-loader:把文件輸出到一個(gè)文件夾中,在代碼中通過(guò)相對(duì) URL 去引用輸出的文件
url-loader:和 file-loader 類似,但是能在文件很小的情況下以 base64 的方式把文件內(nèi)容注入到代碼中去
source-map-loader:加載額外的 Source Map 文件,以方便斷點(diǎn)調(diào)試
image-loader:加載并且壓縮圖片文件
babel-loader:把 ES6 轉(zhuǎn)換成 ES5
css-loader:加載 CSS,支持模塊化、壓縮、文件導(dǎo)入等特性
style-loader:把 CSS 代碼注入到 JavaScript 中,通過(guò) DOM 操作去加載 CSS。
eslint-loader:通過(guò) ESLint 檢查 JavaScript 代碼
有哪些常見(jiàn)的Plugin?他們是解決什么問(wèn)題的?
define-plugin:定義環(huán)境變量
commons-chunk-plugin:提取公共代碼
uglifyjs-webpack-plugin:通過(guò)UglifyES壓縮ES6代碼
webpack的構(gòu)建流程是什么?
1.初始化參數(shù):從配置文件和 Shell 語(yǔ)句中讀取與合并參數(shù),得出最終的參數(shù);
2.開(kāi)始編譯:用上一步得到的參數(shù)初始化 Compiler 對(duì)象,加載所有配置的插件,執(zhí)行對(duì)象的 run 方法開(kāi)始執(zhí)行編譯;
3.確定入口:根據(jù)配置中的 entry 找出所有的入口文件;
4.編譯模塊:從入口文件出發(fā),調(diào)用所有配置的 Loader 對(duì)模塊進(jìn)行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過(guò)了本步驟的處理;
5.完成模塊編譯:在經(jīng)過(guò)第4步使用 Loader 翻譯完所有模塊后,得到了每個(gè)模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系;
6.輸出資源:根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個(gè)個(gè)包含多個(gè)模塊的 Chunk,再把每個(gè) Chunk 轉(zhuǎn)換成一個(gè)單獨(dú)的文件加入到輸出列表,這步是可以修改輸出內(nèi)容的最后機(jī)會(huì);
7.輸出完成:在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫(xiě)入到文件系統(tǒng)。
在以上過(guò)程中,Webpack 會(huì)在特定的時(shí)間點(diǎn)廣播出特定的事件,插件在監(jiān)聽(tīng)到感興趣的事件后會(huì)執(zhí)行特定的邏輯,并且插件可以調(diào)用 Webpack 提供的 API 改變 Webpack 的運(yùn)行結(jié)果。
是否寫(xiě)過(guò)Loader和Plugin?描述一下編寫(xiě)loader或plugin的思路?
Loader像一個(gè)"翻譯官"把讀到的源文件內(nèi)容轉(zhuǎn)義成新的文件內(nèi)容,并且每個(gè)Loader通過(guò)鏈?zhǔn)讲僮?,將源文件一步步翻譯成想要的樣子。
編寫(xiě)Loader時(shí)要遵循單一原則,每個(gè)Loader只做一種"轉(zhuǎn)義"工作。 每個(gè)Loader的拿到的是源文件內(nèi)容(source),可以通過(guò)返回值的方式將處理后的內(nèi)容輸出,也可以調(diào)用this.callback()方法,將內(nèi)容返回給webpack。 還可以通過(guò) this.async()生成一個(gè)callback函數(shù),再用這個(gè)callback將處理后的內(nèi)容輸出出去。 此外webpack還為開(kāi)發(fā)者準(zhǔn)備了開(kāi)發(fā)loader的工具函數(shù)集——loader-utils。
相對(duì)于Loader而言,Plugin的編寫(xiě)就靈活了許多。 webpack在運(yùn)行的生命周期中會(huì)廣播出許多事件,Plugin 可以監(jiān)聽(tīng)這些事件,在合適的時(shí)機(jī)通過(guò) Webpack 提供的 API 改變輸出結(jié)果。
如何利用webpack來(lái)優(yōu)化前端性能?
用webpack優(yōu)化前端性能是指優(yōu)化webpack的輸出結(jié)果,讓打包的最終結(jié)果在瀏覽器運(yùn)行快速高效。
- 壓縮代碼。刪除多余的代碼、注釋、簡(jiǎn)化代碼的寫(xiě)法等等方式??梢岳脀ebpack的UglifyJsPlugin和ParallelUglifyPlugin來(lái)壓縮JS文件, 利用cssnano(css-loader?minimize)來(lái)壓縮css
- 利用CDN加速。在構(gòu)建過(guò)程中,將引用的靜態(tài)資源路徑修改為CDN上對(duì)應(yīng)的路徑??梢岳脀ebpack對(duì)于output參數(shù)和各loader的publicPath參數(shù)來(lái)修改資源路徑
- 刪除死代碼(Tree Shaking)。將代碼中永遠(yuǎn)不會(huì)走到的片段刪除掉??梢酝ㄟ^(guò)在啟動(dòng)webpack時(shí)追加參數(shù)--optimize-minimize來(lái)實(shí)現(xiàn)
- 提取公共代碼。
如何在vue項(xiàng)目中實(shí)現(xiàn)按需加載?
Vue UI組件庫(kù)的按需加載 為了快速開(kāi)發(fā)前端項(xiàng)目,經(jīng)常會(huì)引入現(xiàn)成的UI組件庫(kù)如ElementUI、iView等,但是他們的體積和他們所提供的功能一樣,是很龐大的。 而通常情況下,我們僅僅需要少量的幾個(gè)組件就足夠了,但是我們卻將龐大的組件庫(kù)打包到我們的源碼中,造成了不必要的開(kāi)銷。
不過(guò)很多組件庫(kù)已經(jīng)提供了現(xiàn)成的解決方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import 安裝以上插件后,在.babelrc配置中或babel-loader的參數(shù)中進(jìn)行設(shè)置,即可實(shí)現(xiàn)組件按需加載了。