解读webpack的bundle.js
可能就是好奇心略重了,读了一下webpack打包后的bundle.js的代码,复杂的模块可能读不懂,但简单的hello world模块我还是能看懂的。没什么目的,就是想通过几个简单的模块,一条简单的webpack命令,一个神奇的bundle.js代码来了解webpack是怎么把遵循commonJs规范的模块应用到浏览器端的。
几个简单的模块:
一条简单的webpack命令:
一个神奇的bundle.js:
/******/ (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] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ }; /******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded
/******/ module.loaded = 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; /******/ // __webpack_public_path__
/******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) { /*
打印文本的index模块
*/
var text = __webpack_require__(1);
console.log(text); /***/ },
/* 1 */
/***/ function(module, exports) { /*
生成文本的Hello world模块
*/
module.exports = 'Hello world!'; /***/ }
/******/ ]);
注释太多有点懵逼,可是细看也不就是一个立即执行的函数表达式嘛(IIFE),这是JavaScript中常见的独立作用域的方法。这里我将注释简化一下:
(function(modules){
//module缓存对象
var installedModules = {};
//require函数
function __webpack_require__(moduleId){
//检查module是否在cache中
if(installedModules[moduleId]){
return installedModules[moduleId].exports;
}
//若不在cache中则新建module并放入cache中
var module = installedModules[moduleId] = {
exports: {},
id: moduleId,
loaded: false
};
//执行module函数
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
//标记module已经加载
module.loaded = true;
//返回module的导出模块
return module.exports;
} //暴露modules对象(__webpack_modules__)
__webpack_require__.m = modules;
//暴露modules缓存
__webpack_require__.c = installedModules;
//设置webpack公共路径__webpack_public_path__
__webpack_require__.p = "";
//读取入口模块并且返回exports导出
return __webpack_require__(0); })([function(module, exports, __webpack_require__){ /*模块Id为0*/
var text = __webpack_require__(1);
console.log(text);
},function(module, exports){ /*模块Id为1*/
module.exports = 'Hello world';
}]);
这个IIFE接收一个数组作为参数modules,数组的每一项都是一个匿名函数代表一个模块(index.js和hello.js模块)。可是为什么构建命令中只出现了“index.js"呢,这是因为webpack通过静态分析index.js文件得到语法树,递归检测index.js所依赖的模块,以及依赖的依赖,入口模块和所有的依赖模块作为数组中的项,并合并到最终的代码中。
正是由于模块代码被包装成函数后,每个模块的运行时机变的可控,可以决定何时调用(通过 modules[moduleId].call ),而且也有了独立的作用域,定义变量,声明函数都不会污染全局作用域。模块函数的参数列表中除了commonJS规范所要求的 module 与 exports 外,还有 __webpack_require__ 函数,用来替换 require ,作用是声明对其他模块的依赖并获得该模块的 exports ( return installedModules[moduleId].exports 和 return module.exports; )。而且不需要提供模块的相对路径或其他形式的ID,直接传入该模块在modules列表中索引即可,这样可以省掉模块标识符的解析过程(准确说,webpack是把require模块的解析过程提前到了构建期),从而可以获得更好的运行性能。
程序解读:
bundle.js通过 __webpack_require__(0); 启动整个程序,先检查模块ID = 0是否在缓存对象中,若该模块的缓存存在返回 module.exports 即模块所暴露出来的数据,若该模块的缓存不在则新创建module对象(该module对象作用是用来指向真实模块)并加入到缓存对象中,此时由于module对象和该模块的缓存对象 installedModules[moduleId] 的exports属性为没有数据,所以需要通过执行该模块函数来返回具体require其他模块的数据,传入的上下文对象是 module.exports 和 installedModules[moduleId].exports 所共同指向的一个对象。当程序执行到 var text = __webpack_require__(1); 时,又会执行 modules[1].call ,然后 module.exports = 'Hello world'; 将执行 __webpack_require__(1) 时创建的module1的exports赋值为Hello world,并返回,此时 __webpack_require__(1) 执行完毕,text为Hello world并打印, __webpack_require__(0) 执行完毕。这是一个递归的过程,如果还有更多依赖模块的话会更明显。
总结一下,webpack主要做了两部分工作:
1.分析得到所有必须模块并合并。
2.提供让这些模块有序,正常的执行环境。
参考:
《React全栈 Redux+Flux+webpack+Babel整合开发》
解读webpack的bundle.js的更多相关文章
- vue-cli脚手架npm相关文件解读(2)webpack.prod.conf.js
系列文章传送门: 1.build/webpack.base.conf.js 2.build/webpack.prod.conf.js 3.build/webpack.dev.conf.js 4.bui ...
- 解决webpack因新版本打包失败问题--ERROR in multi ./src/main.js ./dist/bundle.js
最近在学习webpack打包过程中遇到的一个问题向大家分享下! 创建了一个webpacksty的目录,目录下放着dist,src子目录,然后通过node环境下,npm init -y 初始化项目出现p ...
- webpack最简单的入门教程里bundle.js之运行单步调试的原理解析
读这篇文章的朋友,请确保对webpack有最基础的认识. 您可以阅读我前一篇文章:Webpack 10分钟入门 来在本地运行一个Webpack的hello world项目.https://www.to ...
- webpac4k运行webpack .\src\main.js .\dist\bundle.js打包出错
打包的命令格式:webpack 要打包的文件的路径 打包好的输出文件的路径 运行webpack .\src\main.js .\dist\bundle.js 提示错误,错误信息如下: WARNING ...
- 在Visual Studio Code 运行 webpack ./src/main.js --output-filename ./dist/bundle.js --output-path . --mode development 提示 Module no t found:Error:Can't resolve' 'jquery' 是因为vs code还没安装jquery
在Visual Studio Code 运行 webpack ./src/main.js --output-filename ./dist/bundle.js --output-path . --mo ...
- webpack打包错误 ERROR in multi ./src/main.js ./dist/bundle.js
webpack打包错误 ERROR in multi ./src/main.js ./dist/bundle.js:https://www.jianshu.com/p/a55fb5bf75e1
- 解决 webpack .\src\main.js .\dist\bundle.js 错误
打包的命令格式:webpack 要打包的文件的路径 打包好的输出文件的路径 栗子: webpack .\src\main.js .\dist\bundle.js 提示错误,错误信息如下: 错误原因 w ...
- vue-cli脚手架npm相关文件解读(3)webpack.dev.conf.js
系列文章传送门: 1.build/webpack.base.conf.js 2.build/webpack.prod.conf.js 3.build/webpack.dev.conf.js 4.bui ...
- vue-cli脚手架npm相关文件解读(1)webpack.base.conf.js
系列文章传送门: 1.build/webpack.base.conf.js 2.build/webpack.prod.conf.js 3.build/webpack.dev.conf.js 4.bui ...
随机推荐
- SQL中查询语句的使用
常用SQL查询语句 - myLittleGarden - 博客园 http://www.cnblogs.com/sunada2005/p/3411873.html 一.简单查询语句 1. 查看表结构 ...
- Xshell通过ssh方式连接Linux服务器,通过Xftp进行文件传输
准备工作: 一.Linux服务器一台,并配置ssh(本文以腾讯云服务器为例). 1.生成秘钥 打开腾讯云控制台,依次选择:总览->云服务器->SSH秘钥 点击创建秘钥,输入秘钥名称,点击确 ...
- 为KindEditor编辑器中的内容添加样式,使得自己定义前台页面显示效果与编辑器效果一致
KindEditor 本身自带有一定的样式,且为内部样式,在使用过程中,难免会发现部分效果不是我们想要的,因此.KindEditor提代了两种方式供使用着调用 1.内部样式.通过 cssData 属性 ...
- java编写的2048程序
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util ...
- RF使用的相关库API
RF内置库: http://robotframework.org/robotframework/ SSHLibrary: ---WEB自动化测试 http://robotframework.org ...
- Python 数据类型:数值
数值类型分为:整型 .长整型 .浮点型 .复数型 整型示例: In [1]: a = 100 # 整型也就是整数类型 In [2]: type(a) # 整型的英文缩写为int Out[2]: int ...
- HTTP 基础术语
URI 和 URL:URI用于标记一个网络资源,URL则表示这个网络资源的访问地址,详细说明 超文本:普通的一段文字叫做文本,如果给这段文字加上超链接,那么就叫做超文本,HTML 就是超文本标记语言 ...
- windows cmd命令大全/cmd命令提示符大全
刚接触电脑的时候是从DOS系统开始,DOS时代根本就没有Windows这样的视窗操作界面,只有一个黑漆漆的窗口,让你输入命令.所以学DOS系统操作,cmd命令提示符是不可或缺的.可以告诉大家,大多数的 ...
- mySQL数据库二:命令行的使用
在做整理的时候,上一篇刚开始只是简单的做了个数据类型的开头,在这里简单说一下mySQL的使用以及它的命令行 1.准备工作 有一个好的开发工具可以几何倍数的增加我们的工作效率,所以,工具是必不可少的,首 ...
- thinkphp5 Windows下用Composer引入官方GitHub扩展包
很多新手,比如说我,写代码就是在windows下,所以总会遇到很多不方便的地方,比如说GitHub上面的代码更新了,要是你在linux,只要几行命令就可以搞定更新了,在windows下面,你需要用到C ...