webpack是開發工具,面試考點重點在配置和使用,原理理解不需要太深。 一、基本配置 1、拆分配置和merge 將公共配置跟dev和prod的配置拆分,然後通過webpack-merge對配置進行整合。 2、啟動本地服務 dev環境啟動devserver配置。 3、處理ES6 使用babel-lo ...
webpack是開發工具,面試考點重點在配置和使用,原理理解不需要太深。
一、基本配置
1、拆分配置和merge
將公共配置跟dev和prod的配置拆分,然後通過webpack-merge對配置進行整合。
2、啟動本地服務
dev環境啟動devserver配置。
3、處理ES6
使用babel-loader,針對對應目錄的js進行代碼轉換。
4、處理樣式
使用postcss-loader、css-loader、style-loader等,這裡有個考點是loader的執行順序是從後往前執行。
5、處理圖片
在dev環境直接使用file-loader進行圖片的直接引用,prod環境會使用url-loader對小圖片進行base64編碼。
6、模塊化
webpack天生支持模塊化。
二、高級配置
1、配置多入口
entry設置多入口文件,在output輸出文件使用[name]根據entry的key動態生成輸出文件名
plugins要設置多個HtmlWebpackPlugin,根據多入口生成多個html文件,同時要設置chunks,來引入相應入口文件,如果不設置則會把全部入口文件都引入 。
2、每次打包清除dist原有文件
在plugins使用new CleanWebpackPlugin(),會預設清空 output.path 指定的文件夾內容。
3、抽離css文件
mini-css-extract-plugin使用這個插件的loder來替換style-loader。
在plugins裡面配置mini-css-extract-plugin的filename,用於設置存放抽離的css具體目錄和名字。
使用webpack的optimization的minimizer加入 terser-webpack-plugin 和 optimize-css-assets-webpack 插件來壓縮抽離的css。
4、抽離公共代碼
使用webpack的optimization的splitChunks
optimization:{ splitChunks:{ chunks: 'all', // 緩存分組 cacheGroups:{ //第三方模塊 vendor:{ name:'vendor', // chunk 名稱 priority:1, // 許可權最高,優先抽離,重要!! test:/node_modules/, // 匹配目錄規則 minSize:0, // 大小限制 minChunks:1, // 最少復用過幾次 } //公共模塊 common:{ name:'common', // chunk 名稱 priority:0, // 優先順序 minSize:0, // 公共模塊的大小限制 minChunks:2, // 公共模塊最少復用過幾次 } } } }
5、非同步載入js
import語法webpack天生支持非同步載入。
非同步載入會產生單獨的chunk。
6、處理JSX
安裝配置 @babel/preset-react 即可。
7、處理VUE文件
安裝配置 vue-loader 即可
三、優化構建速度
1、優化 babel-loader(可用於生產)
{ test: /\.js$/, use: ['babel-loader?cacheDirectory'], // 開啟緩存 include: path.resolve(__dirname, 'src'), // 明確範圍 // 排除範圍,include 和 exclude 兩者選一個即可 // exclude: path.resolve(__dirname, 'node_modules') }
開啟緩存後,es6沒有改的會使用緩存不會重新編譯
設置使用範圍可以縮小編譯量
2、IgnorePlugin(可用於生產)
忽略正則匹配的 js
3、noParse(可用於生產)
不去解析正則匹配的庫的依賴
4、happyPack(可用於生產)
JS單線程,使用happyPack開啟多進程打包,提高構建速度,特別是多核CPU。
5、ParallelUglifyPlugin(只用在生產)
webpack內置Uglify工具壓縮JS,開啟多進程壓縮JS,原理和happyPack相同。
new ParallelUglifyPlugin({ // 傳遞給UglifyJS的參數,值不過開啟了多進程壓縮 uglifyJS:{ output:{ beautify:false, // 最緊湊的輸出 comments:false, // 刪除所有註釋 }, compress:{ // 刪除所有的 console 語句,可以相容ie drop_console: true, // 內嵌定義了但是只用到一次的變數 collapse_vars: true, // 提取出出現多次但是沒有定義成變數去引用的靜態值 reduce_vars: true, } } })
關於開啟多進程要按需使用,
項目大,打包速度慢,開啟多進程提高速度
項目小,打包速度快,開啟多進程反而降低速度
6、自動刷新(不可用於生產)
{ watch:true, // 開啟監聽,預設 false // 註意,開啟監聽之後,webpack-dev-server 會自動開啟刷新瀏覽器 // 監聽配置 watchOptions:{ ignored: /node_modules/, // 忽略內容 // 監聽到變化發生後等300ms再去執行動作,防止文件更新太快導致重新編譯頻率太高 aggregateTimeout:300, // 預設為300ms // 判斷文件是否發生變化時通過不停的去詢問系統指定文件有沒變化實現的 poll:1000, // 預設每隔1000ms詢問一次 } }
以上配置一般開發不會配置到,因為開啟webpack-dev-server會自動帶上自動刷新的配置。以上配置是為了理解自動刷新有哪些內容。
7、熱更新(不可用於生產)
自動刷新:整個網頁全部刷新,速度較慢,狀態會丟失
熱更新:新代碼生效,網頁不刷新,狀態不丟失
熱更新使用插件:HotModuleReplacementPlugin
在entry入口中要新增兩行配置:
entry:{ index:[ 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/dev-server', path.join(srcPath,'index.js') ] }
然後在plugin中使用HotModuleReplacementPlugin插件。
最後在devServer中增加一個屬性:hot:true,開啟熱更新。
配置熱更新後,需要增加需要熱更新模塊的邏輯代碼,如下
if(module.hot){ moudule.hot.accept(['./math'],()=>{ // 熱更新模塊裡面的回調函數 }) }
8、DllPlugin 動態鏈接庫(不可用於生產)
使用前提:
前端框架如vue、react體積大,構建慢,比較穩定,不常升級。
同一個版本只構建一次即可,不用每次都重新構建。
webpack已內置DllPlugin支持。
使用過程:
DllPlugin先打包出dll文件
DllReferencePlugin再使用dll文件
四、優化產出代碼
優化方向:體積更小,合理分包,不重覆載入,速度更快,記憶體使用更少
1、小圖片Base64編碼
2、bundle加hash
3、懶載入
4、提取公共代碼
5、IngorePlugin
6、使用CDN加速:
在output設置publicPath,會修改所有js跟css文件添加cdn首碼
在url-loader設置publicPath,可以修改圖片的cdn首碼
7、使用production
開啟production模式跟development相比的差異點:
(1)自動開啟代碼壓縮
(2)Vue React等會自動刪掉調試代碼(如開發環境的warning)
(3)自動啟動Tree-Shaking,必須用ES6 Module 才能讓tree-shaking生效,commonjs就不行
ES6 Module 靜態引入,編譯時引入
Commonjs動態引入,執行時引入
只有靜態引入才能進行靜態分析,實現Tree-Shaking
8、Scope Hosting
開啟之後,會將多個引用文件合併成一個函數,減少函數作用域,代碼體積更小,代碼可讀性更好
如何配置:
引用ModuleConcatenationPlugin插件,使用插件即可開啟。
針對npm中第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件
resolve:{ mainFields: ['jsnext:main','brower','main'] }
五、babel
基本配置:.babelrc文件
plugins是寫如何翻譯語法的插件,presets是集合多個插件整合的一個包。
{ "presets":[ ["@babel/preset-env"] ], "plugins":[] }
babel-polyfill:相容低版本瀏覽器,重寫低版本沒有的新語法。
core-js和regenerator兩個庫可以滿足最大多數新語法的polyfill,babel-polyfill就是前兩個庫的集合。
babel 7.4之後已經棄用了babel-polyfill,而推薦直接使用core-js和regenerator。
直接使用的弊端是由於重寫全局方法會污染全局環境。
babel-runtime:
使用runtime配置,可以使polyfill重寫的方法不污染全局環境,相當於重命名方法,代碼也是自動替換成新名稱的方法。
面試真題:
1、前端代碼為什麼要進行構建和打包?
代碼層面:
(1)體積更小(Tree-Shaking、壓縮、合併),載入更快
(2)編輯高級語言或語法(TS、ES6+、模塊化,scss)
(3)相容性和錯誤檢查(Polyfill、postcss、eslint)
研發流程:
(1)統一、高效的開發環境
(2)統一的構建流程和產出標準
(3)集成公司構建規範(提測、上線等)
2、module chunk bundle 分別什麼意思,有何區別?
module - 各個源碼文件,webpack 中一切皆模塊
chunk - 多模塊合併成的,如 entry import() splitChunk
bundle - 最終的輸出文件
3、loader和plugin的區別?
loader模塊轉換器,如 less 轉 css。說出一些常用的loader
plugin擴展插件,如 HtmlWebpackPlugin。說出一些常用的plugin
4、babel和webpack的區別?
babel是JS新語法編譯工具,不關係模塊化
webpack是打包構建工具,是多個 loader plugin 的集合
5、如何產出一個 lib
output:{ // lib的文件名 filename: 'lodash.js', // 輸出 lib 到dist 目錄下 path: distPath, // lib 的全局變數名 library: 'lodash' }
6、webpack如何實現懶載入?
import()語法實現
結合 Vue React 非同步組件,結合 Vue-router React-router 非同步載入路由來簡要說下。
7、webpack常見性能優化?
將上面的三、四的優化內容根據實際效果講下
8、babel-runtime和babel-polyfill的區別?
babel-polyfill會污染全局
babel-runtime不會污染全局
產出第三方 lib 要用 babel-runtime
9、為何Proxy 不能被 polyfill?
Class 可以用 function 模擬, Promise 可以用 callback 來模擬
但是Proxy的功能用Object.defineProperty 無法模擬
放棄安逸,持續努力——成長