目錄
webpack-dev-server和http服務器如nginx有什麼區別?
什麼是Tree-shaking?CSS可以Tree-shaking?
2. 與webpack類似的工具還有哪些?談談你爲什麼最終選擇(或放棄)使用webpack?
6.webpack的構建流程是什麼?從讀取配置到輸出文件這個過程儘量說全
7.是否寫過Loader和Plugin?描述一下編寫loader或plugin的思路?
9.如何利用webpack來優化前端性能?(提高性能和體驗)
12.npm打包時需要注意哪些?如何利用webpack來更好的構建?
談談你對webpack的看法
webpack是一個模塊打包工具,可以使用它管理項目中的模塊依賴,並編譯輸出模塊所需的靜態文件。它可以很好地管理、打包開發中所用到的HTML,CSS,JavaScript和靜態文件(圖片,字體)等,讓開發更高效。對於不同類型的依賴,webpack有對應的模塊加載器,而且會分析模塊間的依賴關係,最後合併生成優化的靜態資源。
webpack的基本功能和工作原理?
- 代碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等等
- 文件優化:壓縮 JavaScript、CSS、HTML 代碼,壓縮合並圖片等
- 代碼分割:提取多個頁面的公共代碼、提取首屏不需要執行部分的代碼讓其異步加載
- 模塊合併:在採用模塊化的項目有很多模塊和文件,需要構建功能把模塊分類合併成一個文件
- 自動刷新:監聽本地源代碼的變化,自動構建,刷新瀏覽器
- 代碼校驗:在代碼被提交到倉庫前需要檢測代碼是否符合規範,以及單元測試是否通過
- 自動發佈:更新完代碼後,自動構建出線上發佈代碼並傳輸給發佈系統。
webpack構建過程
- 從entry裏配置的module開始遞歸解析entry依賴的所有module
- 每找到一個module,就會根據配置的loader去找對應的轉換規則
- 對module進行轉換後,再解析出當前module依賴的module
- 這些模塊會以entry爲單位分組,一個entry和其所有依賴的module被分到一個組Chunk
- 最後webpack會把所有Chunk轉換成文件輸出
- 在整個流程中webpack會在恰當的時機執行plugin裏定義的邏輯
webpack打包原理
將所有依賴打包成一個bundle.js,通過代碼分割成單元片段按需加載
什麼是webpack,與gulp,grunt有什麼區別
- webpack是一個模塊打包工具,可以遞歸地打包項目中的所有模塊,最終生成幾個打包後的文件。
- 區別:webpack支持代碼分割,模塊化(AMD,CommonJ,ES2015),全局分析
什麼是entry,output?
- entry 入口,告訴webpack要使用哪個模塊作爲構建項目的起點,默認爲./src/index.js
- output 出口,告訴webpack在哪裏輸出它打包好的代碼以及如何命名,默認爲./dist
什麼是loader,plugins?
- loader是用來告訴webpack如何轉換某一類型的文件,並且引入到打包出的文件中。
- plugins(插件)作用更大,可以打包優化,資源管理和注入環境變量
什麼是bundle,chunk,module?
bundle是webpack打包出來的文件,chunk是webpack在進行模塊的依賴分析的時候,代碼分割出來的代碼塊。module是開發中的單個模塊
如何自動生成webpack配置?
可以用一些官方腳手架
- webpack-cli
- vue-cli
// 首先安裝
npm install -g @vue/cli
// 新建項目hello
vue create hello
複製代碼
- nuxt-cli
// 確保安裝了npx,npx在npm5.2.0默認安裝了
// 新建項目hello
npx create-nuxt-app hello
複製代碼
webpack如何配置單頁面和多頁面的應用程序?
- 單個頁面
module.exports = {
entry: './path/to/my/entry/file.js'
}
複製代碼
- 多頁面應用程序
module.entrys = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js'
}
}
複製代碼
webpack-dev-server和http服務器如nginx有什麼區別?
webpack-dev-server使用內存來存儲webpack開發環境下的打包文件,並且可以使用模塊熱更新,相比傳統http服務器開發更加簡單高效
什麼是模塊熱更新?
webpack的一個功能,可以使代碼修改後不用刷新瀏覽器就自動更新,高級版的自動刷新瀏覽器
dev-server是怎麼跑起來的
webpack-dev-server支持兩種模式來自動刷新頁面
- iframe模式(頁面放在iframe中,當發送改變時重載) 無需額外配置,只要以這種格式url訪問即可。
http://localhost:8080/webpack-dev-server/index.html
- inline模式(將webpack-dev-server的客戶端入口添加到bundle中) inline模式下url不用發生變化,但啓動inline模式分兩種情況
// 以命令行啓動webpack-dev-server有兩種方式
// 方式1 在命令行中添加--inline命令
// 方式2 在webpack-config.js添加devServer:{inline: true}
// 以node.js API啓動有兩種方式
// 方式1 添加webpack-dev-server/client?http://localhost:8080/到webpack配置的entry入口點
config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/");
// 將<script src="http://localhost:8080/webpack-dev-server.js"></script>添加到html文件中
複製代碼
使用過webpack裏面哪些plugin和loader
loader
- babel-loader: 將ES6+轉移成ES5-
- css-loader,style-loader:解析css文件,能夠解釋@import url()等
- file-loader:直接輸出文件,把構建後的文件路徑返回,可以處理很多類型的文件
- url-loader:打包圖片
// url-loader增強版的file-loader,小於limit的轉爲Base64,大於limit的調用file-loader
npm install url-loader -D
// 使用
module.exports = {
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
outputPath: 'images/',
limit: 500 //小於500B的文件打包出Base64格式,寫入JS
}
}]
}]
}
}
複製代碼
plugins
- html-webpack-plugin: 壓縮html
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//...
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html', // 配置輸出文件名和路徑
template: './public/index.html', // 配置要被編譯的html文件
hash: true,
// 壓縮 => production 模式使用
minify: {
removeAttributeQuotes: true, //刪除雙引號
collapseWhitespace: true //摺疊 html 爲一行
}
})
]
}
複製代碼
- clean-webpack-plugin: 打包器清理源目錄文件,在webpack打包器清理dist目錄
npm install clean-webpack-plugin -D
// 修改webpack.config.js
const cleanWebpackPlugin=require('clean-webpack-plugin')
module.exports = {
plugins: [new cleanWebpackPlugin(['dist'])]
}
複製代碼
webpack中babel的實現
安裝 npm i -D @babel-preset-env @babel-core babel-loader
- @babel-preset-env:可以讓我們靈活設置代碼目標執行環境
- @babel-core: babel核心庫
- babel-loader: webpack的babel插件,讓我們可以在webpack中運行babel
配置.babelrc
{
"presets": ['@babel/preset-env']
}
複製代碼
配置webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {loader: 'babel-loader'}
}]
}
}
複製代碼
提取公用代碼
module.exports = {
optimization: {
splitChunks: {
common: {
// 抽離公共代碼
chunks: 'initial',
name: 'common', // 打包後的文件名
minChunks: 2, // 最小引用2次
minSize: 0 // 超出0字節就生成一個新包
},
styles: {
// 抽離公用代碼
name: 'styles',
test: /\.css$/,
chunks: 'all',
minChunks: 2,
enforce: true
},
vender: {
// 抽離第三方插件
test: /node_modules/,
chunks: 'initial',
name: 'vendor', // 打包後的文件名
priority: 10 // 設置優先級,防止與自定義公共代碼提取時被覆蓋,不進行打包
}
}
}
}
複製代碼
什麼是長緩存?在webpack中如何做到長緩存優化?
- 瀏覽器在用戶訪問頁面的時候,爲了加快加載速度會對用戶訪問的靜態資源進行存儲,但是每一次代碼升級或更新都需要瀏覽器下載新的代碼,最簡單方便的方式就是引入新的文件名稱。
- webpack中可以在output中指定chunkhash,並且分離經常更新的代碼和框架代碼。通過NameModulesPlugin或HashedModuleIdsPlugin使再次打包文件名不變。
什麼是Tree-shaking?CSS可以Tree-shaking?
Tree-shaking是指在打包中取出那些引入了但在代碼中沒有被用到的死代碼。webpack中通過uglifysPlugin來Tree-shaking JS。CSS需要使用purify-CSS
轉自:https://blog.csdn.net/sinat_17775997/article/details/84314006
什麼是webpack
webpack是一個打包模塊化javascript的工具,在webpack裏一切文件皆模塊,通過loader轉換文件,通過plugin注入鉤子,最後輸出由多個模塊組合成的文件,webpack專注構建模塊化項目。
WebPack可以看做是模塊打包機:它做的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其打包爲合適的格式以供瀏覽器使用。
官網的圖片形象的展示了webpack的定義
幾個常見的loader
-
file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件
-
url-loader:和 file-loader 類似,但是能在文件很小的情況下以 base64 的方式把文件內容注入到代碼中去
-
source-map-loader:加載額外的 Source Map 文件,以方便斷點調試
-
image-loader:加載並且壓縮圖片文件
-
babel-loader:把 ES6 轉換成 ES5
-
css-loader:加載 CSS,支持模塊化、壓縮、文件導入等特性
-
style-loader:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS。
-
eslint-loader:通過 ESLint 檢查 JavaScript 代碼
幾個常見的plugin
-
define-plugin:定義環境變量
-
terser-webpack-plugin:通過TerserPlugin壓縮ES6代碼
-
html-webpack-plugin 爲html文件中引入的外部資源,可以生成創建html入口文件
-
mini-css-extract-plugin:分離css文件
-
clean-webpack-plugin:刪除打包文件
-
happypack:實現多線程加速編譯
webpack與grunt、gulp的不同?
Webpack與Gulp、Grunt沒有什麼可比性,它可以看作模塊打包機,通過分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其轉換和打包爲合適的格式供瀏覽器使用。Gulp/Grunt是一種能夠優化前端的開發流程的工具,而WebPack是一種模塊化的解決方案,不過Webpack的優點使得Webpack在很多場景下可以替代Gulp/Grunt類的工具。
他們的工作方式也有較大區別:
Grunt和Gulp的工作方式是:在一個配置文件中,指明對某些文件進行類似編譯,組合,壓縮等任務的具體步驟,工具之後可以自動替你完成這些任務。
Webpack的工作方式是:把你的項目當做一個整體,通過一個給定的主文件(如:index.js),Webpack將從這個文件開始找到你的項目的所有依賴文件,使用loaders處理它們,最後打包爲一個(或多個)瀏覽器可識別的JavaScript文件。
三者都是前端構建工具,grunt和gulp在早期比較流行,現在webpack相對來說比較主流,不過一些輕量化的任務還是會用gulp來處理,比如單獨打包CSS文件等。
grunt和gulp是基於任務和流(Task、Stream)的。類似jQuery,找到一個(或一類)文件,對其做一系列鏈式操作,更新流上的數據, 整條鏈式操作構成了一個任務,多個任務就構成了整個web的構建流程。
webpack是基於入口的。webpack會自動地遞歸解析入口所需要加載的所有資源文件,然後用不同的Loader來處理不同的文件,用Plugin來擴展webpack功能。
所以總結一下:
從構建思路來說
gulp和grunt需要開發者將整個前端構建過程拆分成多個Task,併合理控制所有Task的調用關係
webpack需要開發者找到入口,並需要清楚對於不同的資源應該使用什麼Loader做何種解析和加工
對於知識背景來說
gulp更像後端開發者的思路,需要對於整個流程瞭如指掌 webpack更傾向於前端開發者的思路
webpack有哪些優點
-
專注於處理模塊化的項目,能做到開箱即用,一步到位
-
可通過plugin擴展,完整好用又不失靈活
-
使用場景不侷限於web開發
-
社區龐大活躍,經常引入緊跟時代發展的新特性,能爲大多數場景找到已有的開源擴展
-
良好的開發體驗
webpack的缺點
webpack的缺點是隻能用於採用模塊化開發的項目
分別介紹bundle,chunk,module是什麼
bundle:是由webpack打包出來的文件,
chunk:代碼塊,一個chunk由多個模塊組合而成,用於代碼的合併和分割。
module:是開發中的單個模塊,在webpack的世界,一切皆模塊,一個模塊對應一個文件,webpack會從配置的entry中遞歸開始找出所有依賴的模塊。
分別介紹什麼是loader?什麼是plugin?
loader:模塊轉換器,用於將模塊的原內容按照需要轉成你想要的內容
plugin:在webpack構建流程中的特定時機注入擴展邏輯,來改變構建結果,是用來自定義webpack打包過程的方式,一個插件是含有apply方法的一個對象,通過這個方法可以參與到整個webpack打包的各個流程(生命週期)。
什麼 是模塊熱更新?
模塊熱更新是webpack的一個功能,他可以使得代碼修改過後不用刷新瀏覽器就可以更新,是高級版的自動刷新瀏覽器。
devServer中通過hot屬性可以控制模塊的熱替換
1,通過配置文件
const webpack = require('webpack');
const path = require('path');
let env = process.env.NODE_ENV == "development" ? "development" : "production";
const config = {
mode: env,
devServer: {
hot:true
}
}
plugins: [
new webpack.HotModuleReplacementPlugin(), //熱加載插件
],
module.exports = config;
2,通過命令行
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "NODE_ENV=development webpack-dev-server --config webpack.develop.config.js --hot",
},
什麼是Tree-shaking
Tree-shaking可以用來剔除javascript中不用的死代碼,它依賴靜態的es6模塊化語法,例如通過哦import 和export 導入導出,Tree-shaking最先在rollup中出現,webpack在2.0中將其引入,css中使用Tree-shaking需要引入Purify-CSS
通過webpack處理長緩存
瀏覽器在用戶訪問頁面的時候,爲了加快加載速度,會對用戶訪問的靜態資源進行存儲,但是每一次代碼升級或是更新,都需要瀏覽器去下載新的代碼,最方便和簡單的更新方式就是引入新的文件名稱。在webpack中可以在output縱輸出的文件指定chunkhash,並且分離經常更新的代碼和框架代碼。通過NameModulesPlugin或是HashedModuleIdsPlugin使再次打包文件名不變。
如何提高webpack的構建速度
-
通過externals配置來提取常用庫
-
利用DllPlugin和DllReferencePlugin預編譯資源模塊 通過DllPlugin來對那些我們引用但是絕對不會修改的npm包來進行預編譯,再通過DllReferencePlugin將預編譯的模塊加載進來。
-
使用Happypack 實現多線程加速編譯
要注意的第一點是,它對file-loader和url-loader支持不好,所以這兩個loader就不需要換成happypack了,其他loader可以類似地換一下
-
使用Tree-shaking和Scope Hoisting來剔除多餘代碼
-
使用fast-sass-loader代替sass-loader
-
babel-loader開啓緩存
babel-loader在執行的時候,可能會產生一些運行期間重複的公共文件,造成代碼體積大冗餘,同時也會減慢編譯效率
可以加上cacheDirectory參數或使用 transform-runtime 插件試試
// webpack.config.js
use: [{
loader: 'babel-loader',
options: {
cacheDirectory: true
}]
// .bablerc
{
"presets": [
"env",
"react"
],
"plugins": ["transform-runtime"]
}
-
不需要打包編譯的插件庫換成全局"script"標籤引入的方式
比如jQuery插件,react, react-dom等,代碼量是很多的,打包起來可能會很耗時
可以直接用標籤引入,然後在webpack配置裏使用 expose-loader 或 externals 或 ProvidePlugin 提供給模塊內部使用相應的變量
// @1
use: [{
loader: 'expose-loader',
options: '$'
}, {
loader: 'expose-loader',
options: 'jQuery'
}]
// @2
externals: {
jquery: 'jQuery'
},
// @3
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}),
-
優化構建時的搜索路徑
在webpack打包時,會有各種各樣的路徑要去查詢搜索,我們可以加上一些配置,讓它搜索地更快
比如說,方便改成絕對路徑的模塊路徑就改一下,以純模塊名來引入的可以加上一些目錄路徑
還可以善於用下resolve alias別名 這個字段來配置
還有exclude等的配置,避免多餘查找的文件,比如使用babel別忘了剔除不需要遍歷的
轉自:https://www.cnblogs.com/gaoht/p/11310365.html
1. webpack與grunt、gulp的不同?
三者都是前端構建工具,grunt和gulp在早期比較流行,現在webpack相對來說比較主流,不過一些輕量化的任務還是會用gulp來處理,比如單獨打包CSS文件等。
grunt和gulp是基於任務和流(Task、Stream)的。類似jQuery,找到一個(或一類)文件,對其做一系列鏈式操作,更新流上的數據, 整條鏈式操作構成了一個任務,多個任務就構成了整個web的構建流程。
webpack是基於入口的。webpack會自動地遞歸解析入口所需要加載的所有資源文件,然後用不同的Loader來處理不同的文件,用Plugin來擴展webpack功能。
所以總結一下:
- 從構建思路來說
gulp和grunt需要開發者將整個前端構建過程拆分成多個`Task`,併合理控制所有`Task`的調用關係 webpack需要開發者找到入口,並需要清楚對於不同的資源應該使用什麼Loader做何種解析和加工
- 對於知識背景來說
gulp更像後端開發者的思路,需要對於整個流程瞭如指掌 webpack更傾向於前端開發者的思路
2. 與webpack類似的工具還有哪些?談談你爲什麼最終選擇(或放棄)使用webpack?
同樣是基於入口的打包工具還有以下幾個主流的:
- webpack
- rollup
- parcel
從應用場景上來看:
- webpack適用於大型複雜的前端站點構建
- rollup適用於基礎庫的打包,如vue、react
- parcel適用於簡單的實驗性項目,他可以滿足低門檻的快速看到效果
由於parcel在打包過程中給出的調試信息十分有限,所以一旦打包出錯難以調試,所以不建議複雜的項目使用parcel
3.有哪些常見的Loader?他們是解決什麼問題的?
- file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件
- url-loader:和 file-loader 類似,但是能在文件很小的情況下以 base64 的方式把文件內容注入到代碼中去
- source-map-loader:加載額外的 Source Map 文件,以方便斷點調試
- image-loader:加載並且壓縮圖片文件
- babel-loader:把 ES6 轉換成 ES5
- css-loader:加載 CSS,支持模塊化、壓縮、文件導入等特性
- style-loader:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS。
- eslint-loader:通過 ESLint 檢查 JavaScript 代碼
4.有哪些常見的Plugin?他們是解決什麼問題的?
- define-plugin:定義環境變量
- commons-chunk-plugin:提取公共代碼
- uglifyjs-webpack-plugin:通過UglifyES壓縮ES6代碼
5.Loader和Plugin的不同?
不同的作用
- Loader直譯爲"加載器"。Webpack將一切文件視爲模塊,但是webpack原生是隻能解析js文件,如果想將其他文件也打包的話,就會用到loader。 所以Loader的作用是讓webpack擁有了加載和解析非JavaScript文件的能力。
- Plugin直譯爲"插件"。Plugin可以擴展webpack的功能,讓webpack具有更多的靈活性。 在 Webpack 運行的生命週期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
不同的用法
- Loader在module.rules中配置,也就是說他作爲模塊的解析規則而存在。 類型爲數組,每一項都是一個Object,裏面描述了對於什麼類型的文件(test),使用什麼加載(loader)和使用的參數(options)
- Plugin在plugins中單獨配置。 類型爲數組,每一項是一個plugin的實例,參數都通過構造函數傳入。
6.webpack的構建流程是什麼?從讀取配置到輸出文件這個過程儘量說全
Webpack 的運行流程是一個串行的過程,從啓動到結束會依次執行以下流程:
- 初始化參數:從配置文件和 Shell 語句中讀取與合併參數,得出最終的參數;
- 開始編譯:用上一步得到的參數初始化 Compiler 對象,加載所有配置的插件,執行對象的 run 方法開始執行編譯;
- 確定入口:根據配置中的 entry 找出所有的入口文件;
- 編譯模塊:從入口文件出發,調用所有配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經過了本步驟的處理;
- 完成模塊編譯:在經過第4步使用 Loader 翻譯完所有模塊後,得到了每個模塊被翻譯後的最終內容以及它們之間的依賴關係;
- 輸出資源:根據入口和模塊之間的依賴關係,組裝成一個個包含多個模塊的 Chunk,再把每個 Chunk 轉換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內容的最後機會;
- 輸出完成:在確定好輸出內容後,根據配置確定輸出的路徑和文件名,把文件內容寫入到文件系統。
在以上過程中,Webpack 會在特定的時間點廣播出特定的事件,插件在監聽到感興趣的事件後會執行特定的邏輯,並且插件可以調用 Webpack 提供的 API 改變 Webpack 的運行結果。
7.是否寫過Loader和Plugin?描述一下編寫loader或plugin的思路?
Loader像一個"翻譯官"把讀到的源文件內容轉義成新的文件內容,並且每個Loader通過鏈式操作,將源文件一步步翻譯成想要的樣子。
編寫Loader時要遵循單一原則,每個Loader只做一種"轉義"工作。 每個Loader的拿到的是源文件內容(source),可以通過返回值的方式將處理後的內容輸出,也可以調用this.callback()方法,將內容返回給webpack。 還可以通過 this.async()生成一個callback函數,再用這個callback將處理後的內容輸出出去。 此外webpack還爲開發者準備了開發loader的工具函數集——loader-utils。
相對於Loader而言,Plugin的編寫就靈活了許多。 webpack在運行的生命週期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
8.webpack的熱更新是如何做到的?說明其原理?
webpack的熱更新又稱熱替換(Hot Module Replacement),縮寫爲HMR。 這個機制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。
原理:
首先要知道server端和client端都做了處理工作
- 第一步,在 webpack 的 watch 模式下,文件系統中某一個文件發生修改,webpack 監聽到文件變化,根據配置文件對模塊重新編譯打包,並將打包後的代碼通過簡單的 JavaScript 對象保存在內存中。
- 第二步是 webpack-dev-server 和 webpack 之間的接口交互,而在這一步,主要是 dev-server 的中間件 webpack-dev-middleware 和 webpack 之間的交互,webpack-dev-middleware 調用 webpack 暴露的 API對代碼變化進行監控,並且告訴 webpack,將代碼打包到內存中。
- 第三步是 webpack-dev-server 對文件變化的一個監控,這一步不同於第一步,並不是監控代碼變化重新打包。當我們在配置文件中配置了devServer.watchContentBase 爲 true 的時候,Server 會監聽這些配置文件夾中靜態文件的變化,變化後會通知瀏覽器端對應用進行 live reload。注意,這兒是瀏覽器刷新,和 HMR 是兩個概念。
- 第四步也是 webpack-dev-server 代碼的工作,該步驟主要是通過 sockjs(webpack-dev-server 的依賴)在瀏覽器端和服務端之間建立一個 websocket 長連接,將 webpack 編譯打包的各個階段的狀態信息告知瀏覽器端,同時也包括第三步中 Server 監聽靜態文件變化的信息。瀏覽器端根據這些 socket 消息進行不同的操作。當然服務端傳遞的最主要信息還是新模塊的 hash 值,後面的步驟根據這一 hash 值來進行模塊熱替換。
- webpack-dev-server/client 端並不能夠請求更新的代碼,也不會執行熱更模塊操作,而把這些工作又交回給了 webpack,webpack/hot/dev-server 的工作就是根據 webpack-dev-server/client 傳給它的信息以及 dev-server 的配置決定是刷新瀏覽器呢還是進行模塊熱更新。當然如果僅僅是刷新瀏覽器,也就沒有後面那些步驟了。
- HotModuleReplacement.runtime 是客戶端 HMR 的中樞,它接收到上一步傳遞給他的新模塊的 hash 值,它通過 JsonpMainTemplate.runtime 向 server 端發送 Ajax 請求,服務端返回一個 json,該 json 包含了所有要更新的模塊的 hash 值,獲取到更新列表後,該模塊再次通過 jsonp 請求,獲取到最新的模塊代碼。這就是上圖中 7、8、9 步驟。
- 而第 10 步是決定 HMR 成功與否的關鍵步驟,在該步驟中,HotModulePlugin 將會對新舊模塊進行對比,決定是否更新模塊,在決定更新模塊後,檢查模塊之間的依賴關係,更新模塊的同時更新模塊間的依賴引用。
- 最後一步,當 HMR 失敗後,回退到 live reload 操作,也就是進行瀏覽器刷新來獲取最新打包代碼。
9.如何利用webpack來優化前端性能?(提高性能和體驗)
用webpack優化前端性能是指優化webpack的輸出結果,讓打包的最終結果在瀏覽器運行快速高效。
- 壓縮代碼。刪除多餘的代碼、註釋、簡化代碼的寫法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin來壓縮JS文件, 利用cssnano(css-loader?minimize)來壓縮css
- 利用CDN加速。在構建過程中,將引用的靜態資源路徑修改爲CDN上對應的路徑。可以利用webpack對於output參數和各loader的publicPath參數來修改資源路徑
- 刪除死代碼(Tree Shaking)。將代碼中永遠不會走到的片段刪除掉。可以通過在啓動webpack時追加參數--optimize-minimize來實現
- 提取公共代碼。
10.如何提高webpack的構建速度?
- 多入口情況下,使用CommonsChunkPlugin來提取公共代碼
- 通過externals配置來提取常用庫
- 利用DllPlugin和DllReferencePlugin預編譯資源模塊 通過DllPlugin來對那些我們引用但是絕對不會修改的npm包來進行預編譯,再通過DllReferencePlugin將預編譯的模塊加載進來。
- 使用Happypack 實現多線程加速編譯
- 使用webpack-uglify-parallel來提升uglifyPlugin的壓縮速度。 原理上webpack-uglify-parallel採用了多核並行壓縮來提升壓縮速度
- 使用Tree-shaking和Scope Hoisting來剔除多餘代碼
11.怎麼配置單頁應用?怎麼配置多頁應用?
單頁應用可以理解爲webpack的標準模式,直接在entry中指定單頁應用的入口即可,這裏不再贅述
多頁應用的話,可以使用webpack的 AutoWebPlugin來完成簡單自動化的構建,但是前提是項目的目錄結構必須遵守他預設的規範。 多頁應用中要注意的是:
- 每個頁面都有公共的代碼,可以將這些代碼抽離出來,避免重複的加載。比如,每個頁面都引用了同一套css樣式表
- 隨着業務的不斷擴展,頁面可能會不斷的追加,所以一定要讓入口的配置足夠靈活,避免每次添加新頁面還需要修改構建配置
12.npm打包時需要注意哪些?如何利用webpack來更好的構建?
Npm是目前最大的 JavaScript 模塊倉庫,裏面有來自全世界開發者上傳的可複用模塊。你可能只是JS模塊的使用者,但是有些情況你也會去選擇上傳自己開發的模塊。 關於NPM模塊上傳的方法可以去官網上進行學習,這裏只講解如何利用webpack來構建。
NPM模塊需要注意以下問題:
- 要支持CommonJS模塊化規範,所以要求打包後的最後結果也遵守該規則。
- Npm模塊使用者的環境是不確定的,很有可能並不支持ES6,所以打包的最後結果應該是採用ES5編寫的。並且如果ES5是經過轉換的,請最好連同SourceMap一同上傳。
- Npm包大小應該是儘量小(有些倉庫會限制包大小)
- 發佈的模塊不能將依賴的模塊也一同打包,應該讓用戶選擇性的去自行安裝。這樣可以避免模塊應用者再次打包時出現底層模塊被重複打包的情況。
- UI組件類的模塊應該將依賴的其它資源文件,例如.css文件也需要包含在發佈的模塊裏。
基於以上需要注意的問題,我們可以對於webpack配置做以下擴展和優化:
- CommonJS模塊化規範的解決方案: 設置output.libraryTarget='commonjs2'使輸出的代碼符合CommonJS2 模塊化規範,以供給其它模塊導入使用
- 輸出ES5代碼的解決方案:使用babel-loader把 ES6 代碼轉換成 ES5 的代碼。再通過開啓devtool: 'source-map'輸出SourceMap以發佈調試。
- Npm包大小盡量小的解決方案:Babel 在把 ES6 代碼轉換成 ES5 代碼時會注入一些輔助函數,最終導致每個輸出的文件中都包含這段輔助函數的代碼,造成了代碼的冗餘。解決方法是修改.babelrc文件,爲其加入transform-runtime插件
- 不能將依賴模塊打包到NPM模塊中的解決方案:使用externals配置項來告訴webpack哪些模塊不需要打包。
- 對於依賴的資源文件打包的解決方案:通過css-loader和extract-text-webpack-plugin來實現,配置如下:
13.如何在vue項目中實現按需加載?
Vue UI組件庫的按需加載 爲了快速開發前端項目,經常會引入現成的UI組件庫如ElementUI、iView等,但是他們的體積和他們所提供的功能一樣,是很龐大的。 而通常情況下,我們僅僅需要少量的幾個組件就足夠了,但是我們卻將龐大的組件庫打包到我們的源碼中,造成了不必要的開銷。
不過很多組件庫已經提供了現成的解決方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import 安裝以上插件後,在.babelrc配置中或babel-loader的參數中進行設置,即可實現組件按需加載了。
單頁應用的按需加載 現在很多前端項目都是通過單頁應用的方式開發的,但是隨着業務的不斷擴展,會面臨一個嚴峻的問題——首次加載的代碼量會越來越多,影響用戶的體驗。
通過import(*)語句來控制加載時機,webpack內置了對於import(*)的解析,會將import(*)中引入的模塊作爲一個新的入口在生成一個chunk。 當代碼執行到import(*)語句時,會去加載Chunk對應生成的文件。import()會返回一個Promise對象,所以爲了讓瀏覽器支持,需要事先注入Promise polyfill