[webpack] webpack打包加载机制学习

一堆的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/

你可能感兴趣的:([webpack] webpack打包加载机制学习)