执行顺序是:入口模块 -> 工具模块 -> 入口模块。入口模块中首先就通过 __webpack_require__("./src/utils/math.js") 拿到了工具模块的 exports 对象。再看工具模块, ES 导出语法转化成了 __webpack_require__.d(__webpack_exports__, [key], [getter]),而 __webpack_require__.d 函数的定义在 webpackBootstrap 内:
- // 定义 exports 对象导出的属性。
- __webpack_require__.d = function (exports, name, getter) {
- // 如果 exports (不含原型链上)没有 [name] 属性,定义该属性的 getter。
- if (!__webpack_require__.o(exports, name)) {
- Object.defineProperty(exports, name, {
- enumerable: true,
- get: getter
- });
- }
- };
- // 包装 Object.prototype.hasOwnProperty 函数。
- __webpack_require__.o = function (object, property) {
- return Object.prototype.hasOwnProperty.call(object, property);
- };
可见 __webpack_require__.d 其实就是 Object.defineProperty 的简单包装.
引用工具模块导出的变量后,入口模块再执行它剩余的部分。至此,Webpack 基本的模块执行过程就结束了。
好了,我们用流程图总结一下 Webpack 模块的加载思路:
异步加载
有上面的打包我们发现将不同的打包进一个 main.js 文件。 main.js 会集中消耗太多网络资源,导致用户需要等待很久才可以开始与网页交互。
一般的解决方式是:根据需求降低首次加载文件的体积,在需要时(如切换前端路由器,交互事件回调)异步加载其他文件并使用其中的模块。
Webpack 推荐用 ES import() 规范来异步加载模块,我们根据 ES 规范修改一下入口模块的 import 方式,让其能够异步加载模块:
- src/index.js
-
- console.log( Hello webpack! );window.setTimeout(() => { import( ./utils/math ).then(mathUtil => { console.log( 1 + 2: + mathUtil.plus(1, 2)); });}, 2000);
工具模块 (src/utils/math.js)依然不变,在 webpack 配置里,我们指定一下资源文件的公共资源路径 (publicPath),后面的探索过程中会遇到。
- const path = require( path );
- const MyPlugin = require( ./src/MyPlugin.js )
-
-
- module.exports = {
- mode: development ,
- devtool: source-map ,
- entry: ./src/index.js ,
- output: {
- path: path.resolve(__dirname, dist ),
- publicPath: /dist/
- },
- plugins:[
- new MyPlugin()
- ]
- };
接着执行一下打包,可以看到除了 dist/main.js 外,又多了一个 dist/0.js ./src/utils/math.js。模块从 main chunk 迁移到了 0 chunk 中。而与 demo1 不同的是, main chunk 中添加了一些用于异步加载的代码,我们概览一下:
- // webpackBootstrap
- (function (modules) {
- // 加载其他 chunk 后的回调函数
- function webpackJsonpCallback(data) {
- // ...
- }
- // ...
- // 用于缓存 chunk 的加载状态,0 为已加载
- var installedChunks = {
- "main": 0
- };
- // 拼接 chunk 的请求地址
- function jsonpScriptSrc(chunkId) {
- // ...
- }
- // 同步 require 函数,内容不变
- function __webpack_require__(moduleId) {
- // ...
- }
- // 异步加载 chunk,返回封装加载过程的 promise
- __webpack_require__.e = function requireEnsure(chunkId) {
- // ...
- }
- // ...
- // defineProperty 的包装,内容不变
- __webpack_require__.d = function (exports, name, getter) {}
- // ...
- // 根据配置文件确定的 publicPath
- __webpack_require__.p = "/dist/";
- /**** JSONP 初始化 ****/
- var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
- var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
- jsonpArray.push = webpackJsonpCallback;
- jsonpArray = jsonpArray.slice();
- for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
- var parentJsonpFunction = oldJsonpFunction;
- /**** JSONP 初始化 ****/
- return __webpack_require__(__webpack_require__.s = "./src/index.js");
- })({
- "./src/index.js": (function(module, exports, __webpack_require__) {
- document.write( Hello webpack! );
- window.setTimeout(() => {
- __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./utils/math */ "./src/utils/math.js")).then(mathUtil => {
- console.log( 1 + 2: + mathUtil.plus(1, 2));
- });
- }, 2000);
- })
- })
(编辑:ASP站长网)
|