了解 Webpack 的启动代码对于分析模块和 chunk 是非常有帮助的。
Webpack 启动代码
首先从最简单的情况入手,在入口文件 index.js
中简单引用了一个模块中的方法:
// index.js
import {func1} from './module1';
// module1.js
export function func1() {
console.log('func1');
}
根据以上入口文件,在 target: web
(默认情况)下生成的 chunk 文件只有一个。观察其中包含的 Webpack 启动代码,可以发现由一个 IIFE 构成,其中传入的参数是一个方法数组。从其中每个方法的签名可以看出,类似 AMD。很明显,module1.js
模块的全部代码都在模块1中,而模块0对应 index.js
,引用了模块1。另外有一点值得注意,module1.js
中的方法并没有被真正使用到,注释 /* unused harmony export func1 */
也反映了这一点,后续在生产环境配合 UglifyJSPlugin
插件使用时,依托 TreeShaking 技术,这段无用代码会被移除。
(function(modules) { // IIFE
// 暂时省略处理模块的逻辑
})
([
/* 模块0 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */
var __WEBPACK_IMPORTED_MODULE_0__module1__ = __webpack_require__(1);
}),
/* 模块1 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* unused harmony export func1 */
function func1() {
console.log('func1');
}
})
]);
现在可以深入表达式方法细节了。首先定义了 __webpack_require__
方法,然后在方法上挂了一些属性便于快捷访问,最后调用入口模块也就是模块0。官方的注释非常详细,尤其是 require
方法的,就不再赘述了。
// The module cache
var installedModules = {};
// 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;
}
// 省略挂载属性...
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = 0);
在方法上挂载的属性中,d
用来处理常量
// define getter function for harmony exports
__webpack_require__.d = function(exports, name, getter) {
if(!__webpack_require__.o(exports, name)) {
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 = "";
// index.js
import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
return _.version();
});
在 Webpack 中,chunk 一共有三类:
- Entry chunk:
- Normal chunk:
- Initial chunk: