淺談Webpack是如何打包CommonJS的
CommonJS 是 Node 中的一種模塊化規(guī)范,其是一種運行在 Node 環(huán)境下的代碼,這種代碼是不能直接運行到瀏覽器環(huán)境中的。但是在日常使用 webpack 的項目中不用做額外的處理,我們也能使用 CommonJS 來書寫代碼,那么 webpack 在這背后做了什么呢?
我們這里不看編譯時,只看運行時
一、書寫代碼
使用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)文章
ES6中的Promise對象與async和await方法詳解
Promise是es6引入的異步編程薪解決方案,語法上promise就是一個構(gòu)造函數(shù),用來封裝異步操作病可以獲取其成功或失敗的結(jié)果,這篇文章主要介紹了ES6中的Promise對象與async和await方法,需要的朋友可以參考下2022-12-12
微信小程序之swiper輪播圖中的圖片自適應(yīng)高度的方法
這篇文章主要介紹了微信小程序之swiper輪播圖中的圖片自適應(yīng)高度的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
IE6/7 and IE8/9/10(IE7模式)依次隱藏具有absolute或relative的父元素和子元素后再顯示
多數(shù)情況下隱藏(設(shè)置display:none)一個元素,無需依次將其內(nèi)的所有子元素都隱藏。非要這么做,有時會碰到意想不到的bug。2011-07-07
javascript設(shè)計模式 – 職責(zé)鏈模式原理與用法實例分析
這篇文章主要介紹了javascript設(shè)計模式 – 職責(zé)鏈模式,結(jié)合實例形式分析了javascript職責(zé)鏈模式相關(guān)概念、原理、用法及操作注意事項,需要的朋友可以參考下2020-04-04
Js模塊打包exports require import的用法和區(qū)別
這篇文章主要介紹了Js模塊打包exports require import的用法和區(qū)別,對模塊打包感興趣的同學(xué),可以參考下2021-05-05
網(wǎng)頁中可關(guān)閉的漂浮窗口實現(xiàn)可自行調(diào)節(jié)
廣告式的漂浮窗口,想必大家并不陌生吧,下面為大家簡單介紹下具體的實現(xiàn),有需要的朋友可以參考下2013-08-08
jQuery及JS實現(xiàn)循環(huán)中暫停的方法
這篇文章主要介紹了jQuery及JS實現(xiàn)循環(huán)中暫停的方法,以實例形式分析了循環(huán)中暫停的原理及實現(xiàn)技巧,非常具有實用價值,需要的朋友可以參考下2015-02-02

