webpack中import實現(xiàn)過程

webpack基本原理可參考webpack系列之一總覽,本文是對import方法的補充钢悲。

示例源碼

示例結(jié)構(gòu)
// package.json
{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^2.30.0",
    "webpack": "^3.8.1"
  }
}

// webpack.config.js
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
    // mode: 'production',
    //配置入口文件点额,入口文件可以以對象的形式配置舔株,也可以以數(shù)組的形式配置,后綴名可以省略
    /*
     * 對象形式配置入口
     * */
    entry:{
        index:'./main'       //'./index.js'
    },
    /*
     * 數(shù)組形式配置入口
     * */
    //entry: [
    //    './main.js'
    //],
    //輸出文件出口
    output: {
        /*
         輸出路徑,在這我們要手動創(chuàng)建一個文件夾还棱,名字可以自己命名载慈,
         輸出的文件路徑是相對于本文件的路徑
         * */
        path: path.resolve(__dirname, './dist'),  //輸出路徑
        // publicPath: '/dist/',
        filename: '[name].bundle.js'     //輸出文件名,文件可以自己定義珍手,[name]的意思是與入口文件的文件對應(yīng)办铡,可以不用[name],
    },
    resolve: {
        extensions: ['.js']
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: "index.html",
            inject: "body"
        })
    ]
}
// c.js
export default {
  key: 'something'
}
// main.js
  import('./c').then(test => {
    console.log('??? ', test)
})

分析

以上代碼琳要,執(zhí)行npm run build后寡具,輸出的js文件有兩個:index.bundle.js0.bundle.js,其中index.bundle.js首先插入script中執(zhí)行稚补,0.bunlde.js是動態(tài)引入的童叠,其內(nèi)容如下,主要包裹了c.js

0.bunlde.js

index.bundle.js是一個立即執(zhí)行函數(shù)课幕,入?yún)⑷缦聢D厦坛,主要包裹著main.js的內(nèi)容,其中會動態(tài)引入0.bundle.js(包裹著c.js這個module):
index.bundle.js

  • 如上圖乍惊,153行的webpack_require.e會返回promise杜秸,其實現(xiàn)如下:
__webpack_require__.e = function requireEnsure(chunkId) {
/******/        var installedChunkData = installedChunks[chunkId];
/******/        if(installedChunkData === 0) {
/******/            return new Promise(function(resolve) { resolve(); });
/******/        }
/******/
/******/        // a Promise means "currently loading".
/******/        if(installedChunkData) {
/******/            return installedChunkData[2];
/******/        }
/******/
/******/        // setup Promise in chunk cache
/******/        var promise = new Promise(function(resolve, reject) {
/******/            installedChunkData = installedChunks[chunkId] = [resolve, reject]; // 此處把resove和reject保存到installedChunkData備用
/******/        });
/******/        installedChunkData[2] = promise;
/******/
/******/        // start chunk loading
/******/        var head = document.getElementsByTagName('head')[0];
/******/        var script = document.createElement('script');
/******/        script.type = "text/javascript";
/******/        script.charset = 'utf-8';
/******/        script.async = true;
/******/        script.timeout = 120000;
/******/
/******/        if (__webpack_require__.nc) {
/******/            script.setAttribute("nonce", __webpack_require__.nc);
/******/        }
/******/        script.src = __webpack_require__.p + "" + chunkId + ".bundle.js";
/******/        var timeout = setTimeout(onScriptComplete, 120000);
/******/        script.onerror = script.onload = onScriptComplete;
/******/        function onScriptComplete() { // 該方法用于檢測動態(tài)加載js后的一些檢測
/******/            // avoid mem leaks in IE.
/******/            script.onerror = script.onload = null;
/******/            clearTimeout(timeout);
/******/            var chunk = installedChunks[chunkId];
/******/            if(chunk !== 0) {
/******/                if(chunk) {
/******/                    chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
/******/                }
/******/                installedChunks[chunkId] = undefined;
/******/            }
/******/        };
/******/        head.appendChild(script); // 往頁面中動態(tài)加入0.bundle.js
/******/
/******/        return promise; // 返回promise
/******/    };
  • 在上面的代碼中,0.bundle.js插入script后润绎,運行代碼撬碟,會調(diào)用webpackJsonp方法,如下圖:
    0.bundle.js - webpackJsonp

    webpackJsonp在index.bundle.js中定義:
/******/    window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
/******/        // add "moreModules" to the modules object,
/******/        // then flag all "chunkIds" as loaded and fire callback
/******/        var moduleId, chunkId, i = 0, resolves = [], result;
/******/        for(;i < chunkIds.length; i++) {
/******/            chunkId = chunkIds[i];
/******/            if(installedChunks[chunkId]) {
/******/                resolves.push(installedChunks[chunkId][0]);
/******/            }
/******/            installedChunks[chunkId] = 0;
/******/        }
/******/        for(moduleId in moreModules) {
/******/            if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
/******/                modules[moduleId] = moreModules[moduleId];
/******/            }
/******/        }
/******/        if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
/******/        while(resolves.length) {
/******/            resolves.shift()(); // 第一個元素是resolve莉撇,相當(dāng)于執(zhí)行resolve()呢蛤,觸發(fā)then方法(詳見下一步)
/******/        }
/******/
/******/    };

其中關(guān)鍵是resolves.shift()(),resolves.shift()返回的是resolve稼钩,該句相當(dāng)于執(zhí)行resolve()顾稀,觸發(fā)then方法(詳見下一步)

  • 執(zhí)行完webpack_require.e(0)之后达罗,進入then方法(上一步的resolves.shift()()觸發(fā))坝撑,執(zhí)行webpack_require.bind(null, 1),其中1表示的是0.bundle.js中第二個入?yún)?shù)組的第二個元素(下標(biāo)為1)粮揉,即c.js這個module巡李。webpack_require實現(xiàn)如下:
/******/    function __webpack_require__(moduleId) {
/******/
/******/        // Check if module is in cache
/******/        if(installedModules[moduleId]) {
/******/            return installedModules[moduleId].exports;
/******/        }
/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            i: moduleId,
/******/            l: false,
/******/            exports: {}
/******/        };
/******/
/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/        // Flag the module as loaded
/******/        module.l = true;
/******/
/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }

modules[moduleId]表示的就是c.js module,那么modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);相當(dāng)于就是把c.js中export default內(nèi)容賦給module.exports扶认,執(zhí)行webpack_require侨拦,就相當(dāng)于獲取到了該module.exports

  • 回到index.bunlde.js第153行代碼:
  __webpack_require__.e/* import() */(0).then(__webpack_require__.bind(null, 1)).then(test => {
    console.log('??? ', test)
})

__webpack_require__.bind(null, 1)返回的是函數(shù)辐宾,該函數(shù)執(zhí)行后的結(jié)果(即上一步分析的module.exports)會傳給下一個then方法狱从。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末膨蛮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子季研,更是在濱河造成了極大的恐慌敞葛,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件与涡,死亡現(xiàn)場離奇詭異惹谐,居然都是意外死亡,警方通過查閱死者的電腦和手機驼卖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門氨肌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酌畜,你說我怎么就攤上這事怎囚。” “怎么了檩奠?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵桩了,是天一觀的道長。 經(jīng)常有香客問我埠戳,道長井誉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任整胃,我火速辦了婚禮颗圣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屁使。我一直安慰自己在岂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布蛮寂。 她就那樣靜靜地躺著蔽午,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酬蹋。 梳的紋絲不亂的頭發(fā)上及老,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音范抓,去河邊找鬼骄恶。 笑死,一個胖子當(dāng)著我的面吹牛匕垫,可吹牛的內(nèi)容都是我干的僧鲁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼寞秃!你這毒婦竟也來了斟叼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤春寿,失蹤者是張志新(化名)和其女友劉穎犁柜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堂淡,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡馋缅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绢淀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萤悴。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖皆的,靈堂內(nèi)的尸體忽然破棺而出覆履,到底是詐尸還是另有隱情,我是刑警寧澤费薄,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布硝全,位于F島的核電站,受9級特大地震影響楞抡,放射性物質(zhì)發(fā)生泄漏伟众。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一召廷、第九天 我趴在偏房一處隱蔽的房頂上張望凳厢。 院中可真熱鬧,春花似錦竞慢、人聲如沸先紫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遮精。三九已至,卻和暖如春败潦,著一層夾襖步出監(jiān)牢的瞬間本冲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工变屁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留眼俊,地道東北人意狠。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓粟关,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闷板,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容