webpack5文件解析(下)

行俠仗義的小龍女發表於2020-10-23

宣告:所有的文章demo都在我的倉庫

程式碼分離

程式碼分離的有點在於:

  1. 切割程式碼,生成不同的打包檔案,按需載入這些檔案。
  2. 每個bundle的體積更小
  3. 控制外部資源的載入順序

常用的方法有:

  1. 入口起點:使用入口entry手動分離
  2. 防止重複:使用SplitChunksPlugin去重和分離chunk
  3. 動態匯入:通過模組的行內函數呼叫分離的程式碼

入口起點

新增另一個檔案another-module.js檔案,並在webpack.config.js中進行配置。

entry:{//打包入口
    index:'./src/index.js',
    another:'./src/another-module.js'
},

進行打包後,結果正常。

優點:常用常規的寫法。

缺點:1.如果有相同的模組,不會去重,還是會在每個bundle中被重複的引用。2.不能將核心程式碼進行分割

防止重複

入口依賴

配置dependOn選項,可以在多個chunk之間進行共享模組。

SplitChunkPlugin

為了解決多個bundle引入相同模組的問題,引入這個模組進行去重。

SplitChunkPlugin將公共的模組引入到已有的入口中,或者提取到新的chunk。

相關配置如下:

//webpack.config.js
optimization:{
    splitChunks:{
        chunks:'all'
    }
},

SplitChunkPlugin建立了新的chunk,如下圖所示,shared.bundle.js。將我其他頁面所使用的js引入的lodash模組引入這個檔案中。

*** 以上程式碼在webpack-demo5

快取

通常部署檔案是將webpack打包出來的/dist檔案,部署到server上,客戶端通過訪問server的網站及資源。

由於客戶端訪問server時,非常耗時和耗流量,於是瀏覽器採用快取技術,可以直接從快取中獲取相關的內容,降低了請求的速度和流量。但是這也有一個缺點:如果檔名跟之前的一致,瀏覽器會認為這個檔案沒有做修改,還是會從快取中獲取相關內容。

我們想要的現象是:檔案沒做修改時,瀏覽器從快取中獲取,檔案修改了,重新獲取。

輸出檔案的檔名

webpack提供了一個substitution(可替換的模版字串)的方式,通過帶括號字串來模版化檔名。其中的[contenthash]是根據資源內容建立唯一的hash。當資源內容變化時,[contenthash]也會發生變化。

相關配置如下:

entry:'./src/index.js',
output:{//打包出口
    filename:"[name].[contenthash].js",//打包後的檔名稱
    path:path.resolve(__dirname,'dist')//路徑
}, 

使用contenthash,將內容變化直接反應打包輸出檔案的變化。

檔案不做修改,再次執行npm run build時,文件描述如下:

在我的實際操作中,我的打包檔案是不變的。

第一次:

第二次:

可能跟webpack版本的關係所致。。。

模組的概念

runtime:每個模組的載入和模組的解析邏輯。

manifest:解析和對映模組之間的聯絡

提取引導模版

runtime程式碼,提取到一個單獨的chunk中。optimization.runtimeChunk:'single'表示為所有的chunk建立一個runtime bundle

程式碼如下:

optimization:{
    runtimeChunk:'single'
},

將所有的第三方庫,如lodash/react等提取到單獨的vendor chunk檔案中。由於這些第三方庫不會去頻繁的修改原始碼,所以可以讓更少的向server發請求。

配置如下:

const path=require('path');
const {CleanWebpackPlugin}=require('clean-webpack-plugin')
const HtmlWebpackPlugin=require('html-webpack-plugin')

module.exports={
    mode:'development',
    entry:'./src/index.js',
    output:{//打包出口
        filename:"[name].[contenthash].js",//打包後的檔名稱
        path:path.resolve(__dirname,'dist')//路徑
    }, 
    devtool: 'inline-source-map',
    devServer:{
        contentBase:'./dist'
    },
    optimization:{
        runtimeChunk:'single',
        splitChunks:{
            cacheGroups:{
                vendor:{
                    test:/[\\/]node_modules[\\/]/,
                    name:'vendor',
                    chunks:'all'
                }
            }
        }
    },
    plugins:[
        new CleanWebpackPlugin({
            cleanStaleWebpackAssets:false
        }),
        new HtmlWebpackPlugin({
            title:'管理輸出'
        })
    ]
}

結果會出現一個帶有vendor的檔案。

main檔案裡,不再含有來自node_modulevendor程式碼,而且體積也減少了。

模組識別符號

新增print模組,並在index中進行引入,最終打包的結果跟之前比較結果如下:

我本地打包只有main的檔案進行了變化----符合預期

然而官網上展示的例子是不一樣,引出了需要引入optimization.moduleIds:'hashed'---苦笑不得

*** 以上程式碼在webpack-demo6

環境變數

可以在package.json中配置相關的命令列,可以快速的執行開發環境生產環境

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack serve --env development"
},

表示執行development環境。

模組熱替換(HMR)

模組熱替換(HMR--hot module replacement):在程式執行過程中,若有替換/新增/刪除模組,只更新修改的部分,不需要更新整個頁面。

此功能暫不支援生產環境。

程式碼配置如下:

devServer:{
    contentBase:'./dist',
    hot:true
},

在index頁面加入程式碼

if(module.hot){
  module.hot.accept('./print.js',function(){
    console.log('update the module1');
    Print()
  })
}

注意:執行時使用npm run start,啟動服務,可檢視熱更替。

*** 以上程式碼在webpack-demo7

模組熱更替跟熱更新是兩回事。模組熱更新是指修改了某個部分程式碼,不會重新整理頁面,而是在頁面更新這個模組。熱更新是指及時重新整理頁面。

Tree shaking

概念

是指在打包的時候,剔除沒有用到的程式碼。

但是隻支援ES module的import和export用法。

實踐

打包過程分成3部分:

  1. import會被打包成/* harmony import */做字首,表明這段是import進來的
  2. export會被打包成/* harmony export */做字首,表明這段是export
  3. 純函式,會被打包成/*#__PURE__*/,表明這個函式是純函式,可以被tree shaking

程式碼如下:

package.json

"name": "webpack-demo8",
"sideEffects":false,

webpack.config.js

optimization:{
    usedExports:true
}

*** 以上程式碼在webpack-demo8

我的倉庫地址,github,歡迎star~~

(完)

相關文章