详解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函数ajax
Aug 20 Javascript
点击A元素触发B元素的事件在IE8下会识别成A元素
Sep 04 Javascript
javascript快速排序算法详解
Sep 17 Javascript
js实现将选中内容分享到新浪或腾讯微博
Dec 16 Javascript
AngularJS 指令的交互详解及实例代码
Sep 14 Javascript
Javascript 详解封装from表单数据为json串进行ajax提交
Mar 29 Javascript
jQuery中.attr()和.data()的区别分析
Sep 03 jQuery
jQuery Validate插件ajax方式验证输入值的实例
Dec 21 jQuery
vue 引入公共css文件的简单方法(推荐)
Jan 20 Javascript
React Navigation 使用中遇到的问题小结
May 08 Javascript
Angular异步变同步处理方法
Aug 13 Javascript
如何使用jQuery操作Cookies方法解析
Sep 08 jQuery
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
百事可乐也出咖啡了 双倍咖啡因双倍快乐
2021/03/03 咖啡文化
PHP脚本数据库功能详解(中)
2006/10/09 PHP
DISCUZ 论坛管理员密码忘记的解决方法
2009/05/14 PHP
php数字每三位加逗号的功能函数
2015/10/22 PHP
php 输出json及显示json中的中文汉字详解及实例
2016/11/09 PHP
浅谈PHP中如何实现Hook机制
2017/11/14 PHP
PHP使用curl_multi实现并发请求的方法示例
2018/04/29 PHP
使用PHP反射机制来构造"CREATE TABLE"的sql语句
2019/03/21 PHP
一个javascript参数的小问题
2008/03/02 Javascript
es6学习笔记之Async函数的使用示例
2017/05/11 Javascript
在vue-cli脚手架中配置一个vue-router前端路由
2017/07/03 Javascript
JavaScript实现简单生成随机颜色的方法
2017/09/21 Javascript
一个基于react的图片裁剪组件示例
2018/04/18 Javascript
使用koa-log4管理nodeJs日志笔记的使用方法
2018/11/30 NodeJs
Vue-input框checkbox强制刷新问题
2019/04/18 Javascript
js实现简单的点名器随机色实例代码
2020/09/20 Javascript
js实现鼠标切换图片(无定时器)
2021/01/27 Javascript
React服务端渲染原理解析与实践
2021/03/04 Javascript
Python深入学习之上下文管理器
2014/08/31 Python
Python2.x与Python3.x的区别
2016/01/14 Python
python matlibplot绘制3D图形
2018/07/02 Python
使用python批量修改文件名的方法(视频合并时)
2020/03/24 Python
推荐一些比较有用的css3新属性
2014/11/11 HTML / CSS
CSS3 按钮边框动画的实现
2020/11/12 HTML / CSS
牵手50香港:专为黄金岁月的单身人士而设的交友网站
2020/08/14 全球购物
高中生物教学反思
2014/02/05 职场文书
收银员岗位职责
2014/02/07 职场文书
元旦晚会策划方案
2014/02/18 职场文书
《识字五》教学反思
2014/03/01 职场文书
聚美优品陈欧广告词
2014/03/14 职场文书
文明演讲稿范文
2014/05/12 职场文书
三分钟自我介绍演讲稿
2014/08/21 职场文书
庆六一活动总结
2014/08/29 职场文书
关于教师节的广播稿
2015/08/19 职场文书
Spring JPA 增加字段执行异常问题及解决
2022/06/10 Java/Android
nginx七层负载均衡配置详解
2022/07/15 Servers