// 文件a:入口文件
import {b1,sayB} from './b.js'
export var a1 = 100;
setTimeout(()=>{a1 = 101},1000)
export function sayA(){
console.log('a.js sayA',b1,sayB)
}
var a2 = 100;
export default a2
// 文件b
import {sayC} from './c.js'
export var b1 = 200;
setTimeout(()=>{b1 = 201},1000)
export function sayB(){
console.log('a.js sayB',sayC)
}
var b2 = 100;
export default b2
// 文件c
import {sayB} from './b.js'
export var c1 = 300;
setTimeout(()=>{c1 = 301},1000)
export function sayC(){
console.log('a.js sayC',sayB);
}
var c2 = 100;
export default c2
webpack编译后:
(() => {
// 存放依赖的模块,就是所有通过import导入的文件都会保存在这,我们书写的模块带码会被编译成函数,以url为key保存在__webpack_modules__对象上
var __webpack_modules__ = {
// 模块b文件的代码,导出对象都是我们执行函数时传入的
"./src/b.js":(__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
// 1.往导出对象__webpack_exports__上绑定我们导出的内容
__webpack_require__.d(__webpack_exports__, {
b1: () => (/* binding */ b1),
sayB: () => (/* binding */ sayB),
"default": () => (__WEBPACK_DEFAULT_EXPORT__),
});
// 2.有依赖则加载依赖模块
var _c_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./c.js */ "./src/c.js");
// 3. 等依赖加载完成再,执行模块代码
var b1 = 200;
setTimeout(function () {
b1 = 201;
}, 1000);
function sayB() {
console.log('a.js sayB', _c_js__WEBPACK_IMPORTED_MODULE_1__.sayC);
}
var b2 = 100;
const __WEBPACK_DEFAULT_EXPORT__ = (b2);
},
// 模块c文件的代码,导出对象都是我们执行函数时传入的
"./src/c.js":(__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
// 1.往导出对象__webpack_exports__上绑定我们导出的内容
__webpack_require__.d(__webpack_exports__, {
c1: () => (/* binding */ c1),
sayC: () => (/* binding */ sayC),
"default": () => (__WEBPACK_DEFAULT_EXPORT__),
});
// 2.有依赖则加载依赖模块
var _b_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./b.js */ "./src/b.js");
// 3. 等依赖加载完成再,执行模块代码
var c1 = 300;
setTimeout(function () {
c1 = 301;
}, 1000);
function sayC() {
console.log('a.js sayC', _b_js__WEBPACK_IMPORTED_MODULE_1__.sayB);
}
var c2 = 100;
const __WEBPACK_DEFAULT_EXPORT__ = (c2);
}
}
// 缓存模块的导出对象{"./src/a.js":{exports:{}}}
var __webpack_module_cache__ = {};
// 加载模块:读取缓存__webpack_module_cache__[url],有缓存有则直接返回对应值,没有缓存则执行模块代码__webpack_modules__[url],然后将导出内容缓存
function __webpack_require__(moduleId) {
// 1.查找缓存,有则直接返回缓存的导出对象
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// 2.没有缓存则创建一个导出对象exports
var module = __webpack_module_cache__[moduleId] = {
exports: {}
};
// 3.传入创建的导出对象exports,执行模块对应的函数
// 1.往导出对象exports上绑定我们导出的内容,通过Object.defineProperty(__webpack_exports__,key,{get(){xxx}})设置get,
// 2.有依赖文件则递归加载文件模块
// 3.等依赖加载完成再,再执行模块代码
__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 4.返回导出对象
return module.exports;
}
// 入口文件的代码:
// 1.创建一个导出对象
var __webpack_exports__ = {};
__webpack_require__.r(__webpack_exports__);
//2.往导出对象上绑定导出内容,通过Object.defineProperty(__webpack_exports__,key,{get(){xxx}})设置get
__webpack_require__.d(__webpack_exports__, {
a1: () => (/* binding */ a1),
sayA: () => (/* binding */ sayA),
"default": () => (__WEBPACK_DEFAULT_EXPORT__),
});
// 3.有依赖则加载依赖模块,__webpack_require__(moduleId:url)
var _b_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./b.js */ "./src/b.js");
// 4.执行模块代码
var a1 = 100;
setTimeout(function () {
a1 = 101;
}, 1000);
function sayA() {
console.log('a.js sayA', _b_js__WEBPACK_IMPORTED_MODULE_1__.b1, _b_js__WEBPACK_IMPORTED_MODULE_1__.sayB);
},
var a2 = 100;
const __WEBPACK_DEFAULT_EXPORT__ = (a2);
})()
我们在a.js中导入了b.js import {b1,sayB} from './b.js'
我们在b.js中导入了c.js import {sayC} from './c.js'
我们在c.js中导入了b.js import {sayB} from './b.js'
只要被任何一个import 导入过的js文件(例如这里的b.js、c.js)代码都会被编译成函数保存__webpack_modules__:{}对象上,通过__webpack_require__()函数来加载模块
没有被任何文件import 导入过的js文件(一般是入口文件,例如这里的a.js)则不会被编译成函数,代码直接在自执行函数内执行
入口文件会被webpack编译成一个自执行的函数(() => { 这里放模块相关的代码})()
模块相关的代码:
存放依赖的模块: var webpack_modules = {url:(module,exports,webpack_require)=>{模块代码}}
缓存模块导出对象: var webpack_module_cache = {"./src/a.js":{exports:{}}};
加载模块的函数: function webpack_require(moduleId) {}
// 入口文件的代码: 1.创建一个导出对象__webpack_exports__={};
2.往导出对象上绑定导出内容,通过Object.defineProperty(webpack_exports,key,{get(){xxx}})设置get 3.是否有依赖文件,没有则直接进入到下一步,有则递归加载文件模块,通过__webpack_require__(moduleId:url),加载执行完成才会进入到下一步;
1.查找缓存__webpack_module_cache__[moduleId:url],有则直接返回缓存的导出对象exports
2.没有缓存则创建一个空导出对象exports={},保存到__webpack_module_cache__[moduleId]={exports:{}}上
3.传入新创建的导出对象exports,执行模块对应的函数__webpack_modules__[moduleId].call(exports)
1.往导出对象exports上绑定我们导出的内容,通过Object.defineProperty(webpack_exports,key,{get(){xxx}})设置get,
2.是否有依赖文件,没有则直接进入到下一步,有则递归加载文件模块,通过__webpack_require__(moduleId:url),加载执行完成才会进入到下一步;
3.执行模块代码
4.执行模块代码
所以代码的执行顺序是深度优先的,先执行c.js===>在执行b.js===>最后执行a.js
文件b.js和文件c.js是循环引用的为什么不会栈溢出报错?
在执行a.js时我们第一次加载b.js,此时缓存__webpack_module_cache__中不存在b.js的导出对象,则会执行b.js对应的函数modelB(),函数执行时会先去加载c.js, 此时缓存__webpack_module_cache__中不存在c.js的导出对象,则会执行c.js对应的函数modelC(),函数modelC中我们第二次加载b.js,这时会直接读取__webpack_module_cache__缓存中的值直接返回, 如果没有缓存值判断,则会一直循环调用直到栈溢出。这里使用缓存后则不会再去执行b.js对应的函数modelC(),这样就可以避免的循环调用。
export 和export default 导出的值是不一样的,export导出的是值的引用(导入和导出使用的是导出文件中的同一个变量),export default导出的是值的拷贝(导出文件中的变量,与导入文件使用的是不同的变量)