Working with Modules and Code Splitting
HyperRedStart
Posted on April 8, 2022
此章節會介紹 Webpack 中的 模組 (Module) 以及程式碼分離 (Code Splitting) 兩個 Webpack 特色,透過以上特色使專案代碼分割並以最適合的方式分割代碼。
此章節包含內容:
- 解釋 Webpack 中的 Modules
- 了解 Code Splitting 機制
- 將所需要的模組預先載入
- 範例展示
Module
透過 Webpack 模組會將共用的方法集合在同一檔案內,並會依照不同類型進行分類,如下圖所釋:
Webpack 根據不同的模組標準有以下幾種語句:
ECMA 2015 : import
CommonJS : require
ASM(Asynchronous Module Definition) : define / require
CSS : @import stylesheet
模組支援語言
確保 Webpack 支援這些模組,必須要使用允許的程式語言,透過 Webpack 社群所建立的 Loaders 支援了大量的語言例如以下幾種。
- TypeScript
- SASS
- LESS
- C++
- Babel
- Bootstrap
載入模組路徑
絕對路徑
從根目錄開始定位到引用檔案
import 'C:\Users\project\file';相對路徑
根據當前檔案定位到引用檔案
import '../src/file';模組路徑
從模組中搜尋名稱,引用模組內的檔案
import 'module/sub-directory/file';
Code Splitting
允許使用者將片段的程式放入不同的套件中,並且可以按需求或是並行載入,被認為是 Webpack 最具矚目的功能。
達成方法
- Entry Points: 可以手動設置片段程式進入點設定檔
- SplitChunksPlugin: 並免相同程式載入,將片段的程式碼整合成群組這種群組稱為 "chunks"
- Dynamic Imports: 透過程式來動態將片段程式碼載入
Entry Points
使用 Entry points 是最簡單可以達成 code splitting 的方法。
我們根據第一章範例的專案,增改以下內容
src/another-module.js
import _ from 'lodash';
console.log(_.join(['Another', 'module', 'loaded!'], ' '));
webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
編譯專案
$ npm run build
Asset Size Chunks Chunk Names
another.bundle.js 550 KiB another [emitted] another
index.bundle.js 550 KiB index [emitted] index
Entrypoint index = index.bundle.js
Entrypoint another = another.bundle.js
編譯完成後再 dist 目錄下產生了 index.bundle.js/another.bundle.js 倆的檔案,但因為兩支js程式都有加載 lodash 導致兩支程式代碼重複。
SplitChunksPlugin
預防重複程式碼
從剛剛的 entrypoints 結果我們的程式碼重複了,為了避免這個狀況我們可以使用 SplitChunks 的 Webpack 套件
webpack.config.js
在 module 中 增加 optimization 參數,再進行編譯
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
編譯專案
$npm run build
> 01-sample-app2@1.0.0 build
> webpack --config webpack.config.js
asset vendors-node_modules_lodash_lodash_js.bundle.js 550 KiB [emitted] (id hint: vendors)
asset index.bundle.js 8.83 KiB [emitted] (name: index)
asset another.bundle.js 8.75 KiB [emitted] (name: another)
Entrypoint index 559 KiB = vendors-node_modules_lodash_lodash_js.bundle.js 550 KiB index.bundle.js 8.83 KiB
Entrypoint another 559 KiB = vendors-node_modules_lodash_lodash_js.bundle.js 550 KiB another.bundle.js 8.75 KiB
runtime modules 7.3 KiB 16 modules
cacheable modules 532 KiB
./src/index.js 212 bytes [built] [code generated]
./src/another-module.js 83 bytes [built] [code generated]
./node_modules/lodash/lodash.js 531 KiB [built] [code generated]
webpack 5.69.1 compiled successfully in 326 ms
此時除了 anotherjs 與 indexjs 外多了一個檔案 "vendors-node_modules_lodash_lodash_js.bundle.js" lodash 的代碼就統一放在這個檔案,避免代碼重複
現在我們了解了如何避免重複代碼,接下來就要換到另一個更難的主題,Dynamic Imports。
Dynamic Imports
Dynamic Imports 是實現 on-demand imports 的必要方法。
webpack.config.js
output 中增加 chunkFilename 指定Dynamic Import Moudle 檔案名稱
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: './src/index.js'
},
output: {
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
};
index.js
透過在程式中 import 以動態的方式載入第三方模組,編譯過後就會產生相應檔案,並透過 webpackChunkName 指定產出名稱。
function getComponent() {
return import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'Webpack'], ' ');
return element;
}).catch(error => 'An error occurred while loading the component');
}
getComponent().then(component => {
document.body.appendChild(component);
});
編譯專案
$npm run build
> 01-sample-app2@1.0.0 build
> webpack --config webpack.config.js
asset another.bundle.js 554 KiB [emitted] (name: another)
asset lodash.bundle.js 550 KiB [emitted] (name: lodash) (id hint: vendors)
asset index.bundle.js 14.2 KiB [emitted] (name: index)
runtime modules 9.2 KiB 17 modules
cacheable modules 532 KiB
./src/index.js 390 bytes [built] [code generated]
./src/another-module.js 83 bytes [built] [code generated]
./node_modules/lodash/lodash.js 531 KiB [built] [code generated]
webpack 5.69.1 compiled successfully in 316 ms
透過這些方法可以改善瀏覽器的快取速度。
Caching
章節最後也介紹了其他的 Plugin 來協助我們來預先載入或是減少記憶體用量。
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "Output Management",
title: "Caching",
}),
],
output: {
filename: "bundle.js",
filename: "[name].[contenthash].js",
path: path.resolve(__dirname, "dist"),
},
};
好了我們的第二章節 Working with Modules and Code Splitting 結束 🎉
後面的章節會再介紹有關 Webpack 的強大功能!敬請期待!
Posted on April 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.