先不进源码,分析一下打包后的文件,来一张图:

  

  首先创建两个JS文件,内容如下:

// config.js
module.exports = {
entry: './input.js',
output: {
filename: 'output.js'
}
}
// input.js
console.log('input')

  分别为配置文件和入口JS文件,内容弄个简单的。

  接下来在当前目录执行webpack --config config.js,会输出一个output.js,简化后内容如下:

(function(modules) { // webpackBootstrap
// 模块缓存对象
var installedModules = {}; function __webpack_require__(moduleId) { // 加载入口JS // 输出
return module.exports;
} // 挂载模块数组
__webpack_require__.m = modules;
// ...
// 在__webpack_require__挂载多个属性 // 传入入口JS模块ID执行函数并输出模块
return __webpack_require__(__webpack_require__.s = 0);
});
// 包含所有模块的数组
([
/* id为0 */
(function(module, exports) {
console.log('1')
})
]);

  可以看到,这是一个IIFE,可以利用闭包来对模块进行缓存以及其余便利性的功能。

  整个JS可以分为三块:

1、传入包含所有模块的数组,每一个模块有唯一的标识ID

2、模块输出函数

3、在函数上挂载多个属性

__webpack_require__
  
  函数代码如下:
// 传入入口文件的模块ID
function __webpack_require__(moduleId) {
// 检测缓存
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 无缓存时创建新的模块
// i => 模块ID
// l => 是否被加载
// exports => 输出内容
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
// 执行模块函数
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 标记模块已被加载
module.l = true;
// 返回模块输出
return module.exports;
}

  入口文件的模块ID会当成参数传入该函数,首先会进行缓存检测,没找到会生成一个新的模块对象,然后执行入口模块,将该模块标记为已加载后返回对应的exports。

  由于被打包的文件内容十分简单,所以只会执行console语句。

__webpack_require__属性挂载

  由于函数也是对象,所以可以在上面添加属性,具体代码如下:

// 模块数组
__webpack_require__.m = modules;
// 模块缓存
__webpack_require__.c = installedModules;
// 属性判断
__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// 如果不存在对应属性 定义输出的getter
__webpack_require__.d = function(exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
// 默认模块
__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 = "";

  挂载了6个属性,模块组、缓存对象、属性检测方法、getter定义、默认模块、公共路径.

  这里的getter稍微解释一下,module的引入模块有两种输出模式,一种是webpack定义的module.exports,另一种是ES定义的export default,这里就是判断是哪一种方式。默认情况下当然是module.exports获取模块输出内容。但是用ES的方式,模块输出会被包裹在一个default对象,此时需要用module['default']来获取。

  接下来弄复杂一些再观察,配置文件不变,改变入口JS并添加一个依赖JS:

// require,js
module.exports = function require() {
console.log('require');
}
// input.js
import rq from "./require.js"
rq();

  简单的实现一个JS加载另外一个JS,接下来执行打包。

  打包后主处理函数不会变,传入的模块数组发生了变化,代码如下:

(function(modules) {
// ...
return __webpack_require__(__webpack_require__.s = 0);
})
([
/* 0 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */
var __WEBPACK_IMPORTED_MODULE_0__require_js__ = __webpack_require__(1);
/* harmony import */
var __WEBPACK_IMPORTED_MODULE_0__require_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__require_js__);
__WEBPACK_IMPORTED_MODULE_0__require_js___default()()
}),
/* 1 */
(function(module, exports) {
module.exports = function require() {
console.log('require');
}
})
]);

  这里的模块数组出现了2个,但是入口的JS仍然只有1个,ID为0,被依赖的ID为1。

  可以注意到,module、exports分别对应函数的2个参数,而在主处理函数中exports就是输出的模块内容,所以这就是为什么打包函数都是通过module.exports来输出模块内容。

  这里仔细看一下ID为0的入口模块:

/* 0 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
// 定义该模块的exports的__esModule属性为true
// 该属性影响__webpack_require__.n的输出
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
// 获取ID为1的模块
var __WEBPACK_IMPORTED_MODULE_0__require_js__ = __webpack_require__(1);
// 这里传入了模块1并调用了__webpack_require__.n
// 模块1并没有被标记__esModule
// 返回函数function getModuleExports() { return module; };
var __WEBPACK_IMPORTED_MODULE_0__require_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__require_js__);
// 注意这里的module并不是模块的module对象 而是传入函数n的参数
// 所以这里的调用相当于__webpack_require__(1)() => (function require() {console.log('require');})()
__WEBPACK_IMPORTED_MODULE_0__require_js___default()()
}),

  由于案例比较简单,所以虽然变量名很长,但是也非常好懂,引入依赖JS后,判断模块的输出模式,然后执行输出代码。

  暂时先写这么多。

.2-浅析webpack源码之打包后文件的更多相关文章

  1. 从Webpack源码探究打包流程,萌新也能看懂~

    简介 上一篇讲述了如何理解tapable这个钩子机制,因为这个是webpack程序的灵魂.虽然钩子机制很灵活,而然却变成了我们读懂webpack道路上的阻碍.每当webpack运行起来的时候,我的心态 ...

  2. .16-浅析webpack源码之编译后流程梳理

    这节把编译打包后的流程梳理一下,然后集中处理compile. 之前忽略了一个点,如下: new NodeEnvironmentPlugin().apply(compiler); // 引入插件加载 i ...

  3. .35-浅析webpack源码之babel-loader入口文件路径读取

    在处理./input.js入口文件时,在类型判断被分为普通文件,所以走的文件事件流,最后拼接得到文件的绝对路径. 但是对应"babel-loader"这个字符串,在如下正则中被判定 ...

  4. .3-浅析webpack源码之预编译总览

    写在前面: 本来一开始想沿用之前vue源码的标题:webpack源码之***,但是这个工具比较巨大,所以为防止有人觉得我装逼跑来喷我(或者随时鸽),加上浅析二字,以示怂. 既然是浅析,那么案例就不必太 ...

  5. .20-浅析webpack源码之compile流程-Template模块

    这里的编译前指的是开始触发主要的事件流this-compilaiton.compilation之前,由于还有一些准备代码,这一节全部弄出来. 模块基本上只走构造函数,具体的方法调用的时候再具体讲解. ...

  6. .17-浅析webpack源码之compile流程-入口函数run

    本节流程如图: 现在正式进入打包流程,起步方法为run: Compiler.prototype.run = (callback) => { const startTime = Date.now( ...

  7. .30-浅析webpack源码之doResolve事件流(1)

    这里所有的插件都对应着一个小功能,画个图整理下目前流程: 上节是从ParsePlugin中出来,对'./input.js'入口文件的路径做了处理,返回如下: ParsePlugin.prototype ...

  8. .39-浅析webpack源码之parser.parse

    因为换了个工作,所以博客停了一段时间. 这是上个月留下来的坑,webpack的源码已经不太想看了,又臭又长,恶心的要死,想去看node的源码……总之先补完这个 上一节完成了babel-loader对J ...

  9. .34-浅析webpack源码之事件流make(3)

    新年好呀~过个年光打游戏,function都写不顺溜了. 上一节的代码到这里了: // NormalModuleFactory的resolver事件流 this.plugin("resolv ...

随机推荐

  1. unidbgrid显示列的合计值

    procedure TfrmClient.UniDBGrid1ColumnSummaryResult(Column: TUniDBGridColumn; GroupFieldValue: Varian ...

  2. 关于质能等效的两个思想实验 Two Ideological Experiments on Mass-Energy Equivalence

    大家知道,物质和能量是等效的,虽然质能方程已暗示了这种等效关系,但并非显而易见.此等效性可以从以下两个思想实验中获知. 实验一:一台电子称上放置一个金属物体,加热它,称的读数将会略微增加.这是因为金属 ...

  3. Windows 7 系统中开启 ASP.NET State Service 服务的方法

    控制面板 -> 程序和功能 -> “打开或者关闭 Windows 功能”对话框 -> Internet 信息服务 -> 万维网服务 -> 应用程序开发功能 -> A ...

  4. play framework - 初识

    背景 研发代码框架是play-framework框架,想看代码的话,需要学习下play框架.IDE工具的话之前一直用的idea,所以本文涉及的idea play的配置 和 一些play的简单知识 认识 ...

  5. Ocelot入门实践

    博主是第一次写技术文档,一是对这两年工作以来的一些技术和经验进行整理,二也是希望能和大家多多分享交流,如有写的不对的地方望大家多多指正.进入正题 Ocelot 概念就不说了,大家自行百度,今天做一个O ...

  6. ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下

    先简单了解一这个几个 名词的意思. 控制反转(IOC) 依赖注入(DI) 并不是某种技术. 而是一种思想.一种面向对象编程法则 什么是控制反转(IOC)?  什么是依赖注入(DI) 可以点击下面链接 ...

  7. Python 读取文件中unicode编码转成中文显示问题

    Python读取文件中的字符串已经是unicode编码,如:\u53eb\u6211,需要转换成中文时有两种方式 1.使用eval: eval("u"+"\'" ...

  8. 07_python_集合深浅拷贝

    一.join li = ["李嘉诚", "麻花藤", "林海峰", "刘嘉玲"] s = "_".j ...

  9. phpMyadmin提权那些事

    i春秋作家:anyedt phpMyadmin提权那些事 引言:在渗透测试过程中获知到phpMyadmin的账号密码,如何进行提权呢?往下看,我今天和你说说phpMyadmin提权那些事. 0×00 ...

  10. spring mvc开发过程中的乱码问题

    在保证jsp,xml,数据库,编辑器编码一致的情况下. 1,用户输入中文,后台接收到也是中文,但是保存到数据库时乱码, 解决方法: 链接数据库的url="jdbc:mysql://local ...