什麼是前端模組化?
2024年10月25日
面試中,關於打包工具的相關知識是非常常見的考題,無可避免的可能會被問到,為什麼需要使用到打包工具、或前端工程化的實現,而要回答這些問題前,需要先了解的就是前端模組化。所以在本篇筆記中,會讓大家了解前端模組化的演進和功用。
什麼是模組化?
開發人員將程式碼或系統分割為不同模組的過程,就稱為模組化。每個模組就代表一個完整的小程序或小功能,所有模組組裝起來成為一個整體,進而完成整個系統的功能要求。
Node.js 幾乎一開始就支持模組化,相比之下 Web 開發,模組化應用進展慢了許多,但到今日也出現了許多支持前端模組化的工具。
為什麼需要前端模組化?
我們先來想像如果今天不用打包工具、模組化語法,要如何在瀏覽器上執行 JavaScript?
- 方法一:每個功能就是一個 JavaScript script 檔案並載入。但此方法會讓程式碼難以擴展,載入太多 script 也會導致網路瓶頸,並且也有載入先後順序的相依性問題。
- 方法二:使用一個統一的大
.js
檔案,將所有功能都包含在其中,但這會導致維護、易讀性方面的問題。
模組化工具出現之前,會透過一些方案來解決上述的做法問題,最常見的就是透過立即執行函式(IIFE),它其實是利用函式的閉包特性來實踐數據私有化和共享方法,如下範例
const moduleB = (function () {
return {
number: 200,
};
})();
const moduleA = (function (otherModule) {
let number = 100;
function getNumber() {
console.log(number + otherModule.number);
}
return { getNumber };
})(moduleB);
我們可以透過 moduleA
拿到 getNumber
方法,並且實踐 number
變數的私有化,防止外部調用,此外 moduleA
也可以引入其他 module
,通過這種方式,我們就可以在 moduleA 中使用其他模組,進而解決很多問題。
moduleA.getNumber(); // 300
moduleA.number; // undefined
IIFE 的做法也成為現在模組化的概念來源。但隨著前端對模組需求越來越大,逐漸出現了一些模組化解決方案、並演變成了通用的規範,從 CommonJS 到現在的 ES Module(ESM)。下個段落會介紹各個通用的模組化規範
延伸閱讀:JavaScript 立即調用函式 IIFE (Immediately Invoked Function Expression) 是什麼?優缺點是什麼?
JS 模組化規範
CommonJS
當 Node.js
發佈時,它帶來了新的挑戰。因為 JavaScript 不是在瀏覽器中運行,因此沒有可以添加到其中的 html 文件和腳本標籤,那麼 Node
應用程序應該如何加載不同的程式碼呢?- 透過 CommonJS
。CommonJS
規範在 2009 年被社群開發出來,引入了 require
和 export
宣告模組的語法,一個文件就是一個模組,是以同步的方式載入模組,因此適合伺服器端的開發。
AMD(Async Module Definition)
AMD
在中文是非同步模組定義的意思。它起源於 Dojo 工具箱 (一套 JavaScript Web 應用程式庫)。同時,AMD
一開始就是為瀏覽器而設計的,目前為止,最受歡迎的 AMD
實作是 RequireJS (一個 JavaScript 模組加載器)。AMD
可以自動決定相依關係,模組是以非同步方式載入,避免阻塞的問題,並且可以把多個模組定義在同一個檔案中。
CMD(Common Module Definition)
CMD
的出現較晚一些, Sea.js
在 2012 年開始推廣,它汲取了 CommonJS
和 AMD
規範的優點,也是專門用於瀏覽器的異步模塊加載。在規範中,一個文件就是一個模組。
UMD(Universal Module Definition)
AMD
和 CommonJS
是最受歡迎的兩套模組標準,也各有優缺點,通常開發者會根據自己的需求選擇不同的標準。但是,我們也有可能會去使用到不同標準所開發出來的程式碼,這可能就會造成問題。一種解決方案就是 UMD
,它可以讓 AMD
和 CommonJS
使用同一份檔案。
ES Module(ESM)
ES6 發佈之後,終於實現了模塊的功能,並結合了 CommonJS
和 AMD
的兩者優點
- 類似
CommonJS
,引入簡單的語法如export
和import
,並且也是一個檔案為一個模組 - 類似於
AMD
也有支援非同步載入
模組打包工具(Module Bundler)的作用
上個段落介紹了不同模組規範,以及 RequireJS 等模組加載工具被創建,讓我們能在瀏覽器中使用模組。然而,雖然有這些模組化工具,因為各家瀏覽器支援度不同等問題,導致有時候如果你想用別人寫好的模組 (例如 npm 上的套件),很可能沒辦法順利引用。
因為有瀏覽器模組機制相容性、兼容性的問題,前端業界後來發展出 webpack 等工具,協助開發者打包模組,所以假如你的程式碼中,有使用某個 npm 的套件,webpack 會協助你打包,讓他變得像是你自己寫的模組,這有效解決瀏覽器模組功能支援度的問題。
除此之外, webpack 這類的不只幫助我們加載管理程式碼的模組。它進一步擴展到可以支援不同的資源載入,讓各種不同資源都可以變成一個模組 (如:圖像、字體和樣式表)。此外,它可以有其他優化,提供更好的使用者和開發者體驗。