一堆的webpack配置教程看腻了?这里有webpack4的打包及加载机制,要不了解一下?
commonJs 的文件
// index.js
const name = require('./name.js');
console.log(name);
// name.js
module.exports = 'elson';
es module
import * as all from './name-es.js';
console.log(all);
window.all = all;
// name-es.js
export let obj = {a: 1, b: 2};
export function getName() {return 'elson';};
let name;
export default name = 'elson'
function run(modules) {
// 传入的参数为所有模块,key为路径名,val为模块function
var installedModules = {}
// The require function
function __webpack_require__(moduleId) {
// 检查是否存在模块
if (installedModules[moduleId]) {
return installedModules[moduleId].exports // 返回模块的exports对象
}
// Create a new module (and put it into the cache)
// 注册模块,key为moduleId
var module = (installedModules[moduleId] = {
i: moduleId, // 注册对象id
l: false, // 是否已加载模块
exports: {} // module.exports 对象,即commonjs中的导出方式
})
// Execute the module function
// 执行模块
modules[moduleId].call(
module.exports, // this传 exports
module, // 第一个值为模块
module.exports, // 第二个值为模块的exports
__webpack_require__ // 传入访问webpack_require方法,用于给模块提供require函数
)
// Flag the module as loaded
module.l = true
// Return the exports of the module
return module.exports
}
// expose the modules object (__webpack_modules__)
// 传入的模块指向m
__webpack_require__.m = modules
// expose the module cache
// 已注册号的模块指向c
__webpack_require__.c = installedModules
// define getter function for harmony exports
// 实现es6模块的动态绑定,模块export出来的每个接口,webpack编译后会为这些接口变量进行绑定
// 这样,注册好的模块内部变化都会反映在接口上
__webpack_require__.d = function(exports, name, getter) {
// 调用检查对象是否有属性校验,传入exports 和name
// 如果返回false,则为exports 对象写入namekey 并且绑定getter访问器属性
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
enumerable: true,
get: getter
})
}
} // define __esModule on exports
// 检查对象是否存在属性 // Object.prototype.hasOwnProperty.call
__webpack_require__.o = function(object, property) {
return Object.prototype.hasOwnProperty.call(object, property)
}
// 标识exports对象,支持es6 symbol就写为symbol,
// 否则写入key = __esModule ,用于标识export对象
__webpack_require__.r = function(exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: 'Module'
})
}
Object.defineProperty(exports, '__esModule', { value: true })
}
// create a fake namespace object
// mode & 1: value is a module id, require it
// mode & 2: merge all properties of value into the ns
// mode & 4: return value when already ns object
// mode & 8|1: behave like require
__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
}
// getDefaultExport function for compatibility with non-harmony modules
__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_public_path__
__webpack_require__.p = '' // Load entry module and return exports
// 设置入口
var entry = './index.js'
__webpack_require__.s = entry
return __webpack_require__(entry) // 执行入口id
}
/**
* webpack boost 启动流程
* 入参为模块对象集,对象属性为 模块名,即 路径名
* 匿名函数执行
* 1. 声明模块注册的对象
* 2. 声明require方法
* 3. 声明其他辅助函数
* 4. 设置入口模块参数,比如 index.js
* 5. 调用require方法,传入入口模块id,比如 index.js
* 6. 由入口模块开始执行整个流程,当遇到require 引入其他模块时,查找是否已注册
* 模块的key为文件路径名,模块为function,有自己的作用域,入参为 (module, exports, require)
* this 指向module.exports
* module 注册好的模块对象(即首次访问模块时会执行模块,并缓存到module中)
* exports module.exports
* require 方法 (用于访问模块,如果模块未注册会先执行注册流程,返回注册好的module.exports)
*
* 执行顺序:
* 传入入口的模块进行执行,模块内通过require方法(__webpack_require__) 访问其他模块
*
*/
// commonjs打包后的文件
const modules = {
// module 为注册模块是绑定的module对象,指向installedModules['./index.js']
// exports 指向module.exports
'./index.js': function(module, exports, __webpack_require__) {
// this 指向 module.exports
const name = __webpack_require__('./name.js') // 访问后拿到的是'./name.js'模块的注册后的module.exports对象
console.log(name)
},
'./name.js': function(module, exports) {
module.exports = 'elson'
}
}
// es module 模块打包后的文件
const esModules = {
'./index-es.js': function(module, __webpack_exports__, __webpack_require__) {
'use strict'
// Object.defineProperty 定义模块的exports为 es6模块
__webpack_require__.r(__webpack_exports__)
/* harmony import */
var _name_es_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
'./name-es.js'
)
console.log(_name_es_js__WEBPACK_IMPORTED_MODULE_0__)
window.all = _name_es_js__WEBPACK_IMPORTED_MODULE_0__
},
'./name-es.js':
/*! exports provided: obj, getName, default */
function(module, __webpack_exports__, __webpack_require__) {
'use strict'
__webpack_require__.r(__webpack_exports__)
// 定义exports的key为访问器属性, 返回对应的值
__webpack_require__.d(__webpack_exports__, 'obj', function() {
return obj
})
/* harmony export (binding) */
__webpack_require__.d(__webpack_exports__, 'getName', function() {
return getName
})
let obj = { a: 1, b: 2 }
function getName() {
return 'elson'
}
let name
// 定义default 对象接口属性
__webpack_exports__['default'] = name = 'elson'
}
}
// https://blog.elsonzhang.cn/2018/08/01/talk-about-webpack-bundle/