Webpack模塊化原理圖解

<script src="a.js"></script><script src="b.js"></script>
這時(shí)模塊a,模板b中的代碼都暴露在全局環(huán)境中,如果模塊a中定義了一個(gè)方法del。同學(xué)b并不知道,在模塊b中也定義了一個(gè)方法del。這時(shí)便造成了命名沖突的的問題。如圖

場(chǎng)景2
C同學(xué)開發(fā)了一個(gè)公共的工具庫utils.js,D同學(xué)開發(fā)了一個(gè)公共的組件tab.js,tab.js依賴utils.js。同學(xué)E需要使用D同學(xué)開發(fā)的tab.js,就需要通過如下方式引用
<script src="util.js"></script><script src="tab.js"></script>
同學(xué)E自己也開發(fā)了一個(gè)dailog.js同時(shí)它也依賴util.js。現(xiàn)在頁面同時(shí)引用了dialog.js和tab.js,代碼如下。
<script src="util.js"></script><script src="dialog.js"></script><scrpt src="tab.js"></script>
同學(xué)E不僅需要同時(shí)引用這三個(gè)js文件,還必須保證文件之間的引用順序是正確的。同時(shí),從上面的代碼我們無法直接看出模塊與模塊之間的依賴關(guān)系,如果不深入tab.js,我們無法知道tab.js到底是只依賴util.js還是dialog.js或者兩者都依賴。隨著項(xiàng)目逐漸增大,不同模塊之間的依賴關(guān)系則會(huì)變的越來越難以維護(hù)也會(huì)導(dǎo)致許多模塊中大量的變量都暴露在全局環(huán)境中。
模塊化的幾種實(shí)現(xiàn)方案
模塊化的規(guī)范有很多種, 如下
| 規(guī)范 | 實(shí)現(xiàn)方案 |
| --- | --- |
| CommonJS | node.js |
| AMD | Require.js |
| CMD | Sea.js
| UMD | |
| ES6 Module | |
webpack支持CommonJS,AMD,ESModule等多種模塊化方式的語法。
webpack的模塊化原理
在webpack中,一切皆模塊。下面我們通過webpack來打包以下代碼。通過對(duì)打包代碼的解析,來一步一步的了解模塊化的實(shí)現(xiàn)原理。
目錄結(jié)構(gòu)如下:

代碼如下:
// webpack.config.jsconst path = require('path');module.exports = {entry: 'a.js',output: {path: path.resolve(__dirname, "dist"),filename: "[name].js"},resolve: {modules: [path.resolve(__dirname)]},optimization: {minimize: false}}// a.jsvar b = require('b');module.exports = b.text + ' world';// b.jsexports.text = 'hello';
在simple目錄下執(zhí)行webpack命令,會(huì)在simple目錄下生成dist/output.js文件。
// outout.js// 代碼及注釋如下(() => {// 所有導(dǎo)入的模塊都存儲(chǔ)在__webpack_modules__對(duì)象中,并且每個(gè)模塊都要一個(gè)標(biāo)識(shí)該模塊的idvar __webpack_modules__ = ({847: ((module, __unsed_webpack_exports, __webpack_require__) => {// 模塊a...}),996: ((__unused_webpack_module, exports) => {// 模塊b...})})var __webpack_module_cache__ = {};function __webpack_require__(moduleId) {// 檢查緩存中不存在847導(dǎo)出對(duì)象,防止模塊847多次執(zhí)行if (__webpack_module_cache__[moduleId]) {// 從緩存中返回847導(dǎo)出對(duì)象return __webpack_module_cache__[moduleId].exports;}// 1.創(chuàng)建{exports: {}}對(duì)象// 2.像緩存中添加該對(duì)象,并讓該對(duì)象與模塊id 847相關(guān)聯(lián)var module = __webpack_module_cache__[moduleId] = {exports: {}}// 3.通過__webpack_modules__查詢模塊847// 4.執(zhí)行模塊847并傳入剛剛創(chuàng)建的模塊847的導(dǎo)出對(duì)象module,以及module.exports等__webpack_modules__[moduleId](module, module.exports, __webpack_require__);// 5.返回模塊847的導(dǎo)出對(duì)象return module.exports;}// 導(dǎo)入模塊847__webpack_require__(847);})()
var module = {exports: {}}
(2)將該導(dǎo)出對(duì)象添加到__webpack_module_cache__對(duì)象中
__webpack_module_cahce__[moduleId] = module
(3)(4)通過__webpack_modules__查詢模塊847并執(zhí)行
// 傳入模塊847的導(dǎo)出對(duì)象,以及require接口__webpack_modules__[moduleId](module, module.exports, __webpack_require__)
(5)返回模塊847的導(dǎo)出對(duì)象
return module.exports
圖解如下:

橘黃色背景的元素代表數(shù)據(jù)
綠色背景的元素代表函數(shù)
總結(jié)
通過模塊化的管理方式
每個(gè)模塊都通過函數(shù)封裝在自己的局部環(huán)境中。 模塊與模塊之間通過require 接口進(jìn)行通信。且不用通過暴露在全局環(huán)境。
每個(gè)模塊都明確通過require接口傳入依賴的模塊,所以模塊與模塊之間的依賴關(guān)系也是非常明了的。如圖a -> b -> c -> d

模塊第1次被引用時(shí),調(diào)用require接口會(huì)像cache中添加導(dǎo)出對(duì)象。并返回添加的導(dǎo)出對(duì)象。
模塊被第2+次引用時(shí),調(diào)用require接口查詢cache對(duì)象時(shí),返回cache中對(duì)應(yīng)的導(dǎo)出對(duì)象。
本文完~

