详解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 相关文章推荐
Mootools 1.2教程 输入过滤第一部分(数字)
Sep 15 Javascript
两个select之间option的互相添加操作(jquery实现)
Nov 12 Javascript
datagrid框架的删除添加与修改
Apr 08 Javascript
jquery遍历checkbox的注意事项说明
Feb 21 Javascript
创建自己的jquery表格插件
Nov 25 Javascript
js获取客户端操作系统类型的方法【测试可用】
May 27 Javascript
Javascript中常用类型的格式化方法小结
Dec 26 Javascript
详解vue-cli开发环境跨域问题解决方案
Jun 06 Javascript
详解Node 定时器
Feb 26 Javascript
angular6开发steps步骤条组件
Jul 04 Javascript
vue基于v-charts封装双向条形图的实现代码
Dec 09 Javascript
JavaScript canvas仿代码流瀑布
Feb 10 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
WAR3重制版DOTA 5V5初体验
2020/04/09 DOTA
基于mysql的论坛(6)
2006/10/09 PHP
确保Laravel网站不会被嵌入到其他站点中的方法
2019/10/18 PHP
简单JS代码压缩器
2006/10/12 Javascript
JavaScript 实现??打印?理
2007/04/28 Javascript
js随机颜色代码的多种实现方式
2013/04/23 Javascript
javascript/jquery获取地址栏url参数的方法
2014/03/05 Javascript
iframe里面的元素触发父窗口元素事件的jquery代码
2014/10/19 Javascript
jQuery获得指定元素坐标的方法
2015/04/14 Javascript
js如何实现淡入淡出效果
2020/11/18 Javascript
JS中的phototype详解
2017/02/04 Javascript
jQuery 循环遍历改变a标签的href(实例讲解)
2017/07/12 jQuery
vue实现导航栏效果(选中状态刷新不消失)
2017/12/13 Javascript
Angular 向组件传递模板的两种方法
2018/02/23 Javascript
H5+C3+JS实现双人对战五子棋游戏(UI篇)
2020/05/28 Javascript
ajax跨域访问遇到的问题及解决方案
2019/05/23 Javascript
通过图带你深入了解vue的响应式原理
2019/06/21 Javascript
非常实用的jQuery代码段集锦【检测浏览器、滚动、复制、淡入淡出等】
2019/08/08 jQuery
微信小程序实现点击页面出现文字
2020/09/21 Javascript
vue+openlayers绘制省市边界线
2020/12/24 Vue.js
[04:00]DOTA2解说界神雕侠侣 CJ第四天谷子现场过生日
2013/07/30 DOTA
[01:45]DOTA2众星出演!DSPL刀塔次级职业联赛宣传片
2014/11/21 DOTA
[10:18]2018DOTA2国际邀请赛寻真——找回自信的TNCPredator
2018/08/13 DOTA
Python最长公共子串算法实例
2015/03/07 Python
python中实现指定时间调用函数示例代码
2017/09/08 Python
python实现协同过滤推荐算法完整代码示例
2017/12/15 Python
Python字符串的一些操作方法总结
2019/06/10 Python
Python3视频转字符动画的实例代码
2019/08/29 Python
如何分离django中的媒体、静态文件和网页
2019/11/12 Python
基于Python实现人脸自动戴口罩系统
2020/02/06 Python
如何使用python写截屏小工具
2020/09/29 Python
详解Pymongo常用查询方法总结
2021/01/29 Python
详解如何解决H5开发使用wx.hideMenuItems无效果不生效
2021/01/20 HTML / CSS
小学教师师德反思
2014/02/03 职场文书
白莲教口号
2014/06/18 职场文书
关于mysql中时间日期类型和字符串类型的选择
2021/11/27 MySQL