一、分类
- 当前文件模块类型:esModule / commonJs
- 加载模块方式:import / import() / require() / require(表达式)
1、基本逻辑
// 导入一个模块
__webpack_require__(模块id)
// => 会执行下面代码
// Execute the module function
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
return module.exports;
// 说明:
// 1、执行通用加载函数:__webpack_require__
// 2、如果该模块没有加载过,则执行该模块,然后导出该模块的exports
复制代码
2、当前文件模块类型是commonJs
// 在webpack会转化成:
// 当前模块:
module.exports = ...
复制代码
3、当前文件模块类型是esModule
// 源码
export const a = {
x:1,
y:[1,2]
}
export default 13;
=> 在webpack会转化成:
/* 1 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "a": () => (/* binding */ a),
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
const a = {
x:1,
y:[1,2]
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (13);
/***/ })
// 分析:
// 1、会执行__webpack_require__.r:把exports标记__esModule:true
// 2、会执行 __webpack_require__.d。对导出的项,做getter处理,没有seter,也就是导出的模块中不能修改导出项
复制代码
4、导入模块方式为import
// 案例一:import + 解析
import {a} from './'
console.log(a)
// => 在webpack中会转化为
var _ref1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
console.log(_ref1_js__WEBPACK_IMPORTED_MODULE_0__.a)
复制代码
// 案例二:import + default
import de from './ref1.js'
console.log(de)
// => 在webpack中会转化为
var _ref1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
console.log(_ref1_js__WEBPACK_IMPORTED_MODULE_0__.default)
复制代码
// 总结:
// 也就是都是通过__webpack_require__(模块id)来加载模块,返回export{}对象
// 如果是{}形式解析,则为importObj.xx形式
// 如果是导入default,则为importObj.default形式
复制代码
5、导入模块方式为import()
// 案例一、如果该模块已经不是已经在modules中了。则
import ref1 from './ref1.js'
import('./ref1.js').then((res)=>{
console.log('import',res)
})
console.log(ref1)
=> 在webpack会转化为:
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _ref1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
// const ref = require('./ref.json')
Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 1)).then((res)=>{
console.log('import',res)
})
console.log(_ref1_js__WEBPACK_IMPORTED_MODULE_0__.default)
// 因为已经有了ref1模块,所以这边没有使用异步再去加载该模块
// 因为import()是动态,是Promise。所以这边模拟了这个过程
// 补充:其实通过前面已经知道,导出的是{a:default:}类似结构,所以,如果需要{a,default} = res来获取到处项
复制代码
// 案例二、纯粹异步加载
import('./ref1.js').then((res)=>{
console.log('import',res)
})
=> 在webpack会转化为:
__webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(__webpack_require__, 1)).then((res)=>{
console.log('import',res)
})
// __webpack_require__.e 是异步加载模块
// 相当于amd类似
复制代码
6、导入模式为import()表达式
// 和下面的require()表达式是一个效果
// 注意:都需要提供一些上下文给系统,不然它也茫然啊,不知道要生成什么map
// 如:require(window.path)你来生成map嘛,最起码要(`./${path}`)类似这种提供一些信息
复制代码
7、导入模式为require()
// 源码:
const ref = require('./ref.json')
=> 在webpack会转化为:
const ref = __webpack_require__(1)
复制代码
8、导入模式为require(表达式):模块上下文(content)
// 源码:
const ref = require('./ref.json')
=>webpack转化后
const ref = __webpack_require__(1)(`./${name}`)
// 具体下面有补充
复制代码
官方文档:webpack.docschina.org/guides/depe…
一、带表达式的require理解
// 案例
const name = "ref.json"
const ref = require(`./${name}`)
复制代码
构建后代码
// module:0
const name = "ref.json"
const ref = __webpack_require__(1)(`./${name}`)
// 也就是这里变成()()结构
// 也就是加载模块1,然后传变量来决定最终是加载哪个模块
// 即:模块1是一个多个模块的一个映射
复制代码
// module:1
// 一个预期符合该表达式的模块映射
var map = {
"./": 2,
"./index": 2,
"./index.js": 2,
"./index1": 5,
"./index1.js": 5,
"./ref": 4,
"./ref.json": 4,
"./requireTest": 0,
"./requireTest.js": 0
};
//...
function webpackContext(req) {
// ...
return __webpack_require__(id);
}
// 导出的不是一个模块,而是一个函数
module.exports = webpackContext;
复制代码
即:require如果是表达式,则编译时返回的是函数,然后运行时映射到真正的模块。
二、require.content的使用
- 理解:对比带表达式的require是系统判断生成的上下文,这里是我们来指定解析上下文
- 这个是webpack提供的api
// 上面是上下文的概念理解,这里贴上这部分完整代码
var map = {
"./": 2,
"./index": 2,
"./index.js": 2,
"./index1": 5,
"./index1.js": 5,
"./ref": 4,
"./ref.json": 4,
"./requireTest": 0,
"./requireTest.js": 0
};
function webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
function webpackContextResolve(req) {
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return map[req];
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = 1;
复制代码
- 返回的是函数,而不是模块;
// webpackContext
webpackContext('./ref') // 加载ref模块
webpackContext.resolve('./ref') // 输出./ref路径匹配到的模块id
webpackContext.keys() // 输出map的keys
webpackContext.id // 输出当前模块的模块id
复制代码

总结
- 模块编译:如果是esModule会执行下面
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "a": () => (/* binding */ a),
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
const a = {
x:1,
y:[1,2]
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (13);
复制代码
- 模块编译:如果是commonJs不会有额外处理
- 我们来观察esModule和commmonJs的区别
1、esModule是对导出项的引用
即:
import {a} from './ref1.js'
console.log(a)
===>
var _ref1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
console.log(_ref1_js__WEBPACK_IMPORTED_MODULE_0__.a)
// 拿a来分析
模块中的a => 模块中导出:对exports设置a且设置getter:()=>(a) => 使用:importObj.a
// 1、设置getter:让其处于编译时候建立联系
// 2、没有setter:让其只读
// 3、模块中的a ==getter==> 使用中的a:导入项的引用
2、commonJs是对导出项的浅拷贝
const ref = require('./ref1.js')
console.log(ref.a)
=>
const ref = __webpack_require__(1)
console.log(ref.a)
// 1、导出对象{} ===> ref:也就是到处对象是导入对象的引用
整体理解:import是require的升级版:import是导出对象的项的引用(对比require是不是要更细致),require是导出对象的引用
// import是require的升级版
1、require是导出对象的引用,import是导出对象的项的引用
2、import通过getter实现编译时建立联系,而require是运行时建立联系(import会变量提升,在编译阶段就有完整的关系图,于是在使用导出对象使用时,使用getter完全ok。而require只是运行时加载,也就是编辑阶段没有完整的关系图,进而会出现循环引用问题)
3、import通过设置getter没有设置setter,进而控制该导出项不能修改,保证了原有模块的稳健。而require是导出对象的引用,而没有其它约束,进而具有破坏性,需要人为注意好不去破坏原有模块。
复制代码
- 导入模块逻辑-静态
__webpack_require__
复制代码
- 导入模块逻辑-动态:表达式
import(表达式)
require(表达式)
// 知识点:编译上下文content
// import()异步
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END





















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)