Open lcxfs1991 opened 7 years ago
原文链接
// webpack.config.js module.exports = { entry: { index: "./main.js", }, output: { path: __dirname + '/dist', filename: '[name].js' }, };
// main.js, entry chunk import { chunk2, chunk3 } from './main1'; import chunk5, { C1, C2, C3 } from './main2'; var chunk1 = 1; exports.chunk1 = chunk1; exports.chunk4 = { a: 1, b: 2 }; console.log(C1); console.log(chunk3);
// main1.js var chunk2 = 2; exports.chunk2 = chunk2; var chunk3 = 3; exports.chunk3 = chunk3; export function f1() { return 'f1'; } export function f2() { return 'f2'; }
// main2.js export function f3() { return 'f3'; } export default class C3 { constructor() { } f1() { console.log("f1") } f2() { console.log("f2"); } } export const C1 = 'c1'; export const C2 = 'c2';
// result file, index.js (function(modules) { // modules在webpack1的时候是数组,现在变成了key值是数字的对象 // module的缓存 var installedModules = {}; // require方法,转义成此 function __webpack_require__(moduleId) { // 若module已被缓存,直接返回 if(installedModules[moduleId]) return installedModules[moduleId].exports; // 创建一个新的module,被放入缓存中 // webpack1的时候都是全称,现在估计为了省点空间,都变成了id => i, load => l var module = installedModules[moduleId] = { i: moduleId, l: false, exports: {} }; // 执行module modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // 标明此module已被加载 module.l = true; // module.exports通过在执行module的时候,作为参数存进去,然后会保存module中暴露给外界的接口, // 如函数、变量等 return module.exports; } // 在源文件中,直接使用__webpack_modules__,生成文件用__webpack_require__.m替换 __webpack_require__.m = modules; // 暴露module缓存 __webpack_require__.c = installedModules; // identity function for calling harmory imports with the correct context __webpack_require__.i = function(value) { return value; }; // 为harmory exports 定义 getter function, configurable=false表明,此属性不能修改 // 例如export const,由于是常量,需要用__webpack_require__.d进行定义 __webpack_require__.d = function(exports, name, getter) { Object.defineProperty(exports, name, { configurable: false, enumerable: true, get: getter }); }; // 兼容 non-harmony 模块,这些模块如果设了__esModule属性,则被标记为non-harmony __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 polyfill __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; // 使用__webpack_public_path__,则会替换__webpack_require__.p __webpack_require__.p = "//localhost:8000/"; // 加载入口模块,并返回exports return __webpack_require__(__webpack_require__.s = 143); }) /************************************************************************/ ({ 143: // 入口模块 function(module, exports, __webpack_require__) { module.exports = __webpack_require__(64); }, 64: // main.js function(module, exports, __webpack_require__) { "use strict"; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__main1__ = __webpack_require__(72); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__main2__ = __webpack_require__(73); var chunk1 = 1; exports.chunk1 = chunk1; exports.chunk4 = { a: 1, b: 2 }; // 此如由于引用了C1,而C1又是常用,它事先定义成属性a,此处直接引用对象的属性a console.log(__WEBPACK_IMPORTED_MODULE_1__main2__["a" /* C1 */]); console.log(__WEBPACK_IMPORTED_MODULE_0__main1__["chunk3"]); }, 72: // main1.js function(module, exports, __webpack_require__) { "use strict"; /* unused harmony export f1 */ /* unused harmony export f2 */ // 此处注释表示,这两个harmony export模块没有被使用,后续如果使用unglify插件,f1与f2会被去掉 // 这个就是著名的tree-shaking var chunk2 = 2; exports.chunk2 = chunk2; var chunk3 = 3; exports.chunk3 = chunk3; function f1() { return 'f1'; } function f2() { return 'f2'; } }, 73: // main2.js function(module, exports, __webpack_require__) { "use strict"; /* unused harmony export f3 */ /* unused harmony export default */ /* harmony export (binding) */ __webpack_require__.d(exports, "a", function() { return C1; }); /* unused harmony export C2 */ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function f3() { return 'f3'; } var C3 = function () { function C3() { _classCallCheck(this, C3); } C3.prototype.f1 = function f1() { console.log("f1"); }; C3.prototype.f2 = function f2() { console.log("f2"); }; return C3; }(); var C1 = 'c1'; var C2 = 'c2'; } });
整个立即执行函数,主要是webpack_require, webpack_require.n, webpack_require.d起作用。installedModules是用于缓存已经加载的模块。
// webpack.config.js module.exports = { entry: { index: "./main.js", }, output: { path: __dirname + '/dist', filename: '[name].js', chunkFilename: "js/[name].js", }, };
// main.js var chunk1 = 1; exports.chunk1 = chunk1; function errorLoading(err) { console.error('Dynamic page loading failed', err); } function loadRoute(cb) { console.log("dynamic loading success"); return (module) => cb(null, module.default); } // 符合es6规范的异步加载模块方法 System.import('./main1') .then(loadRoute(cb)) .catch(errorLoading);
// main1.js var chunk2 = 2; exports.chunk2 = chunk2; var chunk3 = 3; exports.chunk3 = chunk3; export function f1() { return 'f1'; } export function f2() { return 'f2'; } export default function f3() { return 'f3'; }
// result file, index.js
// result file, 0.js webpackJsonp([0],{ 144: function(module, exports, __webpack_require__) { "use strict"; /* harmony export (immutable) */ exports["f1"] = f1; /* harmony export (immutable) */ exports["f2"] = f2; /* harmony export (immutable) */ exports["default"] = f3; var chunk2 = 2; exports.chunk2 = chunk2; var chunk3 = 3; exports.chunk3 = chunk3; function f1() { return 'f1'; } function f2() { return 'f2'; } function f3() { return 'f3'; } } });
// result file index.js (function(modules) { // webpackBootstrap // install a JSONP callback for chunk loading var parentJsonpFunction = window["webpackJsonp"]; // 全局定义webpackJsonp,让chunk加载的时候,直接可调用 window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) { // 将异加载的moreModules,添加到entry chunk的modules里面 // 然后使所有chunk标记为已加载,并触发回调函数 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; } // 将moreModules存入modules中 for(moduleId in moreModules) { if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; } } if(parentJsonpFunction) { parentJsonpFunction(chunkIds, moreModules, executeModules); } // resolves就是需要触发的回调 while(resolves.length) { resolves.shift()(); } }; // The module cache var installedModules = {}; // objects to store loaded and loading chunks var installedChunks = { 3: 0 }; // The require function 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; } // 异步加载函数,返回promise对象 __webpack_require__.e = function requireEnsure(chunkId) { // 如果已经加载,则返回Promise.resolve if(installedChunks[chunkId] === 0) return Promise.resolve(); // an Promise means "currently loading". if(installedChunks[chunkId]) { return installedChunks[chunkId][2]; } // 开始加载 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; // 加载的资源位置 script.src = __webpack_require__.p + "js/chunk/" + ({}[chunkId]||chunkId) + ".js"; var timeout = setTimeout(onScriptComplete, 120000); script.onerror = script.onload = onScriptComplete; function onScriptComplete() { // 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); var promise = new Promise(function(resolve, reject) { // resolve与reject,属于installedChunks[chunkId]的回调函数, // 在webpackJsonpCallback函数中,有可能被调用 installedChunks[chunkId] = [resolve, reject]; console.log(installedChunks[chunkId]); }); return installedChunks[chunkId][2] = promise; }; // expose the modules object (__webpack_modules__) __webpack_require__.m = modules; // expose the module cache __webpack_require__.c = installedModules; // identity function for calling harmory imports with the correct context __webpack_require__.i = function(value) { return value; }; // define getter function for harmory exports __webpack_require__.d = function(exports, name, getter) { Object.defineProperty(exports, name, { configurable: false, enumerable: true, get: getter }); }; // 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 = "//localhost:8000/"; // on error function for async loading __webpack_require__.oe = function(err) { console.error(err); throw err; }; // Load entry module and return exports return __webpack_require__(__webpack_require__.s = 141); }) /************************************************************************/ ({ 141: function(module, exports, __webpack_require__) { module.exports = __webpack_require__(64); }, 64: function(module, exports, __webpack_require__) { var chunk1 = 1; exports.chunk1 = chunk1; function errorLoading(err) { console.error('Dynamic page loading failed', err); } function loadRoute() { console.log("dynamic loading success"); return function (module) { console.log(module.default); }; } // 符合es6规范的异步加载模块 __webpack_require__.e/* System.import */(0).then(__webpack_require__.bind(null, 144)).then(loadRoute()).catch(errorLoading); } });
异步加载,主要是多了webpackJsonp全局函数,以及webpack_require.e作为加载script的函数。
// webpack.config.js module.exports = { entry: { index: "./main.js", spa: "./spamain.js" }, output: { path: __dirname + '/dist', filename: '[name].js', chunkFilename: "js/[name].js", }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "commons", filename: "commons.js", chunks: ['index', 'spa'], }), ] };
// result file, index.js (function(modules) { // webpackBootstrap // install a JSONP callback for chunk loading var parentJsonpFunction = window["webpackJsonp"]; 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()(); // 这里比异步加载相同的函数多了一段执行逻辑,主要用于执行entry chunk if(executeModules) { for(i=0; i < executeModules.length; i++) { result = __webpack_require__(__webpack_require__.s = executeModules[i]); } } return result; }; // The module cache var installedModules = {}; // objects to store loaded and loading chunks var installedChunks = { 3: 0 }; // The require function 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; } // This file contains only the entry chunk. // The chunk loading function for additional chunks __webpack_require__.e = function requireEnsure(chunkId) { if(installedChunks[chunkId] === 0) return Promise.resolve(); // an Promise means "currently loading". if(installedChunks[chunkId]) { return installedChunks[chunkId][2]; } // 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; script.src = __webpack_require__.p + "js/chunk/" + ({"0":"index","1":"spa"}[chunkId]||chunkId) + ".js"; var timeout = setTimeout(onScriptComplete, 120000); script.onerror = script.onload = onScriptComplete; function onScriptComplete() { // 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); var promise = new Promise(function(resolve, reject) { installedChunks[chunkId] = [resolve, reject]; }); return installedChunks[chunkId][2] = promise; }; // expose the modules object (__webpack_modules__) __webpack_require__.m = modules; // expose the module cache __webpack_require__.c = installedModules; // identity function for calling harmory imports with the correct context __webpack_require__.i = function(value) { return value; }; // define getter function for harmory exports __webpack_require__.d = function(exports, name, getter) { Object.defineProperty(exports, name, { configurable: false, enumerable: true, get: getter }); }; // 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 = "//localhost:8000/"; // on error function for async loading __webpack_require__.oe = function(err) { console.error(err); throw err; }; }) /************************************************************************/ ({ 8: function(module, exports, __webpack_require__) { "use strict"; /* unused harmony export f1 */ /* unused harmony export f2 */ /* unused harmony export default */ var chunk2 = 2; exports.chunk2 = chunk2; var chunk3 = 3; exports.chunk3 = chunk3; function f1() { return 'f1'; } function f2() { return 'f2'; } function f3() { return 'f3'; } } });
// main.js webpackJsonp([0],{ 14: function(module, exports, __webpack_require__) { "use strict"; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__main1__ = __webpack_require__(8); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__main2__ = __webpack_require__(24); var chunk1 = 1; exports.chunk1 = chunk1; exports.chunk4 = { a: 1, b: 2 }; }, 24: function(module, exports, __webpack_require__) { "use strict"; /* unused harmony export f3 */ /* unused harmony export default */ /* unused harmony export C1 */ /* unused harmony export C2 */ /* unused harmony export C4 */ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function f3() { return 'f3'; } var C3 = function () { function C3() { _classCallCheck(this, C3); } C3.prototype.f1 = function f1() { console.log("f1"); }; C3.prototype.f2 = function f2() { console.log("f2"); }; return C3; }(); var C1 = 'c1'; var C2 = 'c2'; var C4 = 'c4'; }, 41: function(module, exports, __webpack_require__) { module.exports = __webpack_require__(14); } },[41]);
// spamain.js webpackJsonp([1],{ 16: function(module, exports, __webpack_require__) { "use strict"; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__index_main1__ = __webpack_require__(8); console.log(__WEBPACK_IMPORTED_MODULE_0__index_main1__["chunk2"]); }, 43: function(module, exports, __webpack_require__) { module.exports = __webpack_require__(16); } },[43]);
提取公共包的这种情况,跟异步加载很类似,不过它将主要的功能函数都提取到common.js中,并且新增了执行module的逻辑。但主要入口的chunk都在主要逻辑的index.js与spa.js中。
webpack2使用了一些低端浏览器并不支持的接口,因此如果需要支持这些低端浏览器的业务,需要谨慎使用。
webpack2正式版本了啦?
@lilijialiang beta版
想请问一下,webpack打包的代码中并没有调用__webpack_require__.n函数。该函数是被设计成在用户自己的模块中被调用的吗?如果是这样一般在什么场景下会用到该函数。
@lcxfs1991 似乎缺少spamain.js源码?
原文链接
打包一个模块
整个立即执行函数,主要是webpack_require, webpack_require.n, webpack_require.d起作用。installedModules是用于缓存已经加载的模块。
异步加载
异步加载,主要是多了webpackJsonp全局函数,以及webpack_require.e作为加载script的函数。
CommonsChunkPlugin 提取公共包
提取公共包的这种情况,跟异步加载很类似,不过它将主要的功能函数都提取到common.js中,并且新增了执行module的逻辑。但主要入口的chunk都在主要逻辑的index.js与spa.js中。
webpack2使用了一些低端浏览器并不支持的接口,因此如果需要支持这些低端浏览器的业务,需要谨慎使用。