淺談Webpack是如何打包CommonJS的
CommonJS 是 Node 中的一種模塊化規(guī)范,其是一種運(yùn)行在 Node 環(huán)境下的代碼,這種代碼是不能直接運(yùn)行到瀏覽器環(huán)境中的。但是在日常使用 webpack 的項(xiàng)目中不用做額外的處理,我們也能使用 CommonJS 來書寫代碼,那么 webpack 在這背后做了什么呢?
我們這里不看編譯時,只看運(yùn)行時
一、書寫代碼
使用yarn init -y
命令初始化一個package.json
文件。 接著yarn add webpack
安裝一下webpack
。 目錄下創(chuàng)建一個index.js
內(nèi)容如下:
const sum = require('./sum') console.log(sum(1, 2))
sum.js
文件內(nèi)容如下:
module.exports = (...args) => args.reduce((x, y) => x + y, 0)
二、使用webpack打包編譯
這里不想寫webpack的配置文件然后再通過 webpack-cli 來打包,就直接寫一個打包的文件。
// build.js const webpack = require('webpack') function f1() { return webpack({ entry: './index.js', mode: 'none', output: { iife: false, pathinfo: 'verbose' // verbose: 冗余;盡可能的詳細(xì) } }) } f1().run((err, stat) => { console.log('打包') })
接著在終端跑一下這個文件
node build.js
如果成功的話就會出來一個dist
目錄,里面有個main.js
總共就是50行代碼,其中大部分都是注釋,代碼如下
var __webpack_modules__ = ([ /* 0 */, /* 1 */ /*!****************!*\ !*** ./sum.js ***! \****************/ /*! unknown exports (runtime-defined) */ /*! runtime requirements: module */ /*! CommonJS bailout: module.exports is used directly at 1:0-14 */ ((module) => { module.exports = (...args) => args.reduce((x, y) => x + y, 0) }) ]); /************************************************************************/ // The module cache var __webpack_module_cache__ = {}; // The require function function __webpack_require__(moduleId) { // Check if module is in cache var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } // Create a new module (and put it into the cache) var module = __webpack_module_cache__[moduleId] = { // no module.id needed // no module.loaded needed exports: {} }; // Execute the module function __webpack_modules__[moduleId](module, module.exports, __webpack_require__); // Return the exports of the module return module.exports; } /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { /*!******************!*\ !*** ./index.js ***! \******************/ /*! unknown exports (runtime-defined) */ /*! runtime requirements: __webpack_require__ */ const sum = __webpack_require__(/*! ./sum */ 1) console.log(sum(1, 2)) })();
三、解析
我們再把代碼精簡一下,并加上注釋
// 存放的模塊,是一個數(shù)組 const __webpack_modules__ = [ , ((module) => { // sum.js 中的內(nèi)容 module.exports = (...args) => args.reduce((x, y) => x + y, 0) }) ] // 模塊緩存(也就是說如果模塊已經(jīng)被引用過了就直接從這兒拿) const __webpack_module_cache__ = {} // moduleId 為 __webpack_modules__ 的下標(biāo) function __webpack_require__(moduleId) { // 如果能從緩存里面拿到,則直接返回 const cachedModule = __webpack_module_cache__[moduleId] if (cachedModule !== undefined) return cachedModule.exports // 緩存內(nèi)拿不到,則創(chuàng)建一個對象同時內(nèi)部包含一個 exports 對象并存入到緩存內(nèi) const module = __webpack_module_cache__[moduleId] = { exports: {} } // 接著通過執(zhí)行 __webpack_modules__ 中的moduleId對應(yīng)函數(shù)并傳入 module 對象 // 通過函數(shù)內(nèi)賦值 module.exports 獲得 sum 函數(shù) __webpack_modules__[moduleId](module, module.exports, __webpack_require__) // 最后返回 module 中的 exports 對象 return module.exports } (() => { // index.js 中的內(nèi)容 const sum = __webpack_require__(1) console.log(sum(1, 2)) })();
我們通過注釋配合來解析一下
- 首先執(zhí)行立即執(zhí)行函數(shù)(L32)中的
__webpack_require__
函數(shù),并傳入moduleId 為 1
- 在
__webpack_require__
函數(shù)中嘗試在__webpack_module_cache__
中獲取moduleId
為 1 的模塊(L16) - 在
__webpack_module_cache__
中獲取失敗之后創(chuàng)建一個object
,同時內(nèi)部有屬性exports = {}
,并同時將其賦值給__webpack_module_cache__[moduleId]
(L20) - 執(zhí)行對應(yīng)的
moduleId
的函數(shù)__webpack_modules__[moduleId]
,同時將module
對象作為入?yún)ⅲ诤瘮?shù)內(nèi)將sum
函數(shù)賦值給參數(shù)module.exports
對象(L6),如此module.exports
就是sum
函數(shù)了 - 然后在
__webpack_require__
中返回module.exports
- 執(zhí)行完
__webpack_require__(1)
以后將其返回值賦值給sum
(L34) - 最后就可以調(diào)用
sum
函數(shù)了(L36)
到此這篇關(guān)于淺談Webpack是如何打包CommonJS的的文章就介紹到這了,更多相關(guān)Webpack打包CommonJS內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript如何將時間戳轉(zhuǎn)化為年月日時分秒格式
這篇文章主要給大家介紹了關(guān)于JavaScript如何將時間戳轉(zhuǎn)化為年月日時分秒格式的相關(guān)資料,在前端的日常工作當(dāng)中,時間戳的使用也是不少的,有時后端返回給我們的數(shù)據(jù)是一個時間戳,我們需要轉(zhuǎn)換成年月日,時分秒的形式展示在頁面當(dāng)中,需要的朋友可以參考下2023-11-11JavaScript canvas基于數(shù)組生成柱狀圖代碼實(shí)例
這篇文章主要介紹了JavaScript canvas基于數(shù)組生成柱狀圖代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03在一個瀏覽器里呈現(xiàn)所有瀏覽器測試結(jié)果的前端測試工具的思路
對前端工程師來說,跨瀏覽器的兼容性問題一直是最頭疼的,測試一個小小的東西,就要打開N個瀏覽器,然后比較來比較去,記錄個瀏覽器的數(shù)據(jù),比較不同,實(shí)在是麻煩.2010-03-03javascript 讀取xml,寫入xml 實(shí)現(xiàn)代碼
javascript xml讀取,寫入xml 實(shí)現(xiàn)代碼2009-07-07layer彈出的iframe層在執(zhí)行完畢后關(guān)閉當(dāng)前彈出層的方法
今天小編就為大家分享一篇layer彈出的iframe層在執(zhí)行完畢后關(guān)閉當(dāng)前彈出層的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08手寫的一個兼容各種瀏覽器的javascript getStyle函數(shù)(獲取元素的樣式)
這篇文章主要介紹了手寫的一個兼容各種瀏覽器的javascript getStyle函數(shù),用來取元素的樣式,需要的朋友可以參考下2014-06-06