webpack 性能優(yōu)化
開發(fā)環(huán)境性能優(yōu)化
優(yōu)化打包構(gòu)建速度
HMR優(yōu)化代碼調(diào)試source-map
生產(chǎn)環(huán)境性能優(yōu)化
優(yōu)化打包構(gòu)建速度
oneOf babel 緩存 多進(jìn)程打包 externals dll 優(yōu)化代碼運行的性能 緩存(hash,chunkhash,contenthash) tree shaking code split 懶加載和預(yù)加載 pwa
優(yōu)化 開發(fā)環(huán)境 打包構(gòu)建速度
HMR hot module replacement 熱模塊替換/模塊熱替換
作用:一個模塊發(fā)生變化,只會重新打包這一個模塊 而不是重新打包所有,極大提升構(gòu)建速度
樣式文件: 可以使用HMR功能,因為style-loader內(nèi)部實現(xiàn)了 js文件: 默認(rèn)不能使用HMR功能 -->解決:需要修改js代碼,添加支持HMR功能的代碼。注意,HMR功能對js的處理,只能處理非入口js文件的其他文件。
- if(module.hot){
 - //一旦module.hot是true,說明開啟HMR功能,讓HMR功能代碼生效
 - module.hot.accept('./xxx.js',function(){
 - //此方法會監(jiān)聽print.js文件的變化,一旦發(fā)生變化,其他默認(rèn)不會重新打包構(gòu)建
 - //會執(zhí)行后面的回調(diào)函數(shù)
 - xxx();
 - })
 - }
 
html文件: 默認(rèn)不能使用HMR功能,同時會導(dǎo)致問題:html文件不能熱更新了 解決:改 entry:['入口js','html'] ,但html文件只有一個,所以不用做HMR功能
- devServer:{
 - //項目構(gòu)建后的目錄
 - contentBase: resolve(__dirname,'build'),
 - //啟用gzip壓縮
 - compress:true,
 - //端口號
 - port:3000,
 - //自動打開瀏覽器
 - open:true
 - }
 
優(yōu)化 開發(fā)環(huán)境 代碼調(diào)試
source-map 一種提供源代碼到構(gòu)建后代碼映射的技術(shù)
如果構(gòu)建后代碼出錯了,通過映射可以追蹤到錯誤的代碼
- webpack.config.js
 - devtools:'source-map'
 - //其他 參數(shù) [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
 - source-map : 外部
 - 錯誤代碼的準(zhǔn)確信息和錯誤位置
 - inline-source-map : 內(nèi)聯(lián)
 - 錯誤代碼的準(zhǔn)確信息和錯誤位置
 - hidden-source-map : 外部
 - 錯誤代碼的錯誤原因 但沒有錯誤位置,不能追蹤到源代碼的錯誤,只能提示到構(gòu)建后代碼的位置
 - eval-source-map : 內(nèi)聯(lián)
 - 每一個文件都生成對應(yīng)的source-map,都在eval
 - 錯誤代碼的準(zhǔn)確信息和錯誤位置
 - nosources-source-map : 外部
 - 能找到錯誤代碼的準(zhǔn)確信息 但沒有任何源代碼信息
 - cheap-source-map : 外部
 - 錯誤代碼的準(zhǔn)確信息和錯誤位置 只精確到行,不精確到列
 - cheap-module-source-map : 外部
 - 錯誤代碼的準(zhǔn)確信息和錯誤位置
 - module 會將 loader 的 source-map加入
 - 內(nèi)聯(lián) 和 外部的區(qū)別 :
 - 1.外部生成了文件但內(nèi)聯(lián)沒有生成
 - 2.內(nèi)聯(lián)構(gòu)建速度更快
 
開發(fā)環(huán)境:速度快,調(diào)試更友好
- 速度快 eval>inline>cheap>...
 - 調(diào)試更友好 souce-map>cheap-module-souce-map>cheap-souce-map
 - 所以 一般用eval-source-map
 
生產(chǎn)環(huán)境:源代碼要不要隱藏,調(diào)試要不要友好?內(nèi)聯(lián)會讓體積編碼,所以一般不用內(nèi)聯(lián)
- nosources-source-map 隱藏源代碼
 - hidden-source-map 只隱藏源代碼,會提示構(gòu)建購代碼錯誤信息
 - --> source-map /cheap-module-souce-map
 
優(yōu)化生產(chǎn)環(huán)境
oneOf
rules里中有許多個loader,這樣會導(dǎo)致每個文件都會被所有的loader過一遍,有些能處理,有些處理不了。所以可以利用oneOf達(dá)到以下loader只會匹配到第一個。但需要注意,不能有兩個loader同時處理同一個文件
- webpack.config
 - module.exports={
 - //....
 - module:{
 - rule:[
 - //正常來講,一個文件只能被一個loader處理
 - //當(dāng)一個文件要被多個loader處理,那么一定要指定loader的執(zhí)行順序
 - // 先執(zhí)行eslint 再執(zhí)行babel
 - {
 - test:/\.js$/,
 - exclude:/node_modules/,
 - //優(yōu)先執(zhí)行
 - enforce:'pre',
 - loader:'eslint-loader',
 - options:{
 - fix:true
 - }
 - },
 - {
 - oneOf:[
 - {
 - test: /\.css$/,
 - use:[
 - ...commonCssLoader
 - ]
 - },
 - {
 - test:/\.less$/,
 - use:[
 - ...commonCssLoader,'less-loader'
 - ]
 - },
 - {
 - test:/\.js$/,
 - exclude:/node_modules/,
 - loader:'babel-loader',
 - options:{
 - // 預(yù)設(shè) :指示babel做怎樣的兼容性處理
 - presets:[
 - [
 - '@babel/preset-env',
 - {
 - //按需加載
 - useBuiltIns:'usage',
 - //指定core-js版本
 - corejs:{
 - version:3
 - },
 - //指定兼容性做到哪個版本的瀏覽器
 - targerts:{
 - chrome: '40',
 - fixfox: '50',
 - ie: '9',
 - safari: '10',
 - edge: '17'
 - }
 - }
 - ]
 - ]
 - }
 - },
 - {
 - test:/\.(png|jpg|gif)/,
 - loader:'url-loader',
 - enModule:true,
 - options:{
 - limit:8*1024,
 - name: '[hash:10].[ext]',
 - outputpath:''
 - }
 - },
 - {
 - test:/\.html$/,
 - loader:'html-loader'
 - },
 - {
 - exclude:/\.(js|less|css|png|jpg|gif)/,
 - loader:'file-loader',
 - options:{
 - name:'[hash:10].[ext]'
 - }
 - }
 - ]
 - }
 - ]
 - },
 - }
 
緩存
1.babel緩存-->第二次打包更快
- {
 - test:/\.js$/,
 - exclude:/node_modules/,
 - loader:'babel-loader',
 - options:{
 - // 預(yù)設(shè) :指示babel做怎樣的兼容性處理
 - presets:[
 - [
 - '@babel/preset-env',
 - {
 - //按需加載
 - useBuiltIns:'usage',
 - //指定core-js版本
 - corejs:{
 - version:3
 - },
 - //指定兼容性做到哪個版本的瀏覽器
 - targerts:{
 - chrome: '40',
 - fixfox: '50',
 - ie: '9',
 - safari: '10',
 - edge: '17'
 - }
 - }
 - ]
 - ],
 - //第二次構(gòu)建時,會讀取之前的緩存
 - cacheDirectory: true
 - }
 - },
 
2.文件資源緩存-->上線緩存優(yōu)化
- hash:每次webpack構(gòu)建會生成一個唯一hash值
 - 問題: 因為js和css同時使用一個hash值,如果重新打包,會導(dǎo)致所有緩存失效,可能我卻只改了一個文件,
 - chunkhash:根據(jù)chunk生成hash值,如果打包來源于同一個chunk,那么hash值也一樣
 - 問題:js和css的hash值還是一樣的。
 - 原因:css是由js引入的,所以屬于同一個chunk
 - contenthash: 根據(jù)文件內(nèi)容生成hash值,
 
- webpack.config.js
 
tree shaking
去除應(yīng)用程序中沒有使用的代碼
- 前提:
 - 1.必須使用es6模塊化
 - 2.開啟production模式
 - 在package.json中配置
 - "sideEffects":false 所有代碼都沒有副作用,都可以鏡像tree sharking
 - 問題 可能會把css/@babel/polyfille 干掉
 - "sideEffects": ["*.css","*.less"] 哪些文件不 tree sharking
 
code split
1.入口配置
- 單入口 //單頁面應(yīng)用
 - entry:'./src/js/index.js'
 - 多入口 //多頁面應(yīng)用
 - entry:{
 - index:'./src/js/index.js',
 - test:'./src/js/test.js'
 - }
 
2.optimization
- module.exports={
 - //...
 - // 可以將nodemudules中的代碼單獨打包成一個chunk最終輸出
 - // 還可以自動分析多入口chunk中,有沒有公共的文件,如果有會打包成一個單獨的chunk
 - optimization:{
 - splitChunks:{
 - chunks:'all'
 - }
 - }
 - }
 
3.import 動態(tài)導(dǎo)入語法,能將某個文件單獨打包
通過js代碼,讓某個文件被單獨打包成一個chunk,通過注釋可以固定此文件的名稱
- import(/*webpackChunkName: 'xxxName' */'./xx/xxx.js')
 - .then(res =>{
 - //加載成功
 - })
 - .catch(()=>{
 - //加載失敗
 - })
 
懶加載和預(yù)加載
1.懶加載 當(dāng)文件需要用時才加載
import 動態(tài)導(dǎo)入語法
- document.getElementById('btn').onclick = function(){
 - import(/*webpackChunkName: 'xxxName' */'./xx/ss.js')
 - .then(res=>{
 - //干啥干啥
 - })
 - }
 
2.預(yù)加載 webpackPrefetch:true
./xx/ss.js 已經(jīng)被加載了,點擊的時候再從緩存中加載,
- document.getElementById('btn').onclick = function(){
 - import(/*webpackChunkName: 'xxxName',webpackPrefetch:true */'./xx/ss.js')
 - .then(res=>{
 - //干啥干啥
 - })
 - }
 
正常加載可以認(rèn)為是并行加載(同一時間加載多個文件) 預(yù)加載prefectch 等其他資源加載完畢,瀏覽器空閑了,再偷偷加載資源 兼容性比較差 慎用
PWA 漸進(jìn)式網(wǎng)絡(luò)開發(fā)應(yīng)用程序
網(wǎng)絡(luò)離線可訪問
webbox-->webbox-webpack-plugin
- const WebboxWebpackPlugin = require('webbox-webpack-plugin')
 - module.exports={
 - plugins:[
 - new WebboxWebpackPlugin.GenerateSW({
 - /*
 - 1.幫助 serviceWorker 快速啟動
 - 2.刪除舊的 serviceWorker
 - 生成一個 serviceWorker 配置文件
 - */
 - clientsClaim:true,
 - skipWaiting:true
 - })
 - ]
 - }
 - index.js 中注冊serviceworker
 - //處理兼容性
 - if('serviceWorker' in navigator){
 - window.addEventListener('load',()=>{
 - navigator.serviceWorker
 - .register('./service-work.js')
 - .then(()=>{
 - //成功
 - })
 - .catch(()=>{
 - //失敗
 - })
 - })
 - }
 - 1.可能會出現(xiàn)問題 eslint不認(rèn)識window和navigator
 - 解決 package.json中eslintConfig中配置
 - "env":{
 - "browser":true //支持瀏覽器端的變量
 - }
 - 2. sw代碼必須運行在服務(wù)器上
 - -->node.js
 - --> npm i serve -g
 - serve -s build 啟動一個服務(wù)器將build下的資源作為靜態(tài)資源暴露出去
 
多進(jìn)程打包
thread-loader 一般給babel-loader用
但需要注意
進(jìn)程啟動大約需500ms,進(jìn)程間通信也有開銷。只有工作消耗時間比較長,才需要多進(jìn)程打包
- {
 - test:/\.js$/,
 - exclude:/node_modules/,
 - use:[
 - //'thread-loader',
 - {
 - loader:'thread-loader',
 - options:{
 - workers: 2 //進(jìn)程2個
 - }
 - }
 - {
 - loader:'babel-loader',
 - options:{
 - // 預(yù)設(shè) :指示babel做怎樣的兼容性處理
 - presets:[
 - [
 - '@babel/preset-env',
 - {
 - //按需加載
 - useBuiltIns:'usage',
 - //指定core-js版本
 - corejs:{
 - version:3
 - },
 - //指定兼容性做到哪個版本的瀏覽器
 - targerts:{
 - chrome: '40',
 - fixfox: '50',
 - ie: '9',
 - safari: '10',
 - edge: '17'
 - }
 - }
 - ]
 - ],
 - //第二次構(gòu)建時,會讀取之前的緩存
 - cacheDirectory: true
 - }
 - }
 - ]
 - },
 
externals
- module.exports={
 - externals:{
 - //忽略/拒絕 庫名 -- npm 包名
 - //可以在index.html中引入cdn
 - }
 - }
 
dll 動態(tài)連接
使用dll技術(shù) 對某些庫(第三方庫) 進(jìn)行單獨打包
- 指令 webpack --config webpack.dll.js
 - webpack.dll.js
 - const {resolve} = require('path')
 - const webpack = require('webpack')
 - module.exports = {
 - entry:{
 - //最終打包生成的[name]-->jquery
 - //['jquery']-->要打包的庫是jquery
 - jquery:['jquery']
 - },
 - ouput:{
 - filename:'[name].js',
 - path:resolve(__dirname,'dll'),
 - library:'[name]_[hash]' //打包的庫里面向外暴露出去的內(nèi)容叫什么名字
 - },
 - plugin:[
 - new webpacl.DllPlugin({
 - //打包生成一個manifest.json --> 提供和jquery映射
 - name: '[name]_[hash]',//映射庫的暴露內(nèi)容名稱
 - path:resolve(__dirname,'dll/manifest.json')
 - })
 - ],
 - mode:'production'
 - }
 - webpack.config.js
 - const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
 - module.exports={
 - plugins:[
 - //告訴webpack哪些庫不參與打包,同時名稱也得變
 - new webpack.DllReferencePlugin({
 - manifest: resolve(__dirname,'dll/manifest.json')
 - }),
 - //將某個文件打包輸出出去,并在html中引入該資源
 - new AddAssetHtmlWebpackPlugin({
 - filepath:resolve(__dirname,'dll/jquery.js')
 - })
 - ]
 - }
 
編輯推薦















 
 
 






 
 
 
 