模块依赖加载解析
// webpack.config.js配置
const path = require('path')
module.exports = {
devtool: 'none', // 不生成映射url,也就是不生成source-map文件
mode: 'development', // development | production
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), // 在当前目录下添加dist目录,并且将输出的内容放在filename指定的文件中
filename: 'bundle.[hash:8].js' // bundle.[hash:8].js防止有缓存,所以每次生成不一样的bundle.js就是加hash,后面的 ':8'表示hash的位数
},
// 这里还配置了一些解析css的loader,省略了
}
// index.js
require('./index.css')
let aa = require('./a.js')
console.log(aa);
console.log('hello webpack');
let fn = () => {
console.log('我是fn');
}
fn()
// a.js
function testshow () {
console.log('哈哈哈哈哈哈');
}
module.exports = testshow
/* index.css */
@import './a.css';
body {
background-color: pink;
transform: rotate(45deg);
background: url('./w3.png');
}
/* a.css */
body{
background-color: red;
}
// bundle.js
(function (modules) {
// 缓存模块对象,如果已经被缓存过了,就不需要再重新加载,直接从这个对象中获取模块文件moduleId对应的exports导出对象
var installedModules = {};
// webpack实现的require导入函数,这个函数用于递归导入依赖模块
function __webpack_require__ (moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId, // moduleId是模块文件名,第一次传入模块文件就是./src/index.js
l: false, // 标记这个模块文件是否被加载过
exports: {} // moduleId对应的模块文件的导出的对象保存在这里
};
// 第一次的modules[moduleId]相当于modules[./src/index.js],获取到的是传入./src/index.js模块对应的函数
// modules[moduleId].call() ,直接加载了moduleId模块文件对应的函数代码,并把函数内部的this指向改为module.exports,还把递归函数__webpack_require__传入。这样相当于执行了./src/index.js模块对象的函数,在函数中又有其他模块的导入,则可以使用__webpack_require__再进行递归加载
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 标记moduleId这个模块已经被加载过了
module.l = true;
// 最终把导出返回,每个模块最终在这里把自己的模块导出对象exports返回到上一层调用处
return module.exports;
}
// m属性向外暴露传入的模块参数对象
__webpack_require__.m = modules;
// c属性向外暴露缓存对象
__webpack_require__.c = installedModules;
// d方法兼容各种导出模式,重写getter方法
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// r方法用于是import导入方式时,则会给模块导出对象exports增加`__esModule`属性标记
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
// t方法 todo暂时没看明白
__webpack_require__.t = function (value, mode) {
if (mode & 1) value = __webpack_require__(value);
if (mode & 8) return value;
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
return ns;
};
// 获取模块默认导出对象,是ES的导出方式,则使用default为默认导出对象,否则按照commonJS的默认导出module
// 主要用于这种场景,导入导出不一致。如果在一个模块文件中,使用import导入了某模块,但是导入的这个模块又是以commonJS的方式导出的
// 导入判断是否ES Module,采用r方法判断;导出是否使用ES Module采用n函数判断
__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;
};
// o方法用于判断property属性是否是object对象自己的属性
__webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// p属性存放公共访问路径
__webpack_require__.p = "";
//__webpack_require__方法在这里调用,并且传入了配置的入口模块"./src/index.js"
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
({
"./src/a.js":
(function (module, exports) {
function testshow () {
console.log('哈哈哈哈哈哈');
}
module.exports = testshow;
}),
"./src/index.css":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
// 由于index.css的源代码中使用ES Module导入的a.css,所以这里调r方法
__webpack_require__.r(__webpack_exports__);
}),
"./src/index.js":
(function (module, exports, __webpack_require__) {
// __webpack_require__递归导入index.css,和a.js,就跟导入index.js一样
__webpack_require__("./src/index.css");
// __webpack_require__("./src/a.js")返回的是a.js的导出export,然后赋值给aa
var aa = __webpack_require__("./src/a.js");
console.log(aa);
console.log('hello webpack');
var fn = function fn () {
console.log('我是fn');
};
fn();
})
});
commonJS和ES Module的导入导出有区别
// index.js
// require('./index.css')
// let aa = require('./a.js')
import a from './a.js';
import './index.css'
let aa = a
console.log(aa);
console.log('hello webpack');
let fn = () => {
console.log('我是fn');
}
fn()
// a.js
function testshow () {
console.log('哈哈哈哈哈哈');
}
module.exports = testshow
// bundle.js 只截取了参数对象这部分
({
"./src/a.js":
(function (module, exports) {
function testshow () {
console.log('哈哈哈哈哈哈');
}
module.exports = testshow;
}),
"./src/index.css":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
}),
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
// r方法标识了index.js是个ESModule
__webpack_require__.r(__webpack_exports__);
var _a_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
// 因为a模块是import导入的,这里使用n方法判断出a.js的默认导出是commonJS的导出
var _a_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_a_js__WEBPACK_IMPORTED_MODULE_0__);
var _index_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/index.css");
var aa = _a_js__WEBPACK_IMPORTED_MODULE_0___default.a;
console.log(aa);
console.log('hello webpack');
var fn = function fn () {
console.log('我是fn');
};
fn();
})
});
模块依赖加载流程总结
0. 自调用函数接收到modules模块集合对象开始执行
1. 执行到 return __webpack_require__(__webpack_require__.s = "./src/index.js");时,调用webpack_require函数传入第一个模块文件index.js
2. webpack_require函数内部开始执行,判断传入的模块index.js是否存在缓存中,有的话直接从缓存中返回导出index.js的export
导出,没有则将其存入缓存,并创建新对象module。
3. 直接获取index.js模块对应的函数,直接执行,并传入响应的参数
4. 执行index.js对象的函数时发现导入了a.js和index.css————>注意这里采用webpack_require函数递归导入a.js等,就跟导入index.js一样,最终将返回的结果在webpack_require的return module.exports处返回对应模块的导出,接着回到index.js对应的方法webpack_require('a.js')获取到a.js模块的exports,然后在index.js中进行使用export导出的值。
发表评论
还没有评论,快来抢沙发吧!