<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【W(wǎng)ebpack】878- 你的 import 被 webpack 編譯成了什么?

          共 12437字,需瀏覽 25分鐘

           ·

          2021-02-23 12:35

          • 本文作者:李永寧

          • 本文鏈接:https://juejin.cn/post/6859569958742196237


          某大廠面試題

          面試官,問:

          import moduleName from 'xxModule'import('xxModule')經(jīng)過webpack編譯打包后最終變成了什么?在瀏覽器中是怎么運(yùn)行的?

          求職者,答:

          嗯。。。,不好意思,我只知道import可以用來加載模塊,然后第二個(gè)import一般用在需要懶加載的地方,其它的就不知道了

          這兩個(gè)語句我們應(yīng)該經(jīng)常能看到,第一個(gè)import就不用說了,可以說現(xiàn)在的前端項(xiàng)目隨處可見,第二個(gè)import可以在需要懶加載的地方看到,比如vue-router的懶加載配置,但是大家好像卻從來都沒太深究過這個(gè)東西。

          前奏

          importes module提供的一個(gè)加載模塊的方法,目前主流的瀏覽器也都支持,像現(xiàn)在比較火的vite就是利用了瀏覽器原生支持import的能力來實(shí)現(xiàn)的,當(dāng)然它還有一個(gè)server端使用koa實(shí)現(xiàn)的。

          我們都知道webpack的打包過程大概流程是這樣的:

          • 合并webpack.config.js和命令行傳遞的參數(shù),形成最終的配置
          • 解析配置,得到entry入口
          • 讀取入口文件內(nèi)容,通過@babel/parse將入口內(nèi)容(code)轉(zhuǎn)換成ast
          • 通過@babel/traverse遍歷ast得到模塊的各個(gè)依賴
          • 通過@babel/core(實(shí)際的轉(zhuǎn)換工作是由@babel/preset-env來完成的)將ast轉(zhuǎn)換成es5 code
          • 通過循環(huán)偽遞歸的方式拿到所有模塊的所有依賴并都轉(zhuǎn)換成es5

          從以上內(nèi)容可以看出來,最終的代碼中肯定是沒有import語句的,因?yàn)?code style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">es5就沒有import;那么我們從哪去找答案呢?有兩個(gè)地方,一是webpack源碼,二是打包后的文件,對于今天的問題而言,后者更簡單直接一些。

          項(xiàng)目

          現(xiàn)在我們來建一個(gè)測試項(xiàng)目

          初始化項(xiàng)目

          mkdir?webpack-bundle-analysis?&&?cd?webpack-bundle-analysis?&&?npm?init?-y?&&?npm?i?webpack?webpack-cli?-D

          webpack.config.js

          const?path?=?require('path')

          module.exports?=?{
          ??entry:?'./src/index.js',
          ??//?為了利于分析打包后的代碼,這里選擇開發(fā)模式
          ??mode:?'development',
          ??output:?{
          ????path:?path.resolve(__dirname,?'./dist'),
          ????filename:?'main.js'
          ??}
          }

          寫代碼,/src

          /src/index.js

          /**
          ?*?入口文件,引入?print?方法,并執(zhí)行
          ?*?定義了一個(gè)?button?方法,為頁面添加一個(gè)按鈕,并為按鈕設(shè)置了一個(gè)?onclick?事件,負(fù)責(zé)動(dòng)態(tài)引入一個(gè)文件
          ?*/

          import?{?print?}?from?'./num.js'

          print()

          function?button?()?{
          ??const?button?=?document.createElement('button')
          ??const?text?=?document.createTextNode('click?me')
          ??button.appendChild(text)
          ??button.onclick?=?e?=>?import('./info.js').then(res?=>?{
          ????console.log(res.log)
          ??})
          ??return?button
          }

          document.body.appendChild(button())

          /src/num.js

          import?{?tmpPrint?}?from?'./tmp.js'
          export?function?print?()?{
          ??tmpPrint()?
          ??console.log('我是?num.js?的?print?方法')
          }

          /src/tmp.js

          export?function?tmpPrint?()?{
          ??console.log('tmp.js?print')
          }

          /src/info.js

          export?const?log?=?"log?info"

          打包

          項(xiàng)目根目錄執(zhí)行

          npx?webpack

          會(huì)看到多了一個(gè) dist 目錄,且看輸出結(jié)果,main.js大家肯定都知道是什么,這個(gè)是我們在webpack.config.js中配置的輸出的文件名,但是0.main.js呢?這是什么?我們也沒配置,可以先想一下,之后我們從代碼中找答案

          模版文件

          新建/dist/index.html文件,并引入打包后的main.js


          <html?lang="en">
          <head>
          ??<meta?charset="UTF-8">
          ??<meta?name="viewport"?content="width=device-width,?initial-scale=1.0">
          ??<title>Documenttitle>
          head>
          <body>
          ??<script?src?=?"./main.js">script>
          body>
          html>

          在瀏覽器打開 index.html

          Network

          Console

          Elements

          可以看到index.html加載以后資源加載以及代碼的執(zhí)行情況,會(huì)發(fā)現(xiàn)我們寫的代碼中的同步邏輯均已執(zhí)行,接下來看看異步邏輯(點(diǎn)擊按鈕),這里為了效果,點(diǎn)擊之前分別清空了NetworkConsole兩個(gè)標(biāo)簽的內(nèi)容

          Network

          Console

          Elements

          大家注意看信息,點(diǎn)擊按鈕以后發(fā)生了什么?從表面看似乎是這樣的:

          點(diǎn)擊按鈕,在html中動(dòng)態(tài)添加了一個(gè)script標(biāo)簽,引入了一個(gè)文件(0.main.js),然后發(fā)送兩個(gè)一個(gè)http請求進(jìn)行資源加載,加載成功以后在控制臺(tái)輸出一段日志。

          到這里其實(shí)有一部分的答案已經(jīng)出來,import('xxModule),它提供了一種懶加載的機(jī)制,動(dòng)態(tài)往html中添加script`標(biāo)簽,然后加載資源并執(zhí)行,那具體是怎么做的呢?

          好了,現(xiàn)象我們也看完了,接下來我們?nèi)ピ创a中找答案

          源碼分析

          我們一步一步來拆解打包后的代碼

          首先,我們將打包后的代碼進(jìn)行折疊,如下

          (function?(modules)?{
          ??//?xxxx
          })({
          ??//?xxx
          })

          這段代碼是不是很熟悉?就是一個(gè)自執(zhí)行函數(shù)

          函數(shù)參數(shù)

          (function?(modules)?{
          ??//?xxxx
          })({
          ????//?src/index.js?模塊
          ????"./src/index.js":
          ??????(function?(module,?__webpack_exports__,?__webpack_require__)?{
          ????????"use?strict";
          ????????__webpack_require__.r(__webpack_exports__);
          ????????var?_num_js__WEBPACK_IMPORTED_MODULE_0__?=?__webpack_require__("./src/num.js");
          ????????Object(_num_js__WEBPACK_IMPORTED_MODULE_0__["print"])()
          ????????function?button()?{
          ??????????const?button?=?document.createElement('button')
          ??????????const?text?=?document.createTextNode('click?me')
          ??????????button.appendChild(text)
          ??????????button.onclick?=?e?=>?__webpack_require__.e(0)
          ????????????.then(__webpack_require__.bind(null,?"./src/info.js"))
          ????????????.then(res?=>?{
          ??????????????console.log(res.log)
          ????????????})
          ??????????return?button
          ????????}
          ????????document.body.appendChild(button())
          ????????//#?sourceURL=webpack:///./src/index.js?");
          ??????}),

          ????//?./src/num.js?模塊
          ????"./src/num.js":
          ??????(function?(module,?__webpack_exports__,?__webpack_require__)?{
          ????????"use?strict";
          ????????__webpack_require__.r(__webpack_exports__);
          ????????__webpack_require__.d(__webpack_exports__,?"print",?function?()?{?return?print;?});
          ????????var?_tmp_js__WEBPACK_IMPORTED_MODULE_0__?=?__webpack_require__("./src/tmp.js");
          ????????function?print()?{
          ??????????Object(_tmp_js__WEBPACK_IMPORTED_MODULE_0__["tmpPrint"])()
          ??????????console.log('我是?num.js?的?print?方法')
          ????????}
          ????????//#?sourceURL=webpack:///./src/num.js?");
          ??????}),

          ????//?/src/tmp.js?模塊
          ????"./src/tmp.js":
          ??????(function?(module,?__webpack_exports__,?__webpack_require__)?{

          ????????"use?strict"
          ;
          ????????//?eval("__webpack_require__.r(__webpack_exports__);\n/*?harmony?export?(binding)?*/?__webpack_require__.d(__webpack_exports__,?\"tmpPrint\",?function()?{?return?tmpPrint;?});\nfunction?tmpPrint?()?{\n??console.log('tmp.js?print')\n}\n\n//#?sourceURL=webpack:///./src/tmp.js?");
          ????????__webpack_require__.r(__webpack_exports__);
          ????????__webpack_require__.d(
          ??????????__webpack_exports__,
          ??????????"tmpPrint",
          ??????????function?()?{
          ????????????return?tmpPrint;
          ??????????});
          ????????function?tmpPrint()?{
          ??????????console.log('tmp.js?print')
          ????????}
          ????????//#?sourceURL=webpack:///./src/tmp.js?");
          ??????})
          })

          看到這里有沒有很熟悉,再回想一下webpack的打包過程,會(huì)發(fā)現(xiàn),webpack將所有的import moduleName from 'xxModule'都變成了一個(gè)Map對象,key為文件路徑,value為一個(gè)可執(zhí)行的函數(shù),而函數(shù)內(nèi)容其實(shí)就是模塊中導(dǎo)出的內(nèi)容,當(dāng)然,模塊自己也被webpack做了一些處理,接著往下進(jìn)行。

          從打包后Map對象中能找到我們代碼中的各個(gè)模塊,以及模塊的內(nèi)容,但是也多了很多不屬于我們編寫的代碼,比如以__webpack_require__開頭的代碼,這些又是什么呢?其實(shí)是webpack自定義的一些方法,我們接著往下閱讀

          函數(shù)體

          以下內(nèi)容為打包后的完整代碼,做了一定的格式化,關(guān)鍵地方都寫了詳細(xì)的注釋,閱讀時(shí)搜索“入口位置”開始一步一步的閱讀,如果有碰到難以理解的地方可配合單步調(diào)試

          /**
          ?*?modules?=?{
          ?*??'./src/index.js':?function?()?{},
          ?*??'./src/num.js':?function?()?{},
          ?*??'./src/tmp.js':?function?()?{}
          ?*?}
          ?*/

          (function?(modules)?{?//?webpackBootstrap
          ??/**
          ???*?install?a?JSONP?callback?for?chunk?loading
          ???*?模塊加載成功,更改緩存中的模塊狀態(tài),并且執(zhí)行模塊內(nèi)容
          ???*?@param?{*}?data?=?[
          ???*??[chunkId],
          ???*??{
          ???*????'./src/info.js':?function?()?{}
          ???*??}
          ???*?]
          ???*/

          ??function?webpackJsonpCallback(data)?{
          ????var?chunkIds?=?data[0];
          ????var?moreModules?=?data[1];


          ????//?add?"moreModules"?to?the?modules?object,
          ????//?then?flag?all?"chunkIds"?as?loaded?and?fire?callback
          ????var?moduleId,?chunkId,?i?=?0,?resolves?=?[];
          ????for?(;?i???????chunkId?=?chunkIds[i];
          ??????if?(Object.prototype.hasOwnProperty.call(installedChunks,?chunkId)?&&?installedChunks[chunkId])?{
          ????????resolves.push(installedChunks[chunkId][0]);
          ??????}
          ??????//?這里將模塊的加載狀態(tài)改為了?0,表示加載完成
          ??????installedChunks[chunkId]?=?0;
          ????}
          ????for?(moduleId?in?moreModules)?{
          ??????if?(Object.prototype.hasOwnProperty.call(moreModules,?moduleId))?{
          ????????//?執(zhí)行模塊代碼
          ????????modules[moduleId]?=?moreModules[moduleId];
          ??????}
          ????}
          ????if?(parentJsonpFunction)?parentJsonpFunction(data);

          ????while?(resolves.length)?{
          ??????resolves.shift()();
          ????}

          ??};


          ??//?The?module?cache,?模塊緩存,類似于?commonJS?的?require?緩存機(jī)制,只不過這里的?key?是相對路徑
          ??var?installedModules?=?{};


          ??/**
          ???*?定義?chunk?的加載情況,比如?main?=?0?是已加載
          ???*?object?to?store?loaded?and?loading?chunks
          ???*?undefined?=?chunk?not?loaded
          ???*?null?=?chunk?preloaded/prefetched
          ???*?Promise?=?chunk?loading
          ???*?0?=?chunk?loaded
          ???*/

          ??var?installedChunks?=?{
          ????"main":?0
          ??};



          ??//?script?path?function,?返回需要?jiǎng)討B(tài)加載的?chunk?的路徑
          ??function?jsonpScriptSrc(chunkId)?{
          ????return?__webpack_require__.p?+?""?+?chunkId?+?".main.js"
          ??}

          ??/**
          ???*?The?require?function
          ???*?接收一個(gè)?moduleId,其實(shí)就是一個(gè)模塊相對路徑,然后查緩存(沒有則添加緩存),
          ???*?然后執(zhí)行模塊代碼,返回模塊運(yùn)行后的?module.exports
          ???*?一句話總結(jié)就是?加載指定模塊然后執(zhí)行,返回執(zhí)行結(jié)果(module.exports)
          ???*?
          ???*?__webpack_require__(__webpack_require__.s?=?"./src/index.js")
          ???*/

          ??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)
          ?????*?
          ?????*?//?示例
          ?????*?module?=?installedModules['./src/index.js']?=?{
          ?????*??i:?'./src/index.js',
          ?????*??l:?false,
          ?????*??exports:?{}
          ?????*?}
          ?????*/

          ????var?module?=?installedModules[moduleId]?=?{
          ??????i:?moduleId,
          ??????l:?false,
          ??????exports:?{}
          ????};

          ????/**
          ?????*?Execute?the?module?function
          ?????*?modules['./src/index.js']?is?a?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;
          ??}

          ??//?This?file?contains?only?the?entry?chunk.
          ??//?The?chunk?loading?function?for?additional?chunks
          ??/**
          ???*?
          ???*/

          ??__webpack_require__.e?=?function?requireEnsure(chunkId)?{
          ????var?promises?=?[];

          ????//?JSONP?chunk?loading?for?javascript

          ????//?從緩存中找該模塊
          ????var?installedChunkData?=?installedChunks[chunkId];
          ????
          ????//?0?means?"already?installed".
          ????if?(installedChunkData?!==?0)?{?
          ??????
          ??????//?說明模塊沒有安裝

          ??????//?a?Promise?means?"currently?loading".
          ??????if?(installedChunkData)?{
          ????????promises.push(installedChunkData[2]);
          ??????}?else?{
          ????????//?setup?Promise?in?chunk?cache
          ????????var?promise?=?new?Promise(function?(resolve,?reject)?{
          ??????????installedChunkData?=?installedChunks[chunkId]?=?[resolve,?reject];
          ????????});
          ????????promises.push(installedChunkData[2]?=?promise);

          ????????//?start?chunk?loading,?create?script?element
          ????????var?script?=?document.createElement('script');
          ????????var?onScriptComplete;

          ????????script.charset?=?'utf-8';
          ????????//?設(shè)置超時(shí)時(shí)間
          ????????script.timeout?=?120;
          ????????if?(__webpack_require__.nc)?{
          ??????????script.setAttribute("nonce",?__webpack_require__.nc);
          ????????}
          ????????//?script.src?=?__webpack_public_path__?+?chunkId?+?main.js,?即模塊路徑
          ????????script.src?=?jsonpScriptSrc(chunkId);

          ????????//?create?error?before?stack?unwound?to?get?useful?stacktrace?later
          ????????var?error?=?new?Error();

          ????????//?加載結(jié)果處理函數(shù)
          ????????onScriptComplete?=?function?(event)?{
          ??????????//?avoid?mem?leaks?in?IE.
          ??????????script.onerror?=?script.onload?=?null;
          ??????????clearTimeout(timeout);
          ??????????var?chunk?=?installedChunks[chunkId];
          ??????????if?(chunk?!==?0)?{
          ????????????//?chunk?狀態(tài)不為?0?,說明加載出問題了
          ????????????if?(chunk)?{
          ??????????????var?errorType?=?event?&&?(event.type?===?'load'???'missing'?:?event.type);
          ??????????????var?realSrc?=?event?&&?event.target?&&?event.target.src;
          ??????????????error.message?=?'Loading?chunk?'?+?chunkId?+?'?failed.\n('?+?errorType?+?':?'?+?realSrc?+?')';
          ??????????????error.name?=?'ChunkLoadError';
          ??????????????error.type?=?errorType;
          ??????????????error.request?=?realSrc;
          ??????????????chunk[1](error);
          ????????????}
          ????????????installedChunks[chunkId]?=?undefined;
          ??????????}
          ????????};
          ????????//?超時(shí)定時(shí)器,超時(shí)以后執(zhí)行
          ????????var?timeout?=?setTimeout(function?()?{
          ??????????onScriptComplete({?type:?'timeout',?target:?script?});
          ????????},?120000);
          ????????//?加載出錯(cuò)或者加載成功的處理函數(shù)
          ????????script.onerror?=?script.onload?=?onScriptComplete;
          ????????//?將?script?標(biāo)簽添加到?head?標(biāo)簽尾部
          ????????document.head.appendChild(script);
          ??????}
          ????}
          ????return?Promise.all(promises);
          ??};

          ??//?expose?the?modules?object?(__webpack_modules__)
          ??__webpack_require__.m?=?modules;

          ??//?expose?the?module?cache
          ??__webpack_require__.c?=?installedModules;

          ??/**
          ???*?define?getter?function?for?harmony?exports
          ???*?@param?{*}?exports?=?{}
          ???*?@param?{*}?name?=?模塊名
          ???*?@param?{*}?getter?=>?模塊函數(shù)
          ???*?
          ???*?在?exports?對象上定義一個(gè)?key?value,key?為模塊名稱,value?為模塊的可執(zhí)行函數(shù)
          ???*?exports?=?{
          ???*??moduleName:?module?function
          ???*?}?
          ???*/

          ??__webpack_require__.d?=?function?(exports,?name,?getter)?{
          ????if?(!__webpack_require__.o(exports,?name))?{
          ??????Object.defineProperty(exports,?name,?{?enumerable:?true,?get:?getter?});
          ????}
          ??};

          ??/**
          ???*?define?__esModule?on?exports
          ???*?@param?{*}?exports?=?{}
          ???*?
          ???*?exports?=?{
          ???*??__esModule:?true
          ???*?}
          ???*/

          ??__webpack_require__.r?=?function?(exports)?{
          ????if?(typeof?Symbol?!==?'undefined'?&&?Symbol.toStringTag)?{
          ??????Object.defineProperty(exports,?Symbol.toStringTag,?{?value:?'Module'?});
          ????}
          ????Object.defineProperty(exports,?'__esModule',?{?value:?true?});
          ??};

          ??//?create?a?fake?namespace?object
          ??//?mode?&?1:?value?is?a?module?id,?require?it
          ??//?mode?&?2:?merge?all?properties?of?value?into?the?ns
          ??//?mode?&?4:?return?value?when?already?ns?object
          ??//?mode?&?8|1:?behave?like?require
          ??__webpack_require__.t?=?function?(value,?mode)?{
          ????if?(mode?&?1)?value?=?__webpack_require__(value);
          ????if?(mode?&?8)?return?value;
          ????if?((mode?&?4)?&&?typeof?value?===?'object'?&&?value?&&?value.__esModule)?return?value;
          ????var?ns?=?Object.create(null);
          ????__webpack_require__.r(ns);
          ????Object.defineProperty(ns,?'default',?{?enumerable:?true,?value:?value?});
          ????if?(mode?&?2?&&?typeof?value?!=?'string')?for?(var?key?in?value)?__webpack_require__.d(ns,?key,?function?(key)?{?return?value[key];?}.bind(null,?key));
          ????return?ns;
          ??};

          ??//?getDefaultExport?function?for?compatibility?with?non-harmony?modules
          ??__webpack_require__.n?=?function?(module)?{
          ????var?getter?=?module?&&?module.__esModule??
          ??????function?getDefault()?{?return?module['default'];?}?:
          ??????function?getModuleExports()?{?return?module;?};
          ????__webpack_require__.d(getter,?'a',?getter);
          ????return?getter;
          ??};

          ??//?Object.prototype.hasOwnProperty.call
          ??__webpack_require__.o?=?function?(object,?property)?{?return?Object.prototype.hasOwnProperty.call(object,?property);?};

          ??//?__webpack_public_path__
          ??__webpack_require__.p?=?"";

          ??//?on?error?function?for?async?loading
          ??__webpack_require__.oe?=?function?(err)?{?console.error(err);?throw?err;?};
          ??
          ??/**
          ???*?通過全局屬性存儲(chǔ)異步加載的資源項(xiàng),打包文件首次加載時(shí)如果屬性值不為空,則說明已經(jīng)有資源被加載了,
          ???*?將這些資源同步到installedChunks對象中,避免資源重復(fù)加載,當(dāng)然也是這句導(dǎo)致微應(yīng)用框架single-spa中的所有子應(yīng)用導(dǎo)出的
          ???*?包名需要唯一,否則一旦異步的重名模塊存在,重名的后續(xù)模塊不會(huì)被加載,且顯示的資源是第一個(gè)加載的重名模塊,
          ???*?也就是所謂的JS全局作用域的污染
          ???*
          ???*?其實(shí)上面說的這個(gè)問題,webpack官網(wǎng)已經(jīng)提到了
          ???*?https://webpack.docschina.org/configuration/output/#outputjsonpfunction
          ???*/

          ??var?jsonpArray?=?window["webpackJsonp"]?=?window["webpackJsonp"]?||?[];
          ??var?oldJsonpFunction?=?jsonpArray.push.bind(jsonpArray);
          ??jsonpArray.push?=?webpackJsonpCallback;
          ??jsonpArray?=?jsonpArray.slice();
          ??for?(var?i?=?0;?i???var?parentJsonpFunction?=?oldJsonpFunction;


          ??/**
          ???*?入口位置
          ???*?Load?entry?module?and?return?exports
          ???*/

          ??return?__webpack_require__(__webpack_require__.s?=?"./src/index.js");
          })
          ??({
          ????//?代碼中所有的?import?moduleName?from?'xxModule'?變成了以下的?Map?對象

          ????//?/src/index.js?模塊
          ????"./src/index.js":
          ??????/**
          ???????*?@param?module?=?{
          ???????*??i:?'./src/index.js',
          ???????*??l:?false,
          ???????*??exports:?{}
          ???????*?
          ???????*?@param?__webpack_exports__?=?module.exports?=?{}
          ???????*?
          ???????*?@param?__webpack_require__?=>?自定義的?require?函數(shù),加載指定模塊,并執(zhí)行模塊代碼,返回執(zhí)行結(jié)果
          ???????*?
          ???????*/

          ??????(function?(module,?__webpack_exports__,?__webpack_require__)?{
          ????????"use?strict";
          ????????/**
          ?????????*?
          ?????????*?define?__esModule?on?exports
          ?????????*?__webpack_exports?=?module.exports?=?{
          ?????????*??__esModule:?true
          ?????????*?}
          ?????????*/

          ????????__webpack_require__.r(__webpack_exports__);
          ????????//?加載?./src/num.js?模塊
          ????????var?_num_js__WEBPACK_IMPORTED_MODULE_0__?=?__webpack_require__("./src/num.js");
          ????????Object(_num_js__WEBPACK_IMPORTED_MODULE_0__["print"])()
          ????????function?button()?{
          ??????????const?button?=?document.createElement('button')
          ??????????const?text?=?document.createTextNode('click?me')
          ??????????button.appendChild(text)
          ??????????/**
          ???????????*?異步執(zhí)行部分
          ???????????*/

          ??????????button.onclick?=?e?=>?__webpack_require__.e(0)
          ????????????//?模塊異步加載完成后,開始執(zhí)行模塊內(nèi)容?=>?window["webpackJsonp"].push?=?window["webpackJsonp"].push?=?function?(data)?{}
          ????????????.then(__webpack_require__.bind(null,?"./src/info.js"))
          ????????????.then(res?=>?{
          ??????????????console.log(res.log)
          ????????????})
          ??????????return?button
          ????????}
          ????????document.body.appendChild(button())
          ????????//#?sourceURL=webpack:///./src/index.js?");
          ??????}),

          ????//?/src/num.js?模塊
          ????"./src/num.js":
          ???????/**
          ???????*?@param?module?=?{
          ???????*??i:?'./src/num.js',
          ???????*??l:?false,
          ???????*??exports:?{}
          ???????*?
          ???????*?@param?__webpack_exports__?=?module.exports?=?{}
          ???????*?
          ???????*?@param?__webpack_require__?=>?自定義的?require?函數(shù),加載指定模塊,并執(zhí)行模塊代碼,返回執(zhí)行結(jié)果
          ???????*?
          ???????*/

          ??????(function?(module,?__webpack_exports__,?__webpack_require__)?{
          ????????"use?strict";
          ?????????/**
          ?????????*?
          ?????????*?define?__esModule?on?exports
          ?????????*?__webpack_exports?=?module.exports?=?{
          ?????????*??__esModule:?true
          ?????????*?}
          ?????????*/

          ????????__webpack_require__.r(__webpack_exports__);
          ????????/**
          ?????????*?module.exports?=?{
          ?????????*??__esModule:?true,
          ?????????*??print
          ?????????*?}
          ?????????*/

          ????????__webpack_require__.d(__webpack_exports__,?"print",?function?()?{?return?print;?});
          ????????//?加載?./src/tmp.js?模塊
          ????????var?_tmp_js__WEBPACK_IMPORTED_MODULE_0__?=?__webpack_require__("./src/tmp.js");
          ????????function?print()?{
          ??????????Object(_tmp_js__WEBPACK_IMPORTED_MODULE_0__["tmpPrint"])()
          ??????????console.log('我是?num.js?的?print?方法')
          ????????}
          ????????//#?sourceURL=webpack:///./src/num.js?");
          ??????}),

          ????//?/src/tmp.js?模塊
          ????"./src/tmp.js":
          ??????/**
          ???????*?@param?module?=?{
          ???????*??i:?'./src/num.js',
          ???????*??l:?false,
          ???????*??exports:?{}
          ???????*?
          ???????*?@param?__webpack_exports__?=?module.exports?=?{}
          ???????*?
          ???????*?@param?__webpack_require__?=>?自定義的?require?函數(shù),加載指定模塊,并執(zhí)行模塊代碼,返回執(zhí)行結(jié)果
          ???????*?
          ???????*/

          ??????(function?(module,?__webpack_exports__,?__webpack_require__)?{

          ????????"use?strict"
          ;
          ?????????/**
          ?????????*?
          ?????????*?define?__esModule?on?exports
          ?????????*?__webpack_exports?=?module.exports?=?{
          ?????????*??__esModule:?true
          ?????????*?}
          ?????????*/

          ????????__webpack_require__.r(__webpack_exports__);
          ????????/**
          ?????????*?module.exports?=?{
          ?????????*??__esModule:?true,
          ?????????*??tmpPrint
          ?????????*?}
          ?????????*/

          ????????__webpack_require__.d(__webpack_exports__,?"tmpPrint",?function?()?{?return?tmpPrint;?});
          ????????function?tmpPrint()?{
          ??????????console.log('tmp.js?print')
          ????????}
          ????????//#?sourceURL=webpack:///./src/tmp.js?");
          ??????})
          ??});

          總結(jié)

          經(jīng)過以上內(nèi)容的學(xué)習(xí),相比對于一開始的問題,答案呼之欲出了吧。

          面試官,問:

          import moduleName from 'xxModule'import('xxModule')經(jīng)過webpack編譯打包后最終變成了什么?在瀏覽器中是怎么運(yùn)行的?

          求職者,答:

          import經(jīng)過webpack打包以后變成一些Map對象,key為模塊路徑,value為模塊的可執(zhí)行函數(shù);

          代碼加載到瀏覽器以后從入口模塊開始執(zhí)行,其中執(zhí)行的過程中,最重要的就是webpack定義的__webpack_require__函數(shù),負(fù)責(zé)實(shí)際的模塊加載并執(zhí)行這些模塊內(nèi)容,返回執(zhí)行結(jié)果,其實(shí)就是讀取Map對象,然后執(zhí)行相應(yīng)的函數(shù);

          當(dāng)然其中的異步方法(import('xxModule'))比較特殊一些,它會(huì)單獨(dú)打成一個(gè)包,采用動(dòng)態(tài)加載的方式,具體過程:當(dāng)用戶觸發(fā)其加載的動(dòng)作時(shí),會(huì)動(dòng)態(tài)的在head標(biāo)簽中創(chuàng)建一個(gè)script標(biāo)簽,然后發(fā)送一個(gè)http請求,加載模塊,模塊加載完成以后自動(dòng)執(zhí)行其中的代碼,主要的工作有兩個(gè),更改緩存中模塊的狀態(tài),另一個(gè)就是執(zhí)行模塊代碼。


          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計(jì)模式 重溫系列(9篇全)
          4.?正則 / 框架 / 算法等 重溫系列(16篇全)
          5.?Webpack4 入門(上)||?Webpack4 入門(下)
          6.?MobX 入門(上)?||??MobX 入門(下)
          7. 100+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

          點(diǎn)擊“閱讀原文”查看 100+ 篇原創(chuàng)文章

          瀏覽 39
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩三级片一二三区 | 91五月丁香网站 | 亚洲欧美专区 | 天天天天射天天天搞天天要 | 一级片免费观看 |