详解webpack 最简打包结果分析


Posted in Javascript onFebruary 20, 2019

现在的 webpack 不再是入门噩梦,过去 webpack 最让人心塞的莫过于配置文件,而 webpack4 诞生随之而来的是无配置 webpack。

使用 webpack4,至少只需要安装 webpack 和 webpack cli。所以大家完全可以自己打一个最简单的包,还能修改插件对比前后的区别。

npm i webpack webpack-cli -D 安装后,因为 webpack4 会默认 src 为入口目录,所以先新建 src/index.js

// src/index.js
import { sth } from './shouldImport'
import other from './shouldImport'

let test = 'this is a variable'

export default {
 a: test + ',' + sth,
 other,
}

为了更了解 webpack  导入机制所以再新建 src/shouldImport.js。

// src/shouldImport.js
export let sth = 'something you need'

export default {
 others: '',
}

然后运行 node_modules/.bin/webpack --mode development 即可在 dist/main.js 看到打包后的文件。

但是默认设置中模块文件会被 eval 包裹导致不便查看,所以需要再在设置做一点修改,把 devtool 属性改为 'source-map'

// 在根目录新建 webpack.config.js 文件
module.exports = mode => {
 if (mode === 'production') {
  return {}
 }

 return {
  devtool: 'source-map',
 }
}

然后再打包应该就能看到类似一下的文件结构,开发环境下打包得到的文件自带注释,理解起来不难:

;(function(modules) {
 // webpackBootstrap
 // The module cache 模块缓存
 var installedModules = {}

 // The require function 请求函数
 function __webpack_require__(moduleId) {
  // Check if module is in cache
  // 检查模块是否在缓存
  if (installedModules[moduleId]) {
   return installedModules[moduleId].exports
  }
  // Create a new module (and put it into the cache)
  // 创建新模块并放进缓存
  var module = (installedModules[moduleId] = {
   i: moduleId,
   l: false,
   exports: {},
  })

  // Execute the module function
  // 执行模块函数(有点不懂为什么 this 要传入 module.exports)
  modules[moduleId].call(
   module.exports, // this
   module, // 模块对象本身
   module.exports, // 模块对象的 exports 属性
   __webpack_require__ // 请求函数最终返回模块输出,传入用于请求其他模块
  )

  // Flag the module as loaded
  // 加载完成标志
  module.l = true

  // Return the exports of the module
  // 返回模块的输出
  return module.exports
 }

 // expose the modules object (__webpack_modules__)
 // 暴露所有模块对象
 __webpack_require__.m = modules

 // expose the module cache
 // 暴露模块缓存
 __webpack_require__.c = installedModules

 // Object.prototype.hasOwnProperty.call
 __webpack_require__.o = function(object, property) {
  return Object.prototype.hasOwnProperty.call(object, property)
 }

 // define getter function for harmony exports
 // 为 ES6 export 定义 getter 函数
 __webpack_require__.d = function(exports, name, getter) {
  if (!__webpack_require__.o(exports, name)) {
   // 检查属性是否存在
   Object.defineProperty(exports, name, { enumerable: true, get: getter })
  }
 }

 // define __esModule on exports
 // 于 export 定义 __esModule
 __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
 // value 是模块 id,必要
 // mode & 2: merge all properties of value into the ns
 // 合并 value 所有属性到 ns
 // mode & 4: return value when already ns object
 // ns 已经是对象时返回 value
 // mode & 8|1: behave like require
 // 表现如 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
 // 用于兼容非 ES6 模块的 getDefaultExport 函数
 __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
 // 加载入口模块并返回 export
 return __webpack_require__((__webpack_require__.s = './src/index.js'))
})({
 './src/index.js':
  /*! exports provided: default */
  function(module, __webpack_exports__, __webpack_require__) {
   'use strict'
   __webpack_require__.r(__webpack_exports__) // 于 export 定义 __esModule
   /* harmony import */
   var _shouldImport__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
    './src/shouldImport.js'
   )

   let test = 'this is a variable'

   /* harmony default export */

   __webpack_exports__['default'] = {
    a: test + ',' + _shouldImport__WEBPACK_IMPORTED_MODULE_0__['sth'],
    other: _shouldImport__WEBPACK_IMPORTED_MODULE_0__['default'],
   }
  },

 './src/shouldImport.js':
  /*! exports provided: sth, default */
  function(module, __webpack_exports__, __webpack_require__) {
   'use strict'
   __webpack_require__.r(__webpack_exports__)
   /* harmony export (binding) */

   __webpack_require__.d(__webpack_exports__, 'sth', function() {
    return sth
   })
   let sth = 'something you need'

   __webpack_exports__['default'] = {
    others: '',
   }
  },
})

源文件中的所有 import export 都会转换为对应的辅助函数。

  • import 对应 __webpack_require__
  • export 对应 __webpack_exports__['default'] 直接赋值和 __webpack_require__.d。

整理一下整个流程:

  1. 定义 __webpack_require__ 及其辅助函数
  2. 使用 __webpack_require__ 引入入口模块
  3. __webpack_require__ 函数载入模块,将模块放到模块缓存
  4. 调用模块
    1. 同样使用 __webpack_require__ 读取依赖(回到第 3 步)
    2. 运行模块内部功能
    3. 使用 __webpack_exports__['default'] 直接赋值和 __webpack_require__.d 输出
  5. 运行结束

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
游览器中javascript的执行过程(图文)
May 20 Javascript
javascript中的变量作用域以及变量提升详细介绍
Oct 24 Javascript
JS判断两个时间大小的示例代码
Jan 28 Javascript
jQuery中ajax的load()方法用法实例
Dec 26 Javascript
javascript html5实现表单验证
Mar 01 Javascript
深入理解JS继承和原型链的问题
Dec 17 Javascript
Angular2 自定义validators的实现方法
Jul 05 Javascript
js代码规范之Eslint安装与配置详解
Sep 08 Javascript
vue计算属性get和set用法示例
Feb 08 Javascript
使用vue构建多页面应用的示例
Oct 22 Javascript
js实现简单的倒计时
Jan 28 Javascript
关于better-scroll插件的无法滑动bug(2021通过插件解决)
Mar 01 Javascript
jQuery表单元素过滤选择器用法实例分析
Feb 20 #jQuery
jQuery内容过滤选择器与子元素过滤选择器用法实例分析
Feb 20 #jQuery
小程序红包雨的实现示例
Feb 19 #Javascript
vue动态添加路由addRoutes之不能将动态路由存入缓存的解决
Feb 19 #Javascript
jQuery选择器之基本过滤选择器用法实例分析
Feb 19 #jQuery
Vue 实现手动刷新组件的方法
Feb 19 #Javascript
jQuery选择器之层次选择器用法实例分析
Feb 19 #jQuery
You might like
PHP.MVC的模板标签系统(三)
2006/09/05 PHP
浅谈PHP正则表达式中修饰符/i, /is, /s, /isU
2014/10/21 PHP
php使用Jpgraph绘制复杂X-Y坐标图的方法
2015/06/10 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
很多人都是用下面的js刷新站IP和PV
2008/09/05 Javascript
一个很简单的jquery+xml+ajax的无刷新树结构(无css,后台是c#)
2010/06/02 Javascript
js 动态文字滚动的例子
2011/01/17 Javascript
前端开发过程中浏览器版本的两种判定方法
2013/10/30 Javascript
javascript 循环调用示例介绍
2013/11/20 Javascript
jquery.validate.js插件使用经验记录
2014/07/02 Javascript
javascript数组排序汇总
2015/07/07 Javascript
JS点击某个图标或按钮弹出文件选择框的实现代码
2016/09/27 Javascript
微信小程序开发之大转盘 仿天猫超市抽奖实例
2016/12/08 Javascript
使用jQuery ajaxupload插件实现无刷新上传文件
2017/04/23 jQuery
ES6中的rest参数与扩展运算符详解
2017/07/18 Javascript
使用bootstraptable插件实现表格记录的查询、分页、排序操作
2017/08/06 Javascript
微信小程序开发(二):页面跳转并传参操作示例
2020/06/01 Javascript
Python使用函数默认值实现函数静态变量的方法
2014/08/18 Python
跟老齐学Python之有点简约的元组
2014/09/24 Python
python使用urllib2提交http post请求的方法
2015/05/26 Python
Django框架下在视图中使用模版的方法
2015/07/16 Python
python实现数据写入excel表格
2018/03/25 Python
python使用RNN实现文本分类
2018/05/24 Python
Python3.6.0+opencv3.3.0人脸检测示例
2018/05/25 Python
Python 多线程不加锁分块读取文件的方法
2018/12/11 Python
Python3日期与时间戳转换的几种方法详解
2019/06/04 Python
Python获取命令实时输出-原样彩色输出并返回输出结果的示例
2019/07/11 Python
学习雷锋精神演讲稿
2014/05/10 职场文书
应届生面试求职信
2014/07/02 职场文书
义务教育学校标准化建设汇报材料
2014/08/16 职场文书
考试保密承诺书
2014/08/30 职场文书
教师文明餐桌光盘行动倡议书
2015/04/28 职场文书
村主任当选感言
2015/08/01 职场文书
2019大学生实习报告
2019/06/21 职场文书
MySQL深度分页(千万级数据量如何快速分页)
2021/07/25 MySQL
mysql 8.0.27 绿色解压版安装教程及配置方法
2022/04/20 MySQL