webpack编译后源码分析
分模块
- 定义缓存模块的数组为空
- 有一个起始模块执行
- 当请求(require)起始模块时,查找缓存是否存在,不存在需要从模块列表加载并缓存,并且通过call传递
module
,exports
,__webpack_require__
// 01 自执行
(function (modules) {
// 02 require缓存
var installedModules = {}
// 03 require函数封装
function __webpack_require__(moduleId) {
// 05 判断缓存
if (installedModules[moduleId]) {
return installedModules[moduleId].exports
}
// 06 封装需要传递到模块的module,export,require
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
}
// 07 call调用模块函数
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
module.l = true
return module.exports
}
__webpack_require__.m = modules
__webpack_require__.c = installedModules
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
enumerable: true,
get: getter
})
}
}
__webpack_require__.r = function (exports) {
if (typeof Symbol !== ‘undefined‘ && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: ‘Module‘
})
}
Object.defineProperty(exports, ‘__esModule‘, {
value: true
})
}
__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
}
__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
}
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty.call(object, property)
}
__webpack_require__.p = ‘‘
// 04 起始模块启动
return __webpack_require__(__webpack_require__.s = ‘A7Gu‘)
})({
‘A7Gu‘: (function (module, exports, __webpack_require__) {
// 08 请求react,react-dom
var React = __webpack_require__(‘u6V5‘)
var ReactDom = __webpack_require__(‘I7V5‘)
// 09 起始方法的内容执行
var app = React.createElement(‘div‘, {
id: ‘app‘,
onClick: function () {
alert(‘message‘)
}
}, ‘\u4ECA\u5929\u5929\u6C14\u4E0D\u597D‘)
ReactDom.render(app, document.getElementById(‘app‘))
}),
‘u6V5‘: (function (module, exports, __webpack_require__) {
var react = {
createElement(type, attrs, children) {
return { type, attrs, children }
}
}
module.exports = react
}),
‘I7V5‘: (function (module, exports, __webpack_require__) {
var ReactDom = {
render({ attrs }, container) {
let ele = document.createElement(element.type)
for (var attr in attrs) {
if (attr === ‘onClick‘) {
ele.onclick = attrs[attr]
} else {
ele.setAttribute(attr, attrs[attr])
}
}
if (typeof element.children === ‘string‘) {
let text = document.createTextNode(element.children)
ele.appendChild(text)
}
if (container) {
container.appendChild(ele)
} else {
document.body.appendChild(ele)
}
}
}
module.exports = ReactDom
})
})
异步加载
- 在上面的前提上
- 当异步加载时,包装成promise方式,then之后require模块
- 包装script标签加载
- 请求完成自执行,添加到异步缓存标记表示已经加载(当下次异步请求直接返回)
- 然后放到模块列表中,之后执行resove()到then中
- then中在require模块,添加到缓存并传递module,export,require call调用当前函数
- 产生闭包,后面使用模块下面的函数,属性即可
下面标记async是表示,和上面的区别
// main.js
(function (modules) {
var installedModules = {}
/*async*/ // 01 异步标记缓存
var installedChunks = {
‘main‘: 0 // main是起始,可以删除
}
/*async*/
function webpackJsonpCallback(data) {
// 05 push到这里
var chunkIds = data[0]
var moreModules = data[1]
var moduleId, chunkId, i = 0, resolves = []
// 06 异步加载的模块可以是多个
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i]
if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
// 07 promise的resolve
resolves.push(installedChunks[chunkId][0])
}
installedChunks[chunkId] = 0
}
for (moduleId in moreModules) {
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
// 08 缓存到模块列表
modules[moduleId] = moreModules[moduleId]
}
}
if (parentJsonpFunction) parentJsonpFunction(data)
// 09 依次调用resove,即then的逻辑
while (resolves.length) {
resolves.shift()()
}
}
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
}
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
module.l = true
return module.exports
}
__webpack_require__.m = modules
__webpack_require__.c = installedModules
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
enumerable: true,
get: getter
})
}
}
/*async*/
function jsonpScriptSrc(chunkId) {
return __webpack_require__.p + ‘‘ + ({}[chunkId] || chunkId) + ‘.js‘
}
/*async*/
__webpack_require__.e = function requireEnsure(chunkId) {
var promises = []
var installedChunkData = installedChunks[chunkId]
if (installedChunkData !== 0) {
if (installedChunkData) {
promises.push(installedChunkData[2])
} else {
// 03 创建promise
var promise = new Promise(function (resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject]
})
promises.push(installedChunkData[2] = promise)
// 04 创建script标签,请求
var script = document.createElement(‘script‘)
var onScriptComplete
script.charset = ‘utf-8‘
script.timeout = 120
if (__webpack_require__.nc) {
script.setAttribute(‘nonce‘, __webpack_require__.nc)
}
script.src = jsonpScriptSrc(chunkId)
var error = new Error()
onScriptComplete = function (event) {
// 10 收尾
script.onerror = script.onload = null
clearTimeout(timeout)
var chunk = installedChunks[chunkId]
if (chunk !== 0) {
if (chunk) {
var errorType = event && (event.type === ‘load‘ ? ‘missing‘ : event.type)
var realSrc = event && event.target && event.target.src
error.message = ‘Loading chunk ‘ + chunkId + ‘ failed.\n(‘ + errorType + ‘: ‘ + realSrc + ‘)‘
error.name = ‘ChunkLoadError‘
error.type = errorType
error.request = realSrc
chunk[1](error)
}
installedChunks[chunkId] = undefined
}
}
var timeout = setTimeout(function () {
onScriptComplete({ type: ‘timeout‘, target: script })
},120000)
script.onerror = script.onload = onScriptComplete
document.head.appendChild(script)
}
}
return Promise.all(promises)
}
__webpack_require__.r = function (exports) {
if (typeof Symbol !== ‘undefined‘ && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: ‘Module‘
})
}
Object.defineProperty(exports, ‘__esModule‘, {
value: true
})
}
__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
}
__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
}
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty.call(object, property)
}
__webpack_require__.p = ‘‘
/*async*/
__webpack_require__.oe = function (err) {
console.error(err)
throw err
}
var jsonpArray = window[‘webpackJsonp‘] = window[‘webpackJsonp‘] || []
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray)
jsonpArray.push = webpackJsonpCallback
jsonpArray = jsonpArray.slice()
for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i])
var parentJsonpFunction = oldJsonpFunction
return __webpack_require__(__webpack_require__.s = ‘A7Gu‘)
})({
‘A7Gu‘: (function (module, exports, __webpack_require__) {
var React = __webpack_require__(‘u6V5‘)
var ReactDom = __webpack_require__(‘I7V5‘)
var htdiv = React.createElement(‘div‘, {
id: ‘my‘,
onClick: function () {
// 02 包装,请求异步模块,完成之后在require
__webpack_require__.e(0).then((function () {
var A = __webpack_require__(‘46Hr‘)
A.log(‘哈哈哈‘)
alert(A.message)
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe)
}
},‘\u4ECA\u5929\u5929\u6C14\u4E0D\u597D‘)
ReactDom.render(htdiv, document.getElementById(‘app‘))
}),
‘u6V5‘: (function (module, exports, __webpack_require__) {
var react = {
createElement(type, attrs, children) {
return { type, attrs, children }
}
}
module.exports = react
}),
‘I7V5‘: (function (module, exports, __webpack_require__) {
var ReactDom = {
render(element, container) {
let ele = document.createElement(element.type)
for (var attr in element.attrs) {
if (attr === ‘onClick‘) {
ele.onclick = element.attrs[attr]
} else {
ele.setAttribute(attr, element.attrs[attr])
}
}
if (typeof element.children === ‘string‘) {
let text = document.createTextNode(element.children)
ele.appendChild(text)
}
if (container) {
container.appendChild(ele)
} else {
document.body.appendChild(ele)
}
}
}
module.exports = ReactDom
})
})
// 0.js
// 04 push操作
(window[‘webpackJsonp‘] = window[‘webpackJsonp‘] || []).push([[0], {
‘46Hr‘: (function (module, exports) {
var A = {
log() {
console.log(...arguments)
},
message: ‘hello ‘
}
module.exports = A
})
}])