详解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 相关文章推荐
一个JS的日期格式化算法示例
Jul 31 Javascript
使用GruntJS构建Web程序之合并压缩篇
Jun 06 Javascript
使用JavaScript和C#中获得referer
Nov 14 Javascript
在父页面得到zTree已选中的节点的方法
Feb 12 Javascript
Javascript非构造函数的继承
Apr 27 Javascript
JavaScript驾驭网页-CSS与DOM
Mar 24 Javascript
JS实现颜色动态淡化效果
Mar 06 Javascript
微信小程序冒泡事件及其阻止方法实例分析
Dec 06 Javascript
小程序云开发之用户注册登录
May 18 Javascript
layui动态渲染生成select的option值方法
Sep 23 Javascript
原生JavaScript实现留言板
Jan 10 Javascript
关于Vue Router的10条高级技巧总结
May 06 Vue.js
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中register_globals参数为OFF和ON的区别(register_globals 使用详解)
2012/02/05 PHP
php删除文件夹及其文件夹下所有文件的函数代码
2013/01/23 PHP
thinkPHP5.0框架配置格式、加载解析与读取方法
2017/03/17 PHP
一个不错的仿携程自定义数据下拉选择select
2014/09/01 Javascript
node.js中的fs.createWriteStream方法使用说明
2014/12/17 Javascript
jquery插件hiAlert实现网页对话框美化
2015/05/03 Javascript
jQuery实现页面评论栏中访客信息自动填写功能的方法
2016/05/23 Javascript
Vue.js实战之组件之间的数据传递
2017/04/01 Javascript
React Js 微信禁止复制链接分享禁止隐藏右上角菜单功能
2017/05/26 Javascript
Vue的MVVM实现方法
2017/08/16 Javascript
详解利用 Vue.js 实现前后端分离的RBAC角色权限管理
2017/09/15 Javascript
Vue组件通信之Bus的具体使用
2017/12/28 Javascript
vue-cli实现多页面多路由的示例代码
2018/01/30 Javascript
VUE 组件转换为微信小程序组件的方法
2019/11/06 Javascript
构建大型 Vue.js 项目的10条建议(小结)
2019/11/14 Javascript
vue实现导航标题栏随页面滚动渐隐渐显效果
2020/03/12 Javascript
移动端JS实现拖拽两种方法解析
2020/10/12 Javascript
python使用pymysql实现操作mysql
2016/09/13 Python
详解使用 pyenv 管理多个版本 python 环境
2017/10/19 Python
Python下载网络文本数据到本地内存的四种实现方法示例
2018/02/05 Python
Python使用MD5加密算法对字符串进行加密操作示例
2018/03/30 Python
python excel使用xlutils类库实现追加写功能的方法
2018/05/02 Python
详解Python3中ceil()函数用法
2019/02/19 Python
ubuntu 16.04下python版本切换的方法
2019/06/14 Python
Python tensorflow实现mnist手写数字识别示例【非卷积与卷积实现】
2019/12/19 Python
TensorFlow tf.nn.max_pool实现池化操作方式
2020/01/04 Python
Python Tensor FLow简单使用方法实例详解
2020/01/14 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
2020/02/11 Python
判断Threading.start新线程是否执行完毕的实例
2020/05/02 Python
python对接ihuyi实现短信验证码发送
2020/05/10 Python
市优秀教师事迹材料
2014/02/05 职场文书
交通事故死亡赔偿协议书
2014/12/03 职场文书
政协委员个人总结
2015/03/03 职场文书
考试后的感想
2015/08/07 职场文书
个人落户申请书怎么写?
2019/06/28 职场文书
2019XX公司员工考核管理制度!
2019/08/07 职场文书