同步加载打包文件分析
安装模块
cnpm i webpack webpack-cli html-webpack-plugin clean-webpack-plugin -D
webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "development",
devtool: "source-map",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
},
module: {},
plugins: [
new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: ["**/*"] }),
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html",
}),
],
devServer: {},
};
src\index.js
let title = require("./title.js");
console.log(title);
src\title.js
module.exports = "title";
src\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webpack</title>
</head>
<body></body>
</html>
package.json
"scripts": {
"build": "webpack"
}
打包文件
(() => {
// 该入口文件引入的模块,会议键值对的形式放在 modules 里面
// 不管你是用什么样的路径来加载的,最终模块 ID (key值)统一会变成相对根目录的相对路径
// - index.js ./src/index.js
// - title.js ./src/title.js
// - jquery ./node_modules/jquery/dist/jquery.js
var modules = ({
"./src/title.js":
((module, module_exports, require) => {
// 将 title 放入 exports 中
module.exports = "title";
})
});
// 缓存模块
var cache = {};
function require(moduleId) {
// 如果存在缓存,直接从缓存中获取
if (cache[moduleId]) {
return cache[moduleId].exports;
}
// 没有缓存,则需要放入缓存中
var module = cache[moduleId] = {
exports: {} // 默认值为空,引入模块后会赋值到这里
};
// 加载模块,执行该模块代码
modules[moduleId](module, module.exports, require);
return module.exports;
}
// 入口文件加载后,执行以下代码
(() => {
let title = require("./src/title.js");
console.log(title);
})();
})();
异步加载打包文件分析
webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "development",
devtool: "source-map",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
},
module: {},
plugins: [
new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: ["**/*"] }),
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html",
}),
],
devServer: {},
};
src\index.js
import(/* webpackChunkName: "hello" */ "./hello").then((result) => {
console.log(result.default);
});
hello.js
export default 'hello';
dist\main.js
(() => {
// 存放着所有的模块定义,包括懒加载,或者说异步加载过来的模块定义
var modules = ({});
var cache = {};
// 因为在 require 的时候,只会读取 modules 里面的模块定义
function require(moduleId) {
if (cache[moduleId]) {//先看缓存里有没有已经缓存的模块对象
return cache[moduleId].exports;//如果有就直接返回
}
// module.exports默认值 就是一个空对象
var module = { exports: {} };
cache[moduleId] = module;
// 会在模块的代码执行时候给module.exports赋值
modules[moduleId].call(module.exports, module, module.exports, require);
return module.exports;
}
require.f = {};
// 如何异步加载额外的代码块 chunkId=hello
// 2.创建 promise,发起 jsonp 请求
require.e = (chunkId) => {
let promises = [];
require.f.j(chunkId, promises);
return Promise.all(promises); // 等这个 promise 数组里的 promise 都成功之后
}
require.p = ''; // publicPath 资源访问路径
require.u = (chunkId) => { // 参数是代码块的名字,返回值是这个代码的文件名
return chunkId + '.main.js';
}
// 已经安装的代码块, main 代码块的名字:0 表示已经就绪
let installedChunks = {
main: 0,
hello: 0
}
//3.通过 jsonp 异步加载 chunkId,也就是 hello 这个代码块
require.f.j = (chunkId, promises) => {
// 创建一个新的 promise 数组,放到了数组中去
let promise = new Promise((resolve, reject) => {
installedChunks[chunkId] = [resolve, reject];
});
promises.push(promise);
var url = require.p + require.u(chunkId);// /hello.main.js
require.l(url);
}
// http://127.0.0.1:8082/hello.main.js
// 4.通过 JSONP 请求这个新的 url 地址
require.l = (url) => {
let script = document.createElement('script');
script.src = url;
document.head.appendChild(script);// 一旦添加 head 里,浏览器会立刻发出请求
}
//6.开始执行回调
var webpackJsonpCallback = ([chunkIds, moreModules]) => {
// chunkIds = ['hello']=>[resolve,reject]
// let resolves = chunkIds.map(chunkId => installedChunks[chunkId][0]);
let resolves = [];
for (let i = 0; i < chunkIds.length; i++) {
let chunkData = installedChunks[chunkIds[i]];
installedChunks[chunkIds[i]] = 0;
resolves.push(chunkData[0]);
}
// 把异步加载回来的额外的代码块合并到总的模块定义对象 modules 上去
for (let moduleId in moreModules) {
modules[moduleId] = moreModules[moduleId];
}
resolves.forEach(resolve => resolve());
}
/**
* 将 definition 的属性都放到 exports 里面(用代理的方式实现)
*/
require.d = (exports, definition) => {
for (let key in definition) {
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
}
/**
* 新增 2 个属性 Symbol.toStringTag 和 __esModule,用于标识原来是 esModule 模块
*/
require.r = (exports) => {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); // Object.prototype.toString.call(exports) === [object Module]
Object.defineProperty(exports, '__esModule', { value: true }); // exports.__esModule=true
}
// 0.把空数组赋给了 window["webpack5"],然后重写的 window["webpack5"].push
var chunkLoadingGlobal = window["webpack5"] = [];
// 然后重写的 window["webpack5"].push = webpackJsonpCallback
chunkLoadingGlobal.push = webpackJsonpCallback;
// 异步加载 hello chunk 代码块,然后把 hello chunk 代码块里的模块定义合并到主模块定义里去
// 再去加载这个 hello.js 这个模块,拿到模块的导出结果
// 1.准备加载异步代码块 hello
require.e("hello").then(require.bind(require, "./src/hello.js")).then(result => {
console.log(result.default);
})
})();
hello.main.js
// 5.执行 window["webpack5"] 上的 push 方法,传递参数 [chunkIds,moreModules]
(window["webpack5"] = window["webpack5"] || []).push([["hello"], {
"./src/hello.js": ((module, exports, require) => {
require.r(exports);
require.d(exports, {
"default": () => __WEBPACK_DEFAULT_EXPORT__
});
const __WEBPACK_DEFAULT_EXPORT__ = ('hello ');
})
}]);
打赏作者
您的打赏是我前进的动力
微信
支付宝
webpack 中的 process
上一篇
评论