07_webpack_模块化原理和source-map
在webpack的顶层配置中有一个配置叫mode(模式),他其中的值有3种'production、development、none
默认的值为production(生产环境),你会发现webpack解析后的代码是经过压缩和丑化的
因为在你设置mode的时候,他默认代表配置了哪些东西
development |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development . 为模块和 chunk 启用有效的名。 |
production |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production 。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin ,FlagIncludedChunksPlugin ,ModuleConcatenationPlugin ,NoEmitOnErrorsPlugin 和 TerserPlugin 。 |
none |
不使用任何默认优化选项 |
为了分析为什么import 和 require经过webpack解析过的文件能够支持模块化,所以我们要把mode的值设置为:development
设置为development之后,经过webpack解析后的代码不会丑化和压缩,方便分析
模块化原理
在js文件中使用CommonJs语法浏览器是不支持的,es Module有一些低版本的浏览器也不一定支持,但是在开发阶段,你在你的js文件中可以使用你想用的任意的两种模块化方式,然后再使用webpack进行打包,打包后的文件你会发现他们都支持模块化了
Webpack打包的代码,允许我们使用各种各样的模块化,但是最常用的是Commonjs和es module
那么他是如何帮助我们实现了代码中支持模块化呢?
我们来研究它的原理
commonJs模块化实现原理
esModule实现原理
commonJs加载esModule的原理
esModule加载CommonJs的原理
commonJs模块化实现原理
创建一个入口文件common.js
const { dateFormat, priceFormate } = require('./js/format') console.log(dateFormat('abc')); console.log(priceFormate('abc'));
format.js
const dateFormat = (date) => { return "2020-12-12" } const priceFormate = (price) => { return "100.100" } module.exports = { dateFormat, priceFormate }
从webpack打包后的代码里,可以看见很多的eval函数
eval("const { dateFormat, priceFormat, priceFormate } = __webpack_require__(/*! ./js/format */ \"./src/js/format.js\")\r\nconsole.log(dateFormat('abc'));\r\nconsole.log(priceFormate('abc'));\n\n//# sourceURL=webpack://02_webpack/./src/common.js?");
eval("const dateFormat = (date) => {\r\n return \"2020-12-12\"\r\n}\r\n\r\nconst priceFormate = (price) => {\r\n return \"100.100\"\r\n}\r\n\r\nmodule.exports = {\r\n dateFormat,\r\n priceFormate\r\n}\n\n//# sourceURL=webpack://02_webpack/./src/js/format.js?");
现在希望不转换成eval函数,而是转换为正常代码
在webpack.config.js中设置devtool
在我们的mode为development的时候,devtool默认值为veal
所以我们需要重新设置devtool为source-map
mode: 'development', entry: './src/common.js', devtool: 'source-map',
然后再重新打包
打包完成之后你会发现build下面多了个source-map文件,我们不需要这个文件,删除掉就好了
你再重新打开bundle.js的时候就不是eval函数了
格式化(删除注释、立即执行函数)后的代码
//定义了一个对象 // 模块的路径作为key:函数(value) var __webpack_modules__ = { "./src/js/format.js": (function (module) { const dateFormat = (date) => { return "2020-12-12" } const priceFormate = (price) => { return "100.100" } module.exports = { dateFormat, priceFormate } }) } //定义一个对象,作为加载模块的缓存 var __webpack_module_cache__ = {}; //函数,当我们加载一个模块的时候,都会通过这个函数来加载 function __webpack_require__(moduleId) { //检查是否有缓存 var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } //在缓存中根据地址id创建一个对象 var module = __webpack_module_cache__[moduleId] = { exports: {} }; //执行__webpack_modules__传入路径id,得到function,传入创建的module __webpack_modules__[moduleId](module, module.exports, __webpack_require__); return module.exports; } var __webpack_exports__ = {}; //立即执行函数,如果不加前面的感叹号,这就是一个错误的语法 // 加!代表这是一个表达式 //具体开始执行代码逻辑 !function () { const { dateFormat, priceFormate } = __webpack_require__("./src/js/format.js") console.log(dateFormat('abc')); console.log(priceFormate('abc')); }();
esModule实现原理
"use strict"; // 1.定义了一个对象,里面放的是模块映射 var __webpack_modules__ = ({ "./src/js/math.js": (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "mul": function () { return mul; }, "sum": function () { return sum; } }); const sum = (num1, num2) => { return num1 + num2; } const mul = (num1, num2) => { return num1 * num2 } }) }); //2.缓存 var __webpack_module_cache__ = {}; //3.require函数的实现(加载模块) function __webpack_require__(moduleId) { //查看是否有缓存 var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } var module = __webpack_module_cache__[moduleId] = { exports: {} }; __webpack_modules__[moduleId](module, module.exports, __webpack_require__); return module.exports; } !function () { //给这个函数对象添加一个属性:d->function __webpack_require__.d = function (exports, definition) { for (var key in definition) { if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } } }; }(); !function () { //__webpack_require__这个函数添加了一个属性:o->funcion,对象是否有某个属性 __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } }(); !function () { //__webpack_require__这个函数添加了一个属性:r->funcion //给对象中添加esmodule的标识 __webpack_require__.r = function (exports) { //是否支持Symbol if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { //标识这是ESMODUEL Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } //标识这是ESMODUEL Object.defineProperty(exports, '__esModule', { value: true }); }; }(); var __webpack_exports__ = {}; //执行函数 !function () { __webpack_require__.r(__webpack_exports__); var _js_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/js/math.js");
//这种语法的调用和直接调用函数是一样的 console.log((0, _js_math__WEBPACK_IMPORTED_MODULE_0__.mul)(20, 30));
console.log((0, _js_math__WEBPACK_IMPORTED_MODULE_0__.sum)(10, 20)); }();
commonJs加载esModule的原理
//模块映射 var __webpack_modules__ = ({ "./src/js/math.js": (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "mul": function () { return mul; }, "sum": function () { return sum; } }); const sum = (num1, num2) => { return num1 + num2; } const mul = (num1, num2) => { return num1 * num2 } }) }); //缓存 var __webpack_module_cache__ = {}; //导入函数 function __webpack_require__(moduleId) { //查找缓存 var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } var module = __webpack_module_cache__[moduleId] = { exports: {} }; __webpack_modules__[moduleId](module, module.exports, __webpack_require__); return module.exports; } //代理 !function () { __webpack_require__.d = function (exports, definition) { for (var key in definition) { if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } } }; }(); //检测某个对象是否有某个属性 !function () { __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } }(); //给对象中添加esmodule的标识 !function () { __webpack_require__.r = function (exports) { if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; }(); var __webpack_exports__ = {}; !function () { const math = __webpack_require__("./src/js/math.js") console.log(math.mul(10, 20)); console.log(math.sum(20, 30)); }();
esModule加载CommonJs的原理
var __webpack_modules__ = ({ "./src/js/format.js": (function (module) { const dateFormat = (date) => { return "2020-12-12" } const priceFormate = (price) => { return "100.100" } module.exports = { dateFormat, priceFormate } }) }); var __webpack_module_cache__ = {}; function __webpack_require__(moduleId) { var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } var module = __webpack_module_cache__[moduleId] = { exports: {} }; __webpack_modules__[moduleId](module, module.exports, __webpack_require__); return module.exports; } !function () { __webpack_require__.n = function (module) { var getter = module && module.__esModule ? function () { return module['default']; } : function () { return module; }; __webpack_require__.d(getter, { a: getter }); return getter; }; }(); !function () { __webpack_require__.d = function (exports, definition) { for (var key in definition) { if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } } }; }(); !function () { __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } }(); !function () { __webpack_require__.r = function (exports) { if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; }(); var __webpack_exports__ = {}; !function () { "use strict"; __webpack_require__.r(__webpack_exports__); var _js_format__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/js/format.js"); var _js_format__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_js_format__WEBPACK_IMPORTED_MODULE_0__); console.log(_js_format__WEBPACK_IMPORTED_MODULE_0___default().priceFormate()); console.log(_js_format__WEBPACK_IMPORTED_MODULE_0___default().dateFormat()); }();