/******/     // 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].call(module.exports, module, module.exports, __webpack_require__);/******/   /******/     // Return the exports of the module/******/     return module.exports;/******/   }/******/   /******/   // expose the modules object (__webpack_modules__)/******/   __webpack_require__.m = __webpack_modules__;/******/   /************************************************************************//******/   /* webpack/runtime/create fake namespace object *//******/   (() => {/******/     var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);/******/     var leafPrototypes;/******/     // 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 & 16: return value when it's Promise-like/******/     // mode & 8|1: behave like require/******/     __webpack_require__.t = function(value, mode) {/******/       if(mode & 1) value = this(value);/******/       if(mode & 8) return value;/******/       if(typeof value === 'object' && value) {/******/         if((mode & 4) && value.__esModule) return value;/******/         if((mode & 16) && typeof value.then === 'function') return value;/******/       }/******/       var ns = Object.create(null);/******/       __webpack_require__.r(ns);/******/       var def = {};/******/       leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];/******/       for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {/******/         Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key])));/******/       }/******/       def['default'] = () => (value);/******/       __webpack_require__.d(ns, def);/******/       return ns;/******/     };/******/   })();/******/   /******/   /* webpack/runtime/define property getters *//******/   (() => {/******/     // define getter functions for harmony exports/******/     __webpack_require__.d = (exports, definition) => {/******/       for(var key in definition) {/******/         if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {/******/           Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });/******/         }/******/       }/******/     };/******/   })();/******/   /******/   /* webpack/runtime/ensure chunk *//******/   (() => {/******/     __webpack_require__.f = {};/******/     // This file contains only the entry chunk./******/     // The chunk loading function for additional chunks/******/     __webpack_require__.e = (chunkId) => {/******/       return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {/******/         __webpack_require__.f[key](chunkId, promises);/******/         return promises;/******/       }, []));/******/     };/******/   })();/******/   /******/   /* webpack/runtime/get javascript chunk filename *//******/   (() => {/******/     // This function allow to reference async chunks/******/     __webpack_require__.u = (chunkId) => {/******/       // return url for filenames based on template/******/       return "" + chunkId + ".bundle.js";/******/     };/******/   })();/******/   /******/   /* webpack/runtime/global *//******/   (() => {/******/     __webpack_require__.g = (function() {/******/       if (typeof globalThis === 'object') return globalThis;/******/       try {/******/         return this || new Function('return this')();/******/       } catch (e) {/******/         if (typeof window === 'object') return window;/******/       }/******/     })();/******/   })();/******/   /******/   /* webpack/runtime/hasOwnProperty shorthand *//******/   (() => {/******/     __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))/******/   })();/******/   /******/   /* webpack/runtime/load script *//******/   (() => {/******/     var inProgress = {};/******/     var dataWebpackPrefix = "webpack-demo:";/******/     // loadScript function to load a script via script tag/******/     __webpack_require__.l = (url, done, key, chunkId) => {/******/       if(inProgress[url]) { inProgress[url].push(done); return; }/******/       var script, needAttach;/******/       if(key !== undefined) {/******/         var scripts = document.getElementsByTagName("script");/******/         for(var i = 0; i < scripts.length; i++) {/******/           var s = scripts[i];/******/           if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }/******/         }/******/       }/******/       if(!script) {/******/         needAttach = true;/******/         script = document.createElement('script');/******/     /******/         script.charset = 'utf-8';/******/         script.timeout = 120;/******/         if (__webpack_require__.nc) {/******/           script.setAttribute("nonce", __webpack_require__.nc);/******/         }/******/         script.setAttribute("data-webpack", dataWebpackPrefix + key);/******/         script.src = url;/******/       }/******/       inProgress[url] = [done];/******/       var onScriptComplete = (prev, event) => {/******/         // avoid mem leaks in IE./******/         script.onerror = script.onload = null;/******/         clearTimeout(timeout);/******/         var doneFns = inProgress[url];/******/         delete inProgress[url];/******/         script.parentNode && script.parentNode.removeChild(script);/******/         doneFns && doneFns.forEach((fn) => (fn(event)));/******/         if(prev) return prev(event);/******/       }/******/       ;/******/       var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);/******/       script.onerror = onScriptComplete.bind(null, script.onerror);/******/       script.onload = onScriptComplete.bind(null, script.onload);/******/       needAttach && document.head.appendChild(script);/******/     };/******/   })();/******/   /******/   /* webpack/runtime/make namespace object *//******/   (() => {/******/     // define __esModule on exports/******/     __webpack_require__.r = (exports) => {/******/       if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {/******/         Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });/******/       }/******/       Object.defineProperty(exports, '__esModule', { value: true });/******/     };/******/   })();/******/   /******/   /* webpack/runtime/publicPath *//******/   (() => {/******/     var scriptUrl;/******/     if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";/******/     var document = __webpack_require__.g.document;/******/     if (!scriptUrl && document) {/******/       if (document.currentScript)/******/         scriptUrl = document.currentScript.src/******/       if (!scriptUrl) {/******/         var scripts = document.getElementsByTagName("script");/******/         if(scripts.length) scriptUrl = scripts[scripts.length - 1].src/******/       }/******/     }/******/     // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration/******/     // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic./******/     if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");/******/     scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");/******/     __webpack_require__.p = scriptUrl;/******/   })();/******/   /******/   /* webpack/runtime/jsonp chunk loading *//******/   (() => {/******/     // no baseURI/******/     /******/     // object to store loaded and loading chunks/******/     // undefined = chunk not loaded, null = chunk preloaded/prefetched/******/     // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded/******/     var installedChunks = {/******/       "main": 0/******/     };/******/     /******/     __webpack_require__.f.j = (chunkId, promises) => {/******/         // JSONP chunk loading for javascript/******/         var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;/******/         if(installedChunkData !== 0) { // 0 means "already installed"./******/     /******/           // a Promise means "currently loading"./******/           if(installedChunkData) {/******/             promises.push(installedChunkData[2]);/******/           } else {/******/             if(true) { // all chunks have JS/******/               // setup Promise in chunk cache/******/               var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));/******/               promises.push(installedChunkData[2] = promise);/******/     /******/               // start chunk loading/******/               var url = __webpack_require__.p + __webpack_require__.u(chunkId);/******/               // create error before stack unwound to get useful stacktrace later/******/               var error = new Error();/******/               var loadingEnded = (event) => {/******/                 if(__webpack_require__.o(installedChunks, chunkId)) {/******/                   installedChunkData = installedChunks[chunkId];/******/                   if(installedChunkData !== 0) installedChunks[chunkId] = undefined;/******/                   if(installedChunkData) {/******/                     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;/******/                     installedChunkData[1](error);/******/                   }/******/                 }/******/               };/******/               __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);/******/             } else installedChunks[chunkId] = 0;/******/           }/******/         }/******/     };/******/     /******/     // no prefetching/******/     /******/     // no preloaded/******/     /******/     // no HMR/******/     /******/     // no HMR manifest/******/     /******/     // no on chunks loaded/******/     /******/     // install a JSONP callback for chunk loading/******/     var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {/******/       var [chunkIds, moreModules, runtime] = data;/******/       // add "moreModules" to the modules object,/******/       // then flag all "chunkIds" as loaded and fire callback/******/       var moduleId, chunkId, i = 0;/******/       if(chunkIds.some((id) => (installedChunks[id] !== 0))) {/******/         for(moduleId in moreModules) {/******/           if(__webpack_require__.o(moreModules, moduleId)) {/******/             __webpack_require__.m[moduleId] = moreModules[moduleId];/******/           }/******/         }/******/         if(runtime) var result = runtime(__webpack_require__);/******/       }/******/       if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);/******/       for(;i < chunkIds.length; i++) {/******/         chunkId = chunkIds[i];/******/         if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {/******/           installedChunks[chunkId][0]();/******/         }/******/         installedChunks[chunkId] = 0;/******/       }/******/     /******/     }/******/     /******/     var chunkLoadingGlobal = self["webpackChunkwebpack_demo"] = self["webpackChunkwebpack_demo"] || [];/******/     chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));/******/     chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));/******/   })();/******/   /************************************************************************/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 ***!  \******************/__webpack_require__.r(__webpack_exports__);/* harmony import */ var _static__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./static */ "./static.js");

console.log(`parseInt is: ${(0,_static__WEBPACK_IMPORTED_MODULE_0__["default"])(3.1415)}`);
__webpack_require__.e(/*! import() */ "cjs_js").then(__webpack_require__.t.bind(__webpack_require__, /*! ./cjs.js */ "./cjs.js", 23)).then((module)=>{ const sum = module.add(1, 2);
console.log(`sum is: ${sum}`);})
__webpack_require__.e(/*! import() */ "es6_js").then(__webpack_require__.bind(__webpack_require__, /*! ./es6.js */ "./es6.js")).then((module)=>{ const square = module.default(4);
console.log(`square is: ${square}`);})
__webpack_require__.e(/*! import() */ "cmd_js").then(__webpack_require__.t.bind(__webpack_require__, /*! ./cmd.js */ "./cmd.js", 23)).then((module)=>{ const max = module.max(4, 8);
console.log(`max is: ${max}`);})

__webpack_require__.e(/*! import() */ "amd_js").then(__webpack_require__.t.bind(__webpack_require__, /*! ./amd.js */ "./amd.js", 23)).then((module)=>{ const floor = module.floor(4.3);
console.log(`floor is: ${floor}`);})

__webpack_require__.e(/*! import() */ "umd_js").then(__webpack_require__.t.bind(__webpack_require__, /*! ./umd.js */ "./umd.js", 23)).then((module)=>{ const round = module.round(4.5);
console.log(`round is: ${round}`);})

})();
/******/ })();


Webpack 的编译产物看上去有点奇葩

让我们来仔细捋一捋

梳理一下脉络

图片


bundle 整体由一个 IIFE(webpackBootstrap) 包裹,主要包含:

  • __webpack_modules__ 对象,包含了除入口外的所有模块。

    • 注1:源码入口模块中,以静态方式引入的模块,会被直接编译到这里。

    • 注2:源码入口模块中,以动态方式引入的模块,会在运行时按需被添加到这个对象中。

图片

  • __webpack_module_cache__ 对象,存储的是已经被引用(初始化)过的模块。

    • 注:同一个模块被引入多次,但只会被初始化一次。

图片

  • __webpack_require__ 函数,实现模块引用(require) 逻辑

图片

  • __webpack_require__.r ,ES模块工具函数,用于标记某模块是一个 ES 模块

图片

  • __webpack_require__.d ,ES模块工具函数,用于转换ES模块导出的内容;

图片

图片

图片

  • __webpack_require__.o,工具函数,本质就是hasOwnProperty,用于判定对象自身属性中是否具有指定的属性。

图片


上面这几个函数和对象

构成了 Webpack 运行时的“基本特性

—— 模块化 ——


下面这几个函数和对象则

构成了 Webpack 运行时的“高级特性

—— 异步模块的加载、运行能力 ——

  • __webpack_require__.e :是异步模块(chunk)加载功能的入口。

    • 注:__webpack_require__.e 采用了中间件模式。

    • 注:所有需要注册给 __webpack_require__.e 的中间件,都需要注册到 __webpack_require__.f 对象中。

      • 注:__webpack_require__.f.j 则是实现了异步模块(chunk )路径拼接、缓存、异常处理功能的一个中间件。

图片

图片

  • __webpack_require__.l :基于 JSONP 的异步模块(chunk )加载与执行函数

  • __webpack_require__.u :用于拼接异步模块名称的函数

图片

图片

  • __webpack_require__.g:工具函数,获取全局对象。

图片

  • __webpack_require__.p :存储的是自动获取的 publicPath,用于后续加载 chunk 时计算完整 URL 使用。

图片


异步模块是被下载后如何与 

__webpack_modules__、installedChunks 

联动的呢?


  • chunkLoadingGlobal:每一个被下载异步模块(chunk)都会把自己存储到(push)一个全局数组中。

图片

  • 但是chunkLoadingGlobal.push 这个动作被函数 webpackJsonpCallback 劫持(替换了)了,需要先完成与 installedChunks、__webpack_modules__ 的联动,然后才会被存储到 chunkLoadingGlobal 数组中。

图片



4. 扩展阅读

4.1. ES 模块比 CJS 更好吗?

ES modules are an official standard and the clear path forward for JavaScript code structure, whereas CommonJS modules are an idiosyncratic legacy format that served as a stopgap solution before ES modules had been proposed. ES modules allow static analysis that helps with optimizations like tree-shaking and scope-hoisting, and provide advanced features like circular references and live bindings.


4.2. 什么是 "tree-shaking"?

Tree-shaking, also known as "live code inclusion", is a process of eliminating code that is not actually used in a given project. It is a form of dead code elimination but can be much more efficient than other approaches with regard to output size. The name is derived from the abstract syntax tree of the modules (not the module graph). The algorithm first marks all relevant statements and then "shakes the syntax tree" to remove all dead code. It is similar in idea to the mark-and-sweep garbage collection algorithm. Even though this algorithm is not restricted to ES modules, they make it much more efficient as they allow us to treat all modules together as a big abstract syntax tree with shared bindings.

图片


4.3. pkg.module 是什么?

pkg.module will point to a module that has ES2015 module syntax but otherwise only syntax features that the target environments support.

Typically, a library will be accompanied with a package.json file (this is mandatory if you're publishing on npm, for example). That file will often specify a pkg.main property - something like this:

{  "name": "my-package",  "version": "0.1.0",  "main": "dist/my-package.js"}

That instructs Browserify or Webpack or [insert module bundler here] to include the contents of dist/my-package.js – plus any dependencies it has – in your bundle when you call require('my-package') in your app or library.

But for ES2015-aware tools like Rollup, using the CommonJS (or Universal Module Definition) build isn't ideal, because we can't then take advantage of ES2015 module features. So assuming that you've written your package as ES2015 modules, you can generate an ES2015 module build alongside your CommonJS/UMD build:

{  "name": "my-package",  "version": "0.1.0",  "main": "dist/my-package.umd.js",  "module": "dist/my-package.esm.js"}

Now we're cooking with gas - my-package continues to work for everyone using legacy module formats, but people using ES2015 module bundlers such as Rollup don't have to compromise. Everyone wins!


参考:

UMD:https://github.com/umdjs/umd


AMD:https://github.com/amdjs/amdjs-api/wiki

RequireJS:http://requirejs.org/


CMD:https://github.com/seajs/seajs/issues/242

SeaJS:http://www.zhangxinxu.com/sp/seajs/


pkg.module:

https://github.com/rollup/rollup/wiki/pkg.module


es模块化语法回顾:

https://www.rollupjs.org/guide/en/#es-module-syntax