文章目錄
1、分析編譯結果的目的 ?
對webpack的編譯結果
的認識對分析編譯過程
有幫助,理解了編譯過程對後面使用webpack的加載器和插件
的理解有幫助;
2、自己嘗試手寫dist/main.js
自己嘗試手寫dist/main.js
webpack的作用:根據入口文件./src/index.js 分析文件的依賴關係,然後把依賴的模塊合併成一個文件
my-main.js :
//合併兩個模塊
// ./src/a.js
// ./src/index.js
(function (modules) {
var moduleExports = {}; //用於緩存模塊的導出結果
//require函數相當於是運行一個模塊,得到模塊導出結果
function __webpack_require(moduleId) { //moduleId就是模塊的路徑
if (moduleExports[moduleId]) {
//檢查是否有緩存
return moduleExports[moduleId];
}
var func = modules[moduleId]; //得到該模塊對應的函數
var module = {
exports: {}
}
func(module, module.exports, __webpack_require); //運行模塊
var result = module.exports; //得到模塊導出的結果
moduleExports[moduleId] = result; //緩存起來
return result;
}
//執行入口模塊
return __webpack_require("./src/index.js"); //require函數相當於是運行一個模塊,得到模塊導出結果
})({ //該對象保存了所有的模塊,以及模塊對應的代碼
"./src/a.js": function (module, exports) {
eval("console.log(\"module a\")\nmodule.exports = \"a\";\n //# sourceURL=webpack:///./src/a.js")
},
"./src/index.js": function (module, exports, __webpack_require) {
eval("console.log(\"index module\")\nvar a = __webpack_require(\"./src/a.js\")\na.abc();\nconsole.log(a)\n //# sourceURL=webpack:///./src/index.js")
}
});
3、手寫思路
合併./src/index.js
和 ./src/a.js
兩個模塊,合併的結果裏就是原始的js代碼
,不存在任何模塊化的內容
---------------step1-----------------------------------------
1、避免全局變量污染,避免模塊化代碼(module,exports,require
)找不到
問題:
- 合併前的模塊化代碼(
module,exports,require
)怎麼辦?—傳參 - 模塊化的模塊裏不會有 全局變量污染,合併後怎麼
確保也不會污染全局變量
? --模塊裏的內容放在函數裏
方案:
我們可以如下,寫成對象的模式
, 定義一個變量modules 是一個對象
,該對象保存了所有的模塊,以及模塊對應的代碼
var modules = {
"./src/a.js ": function(module,exports,require){
console.log('a 模塊');
module.exports = 'a';
},
"./src/index.js ": function(module,exports,require){
// var a = require('./a');
var a = require('./src/a.js'); //用統一的路徑書寫方式,require('./src/a.js)的時候,就找到對應的函數去執行
console.log(a);
console.log('index模塊');
},
}
模塊的路徑
作爲對象裏的屬性名
,因爲每個模塊的路徑是唯一的,所以通過這個唯一的屬性名就可以找到一個唯一的模塊對象的屬性值
可以寫成一個函數,把模塊裏的代碼放到函數環境
裏,- 在函數裏用到了
module
,在普通的js裏是沒有module的
,我們可以使用函數的參數 給傳進來(commonjs裏還可能用到exports.a =1;我們把exports
也傳進來)
這樣每一個模塊裏面的代碼就沒有污染全局變量!!!
總結:
因爲每個模塊對應一個唯一的路徑
,所以我們把路徑用作屬性名
,屬性值是函數(模塊裏的代碼放在函數裏)
./src/index.js 和 ./src/a.j
s 這兩個模塊,運行一個模塊,就相當於運行一個函數,就是執行函數裏的模塊代碼
---------------step2-----------------------------------------
2、對象modules交給立即執行函數來處理
問題3:那對象modules交給誰來處理呢? –給立即執行函數來處理
方案:我們可以寫一個立即執行函數
,因爲我們儘量的避免污染全局變量
,所以把模塊modules給立即執行函數
,來處理裏面的模塊
var modules = {
"./src/a.js ": function(){ //...}
}
(function(modules){})(modules) //把modules 給立即執行函數,來執行來處理裏面的所有模塊
問題4:var modules = {} 然後傳參給立即執行函數,會有全局變量污染
,
方案:爲了不污染全局變量,直接把modules對應的內容,作爲字面量傳
給立即執行函數
(function(modules){ })({
"./src/a.js ": function(){ //...}
}) //把modules 給立即執行函數,來執行來處理裏面的所有模塊
這樣就不會污染全局變量,同時又把模塊構建好了,所有的模塊對保存在對象裏{模塊的路徑:模塊的函數},然後把這個對象給立即執行函數
---------------step3-----------------------------------------
3、手寫執行函數,執行入口模塊
立即執行函數裏面要執行入口模塊 require('./src/index.js)
--require(’./src/a.js)就是找到./src/a.js
對應的函數去執行
require函數相當於運行一個模塊,並得到模塊的導出結果,這個require函數要自己寫
(function(modules){
function webpack_require(moduleId){ //moduleId就是模塊的路徑,爲了避免require 和node環境的require重名,改用webpack_require
var func = modules[moduleId]; //得到模塊對應的函數
var module = {
exports:{
}
}
var exports = module.exports;
func(module,exports,webpack_require); //執行模塊對應的函數,傳入參數
var result = modules.exports; //得到模塊導出的結果
return result;
}
//執行入口模塊
return __webpack_require("./src/index.js"); //require函數相當於是運行一個模塊,得到模塊導出結果
})({
"./src/a.js ": function(){ //...}
}) //把modules 給立即執行函數,來執行來處理裏面的所有模塊
---------------step4-----------------------------------------
4、加載模塊緩存問題
問題:加載模塊緩存問題?就是一個模塊加載了多次怎麼辦?
(function(modules){
var moduleExports = {
// "./src/a.js":'a' //這種方式緩存結果
};//1-----------------用於緩存模塊的導出結果
function webpack_require(moduleId){ //moduleId就是模塊的路徑,爲了避免require 和node環境的require重名,改用webpack_require
if(moduleExports[moduleId]){
//2-------------- 檢查是否有緩存
return moduleExports[moduleId];
}
//3-----------如果沒有
var func = modules[modules]; //得到模塊對應的函數
var module = {
exports:{
}
}
var exports = module.exports;
func(module,exports,webpack_require); //執行模塊對應的函數,傳入參數
var result = modules.exports; //得到模塊導出的結果
moduleExports[moduleId] = result; //4-----------緩存結果
return result;
}
//執行入口模塊
return __webpack_require("./src/index.js"); //require函數相當於是運行一個模塊,得到模塊導出結果
})({
"./src/a.js ": function(module,exports,require){
console.log('a 模塊');
module.exports = 'a';
},
"./src/index.js ": function(module,exports,require){
var a = require('./src/a.js');
console.log(a);
console.log('index模塊');
},
})
---------------step5-----------------------------------------
5、模塊裏的代碼放到eval()裏,方便調試
問題:爲什麼模塊合併後,把模塊裏的代碼放到對應函數裏的eval()
裏面?
這和瀏覽器有關,最終運行的是合併後的代碼,如果報錯了只能指示到打包文件裏,爲了更好的調試,查找報錯位置,放在eval()裏。
eval()裏的代碼是放到另一個環境執行的,如果報錯,就看不到其他代碼的干擾了
"./src/a.js": function (module, exports) {
eval("console.log(\"module a\")\nmodule.exports = \"a\";\n //# sourceURL=webpack:///./src/a.js")
},
//# sourceURL= webpack:///./src/a.js
告訴瀏覽器觸發調試的時候,顯示的錯誤位置路徑是./src/a.js