We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
按照本文原理,手写了个打包工具:https://github.com/tianma630/mypack
首先我编写了3个js文件 a.js
export default 1; export const b = 2; export const c = 3; export const plus = function(a, b) { return a + b; }
b.js
export default function (a) { return a * a; };
entry.js
import a, {b, c, plus} from './a'; import d from './b'; let ret = plus(a, b) + d(c); console.log(ret);
使用webpack命令生成打包文件,结果其实是一个直接执行函数,为了方便查看,删除了多余代码
(function(modules) { // 存储了所有模块化的信息 var installedModules = {}; // 按文件处理解析模块化信息,moduleId其实就是文件路径名称 function __webpack_require__(moduleId) { // 检查该文件是否缓存了 if(installedModules[moduleId]) { return installedModules[moduleId].exports; } // 新建一个空的 var module = installedModules[moduleId] = { i: moduleId, // 模块id 其实就是文件路径,比如./src/b.js l: false, exports: {} // 这个文件中的所有export的内容,比如b.js中 {default: function(a) { return a * a; }} }; // 处理文件中的模块化信息,并执行代码,具体逻辑在下面的参数中,先mark下 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // 标记文件被加载,就是是否被使用 module.l = true; // 返回模块化的信息 return module.exports; } // 缓存一个模块,就是处理类似export const b = 2;的逻辑 __webpack_require__.d = function(exports, name, getter) { if(!__webpack_require__.o(exports, name)) { // 判断下这个模块是否缓存过 Object.defineProperty(exports, name, { enumerable: true, get: getter }); } }; // 入口执行函数,就是执行entry中的配置文件 return __webpack_require__(__webpack_require__.s = "./src/entry.js"); }) ({ // 处理具体的模块代码文件,按文件区分模块,执行的入口就是上面mark的call方法 "./src/a.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; // 为了方便查看eval中的代码,我们在下面格式化一下 eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return b; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"c\", function() { return c; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"plus\", function() { return plus; });\n/* harmony default export */ __webpack_exports__[\"default\"] = (1);\n\nconst b = 2;\n\nconst c = 3;\n\nconst plus = function(a, b) {\n return a + b;\n}\n\n//# sourceURL=webpack:///./src/a.js?"); }), "./src/b.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = (function (a) {\n return a * a;\n});;\n\n//# sourceURL=webpack:///./src/b.js?"); }), "./src/entry.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a */ \"./src/a.js\");\n/* harmony import */ var _b__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./b */ \"./src/b.js\");\n\n\n\nlet ret = Object(_a__WEBPACK_IMPORTED_MODULE_0__[\"plus\"])(_a__WEBPACK_IMPORTED_MODULE_0__[\"default\"], _a__WEBPACK_IMPORTED_MODULE_0__[\"b\"]) + Object(_b__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(_a__WEBPACK_IMPORTED_MODULE_0__[\"c\"]);\n\nconsole.log(ret);\n\n\n\n// (function(a, b) {\n// let ret = a(1, 2) + b(2, 3);\n\n// console.log(ret);\n// })(\n// {a: function(a, b) {\n// return a + b;\n// }}, \n// function(a, b) {\n// return a * b;\n// }\n// )\n\n\n//# sourceURL=webpack:///./src/entry.js?"); }) });
格式化eval中的代码
// function(module, __webpack_exports__, __webpack_require__) // __webpack_require__ 上面的模块化入口方法 // __webpack_exports__ 存储模块化信息的对象, 可以理解为{} // a.js __webpack_require__.r(__webpack_exports__); // 标记了这个是存储模块化信息的对象,没有直接作用 __webpack_require__.d(__webpack_exports__, "b" , function() { return b; }); // 放入到模块化对象中,可以理解为{b: function() { return b; }} __webpack_require__.d(__webpack_exports__, "c", function() { return c; }); __webpack_require__.d(__webpack_exports__, "plus", function() { return plus; }); __webpack_exports__["defalut"] = (1); // 处理export default const b = 2; const c = 3; const plus = function(a, b) { return a + b; } // b.js __webpack_require__.r(__webpack_exports__); __webpack_exports__["default"] = (function (a) { return a * a; }); // entry.js // 入口文件必须放在最下面执行 __webpack_require__.r(__webpack_exports__); var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js"); // 根据路径获取模块依赖,如果模块不存在,则先执行./src/a.js中的代码,如果已经执行过了,则直接获取缓存中的依赖 var _b__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/b.js"); // 将依赖对象和方法动态替换成引入的依赖 let ret = Object(_a__WEBPACK_IMPORTED_MODULE_0__["plus"])(_a__WEBPACK_IMPORTED_MODULE_0__["default"], _a__WEBPACK_IMPORTED_MODULE_0__["b"]) + _a__WEBPACK_IMPORTED_MODULE_0__["c"] * _b__WEBPACK_IMPORTED_MODULE_1__["default"]; console.log(ret);
模块化整体的逻辑可以简单理解为,按js代码文件路径,将所有的export缓存到模块化对象installedModules中,在入口文件,按依赖路径从模块化对象中获取依赖并执行。
// 本文的例子生成的installedModules对象 { "./src/entry.js": { "i": "./src/entry.js", "l": true, "exports": {} }, "./src/a.js": { "i": "./src/a.js", "l": true, "exports": { "b": function () { return b; }, "c": function() { return c; }, "plus": function (a, b) { return a + b; }, "default": 1 } }, "./src/b.js": { "i": "./src/b.js", "l": true, "exports": { "default": function (a) { return a * a; } } } }
最后还有一个问题是如何把实际的代码转变成eval中的代码结构的,这就要用到ast了,有兴趣的同学可以去了解下。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
按照本文原理,手写了个打包工具:https://github.com/tianma630/mypack
首先我编写了3个js文件
a.js
b.js
entry.js
使用webpack命令生成打包文件,结果其实是一个直接执行函数,为了方便查看,删除了多余代码
格式化eval中的代码
模块化整体的逻辑可以简单理解为,按js代码文件路径,将所有的export缓存到模块化对象installedModules中,在入口文件,按依赖路径从模块化对象中获取依赖并执行。
最后还有一个问题是如何把实际的代码转变成eval中的代码结构的,这就要用到ast了,有兴趣的同学可以去了解下。
The text was updated successfully, but these errors were encountered: