解读webpack的bundle.js

可能就是好奇心略重了,读了一下webpack打包后的bundle.js的代码,复杂的模块可能读不懂,但简单的hello world模块我还是能看懂的。没什么目的,就是想通过几个简单的模块,一条简单的webpack命令,一个神奇的bundle.js代码来了解webpack是怎么把遵循commonJs规范的模块应用到浏览器端的。

几个简单的模块:

一条简单的webpack命令:

一个神奇的bundle.js:

 1 /******/ (function(modules) { // webpackBootstrap
 2 /******/     // The module cache
 3 /******/     var installedModules = {};
 4
 5 /******/     // The require function
 6 /******/     function __webpack_require__(moduleId) {
 7
 8 /******/         // Check if module is in cache
 9 /******/         if(installedModules[moduleId])
10 /******/             return installedModules[moduleId].exports;
11
12 /******/         // Create a new module (and put it into the cache)
13 /******/         var module = installedModules[moduleId] = {
14 /******/             exports: {},
15 /******/             id: moduleId,
16 /******/             loaded: false
17 /******/         };
18
19 /******/         // Execute the module function
20 /******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21
22 /******/         // Flag the module as loaded
23 /******/         module.loaded = true;
24
25 /******/         // Return the exports of the module
26 /******/         return module.exports;
27 /******/     }
28
29
30 /******/     // expose the modules object (__webpack_modules__)
31 /******/     __webpack_require__.m = modules;
32
33 /******/     // expose the module cache
34 /******/     __webpack_require__.c = installedModules;
35
36 /******/     // __webpack_public_path__
37 /******/     __webpack_require__.p = "";
38
39 /******/     // Load entry module and return exports
40 /******/     return __webpack_require__(0);
41 /******/ })
42 /************************************************************************/
43 /******/ ([
44 /* 0 */
45 /***/ function(module, exports, __webpack_require__) {
46
47     /*
48       打印文本的index模块
49      */
50     var text = __webpack_require__(1);
51     console.log(text);
52
53 /***/ },
54 /* 1 */
55 /***/ function(module, exports) {
56
57     /*
58       生成文本的Hello world模块
59      */
60     module.exports = ‘Hello world!‘;
61
62 /***/ }
63 /******/ ]);

注释太多有点懵逼,可是细看也不就是一个立即执行的函数表达式嘛(IIFE),这是JavaScript中常见的独立作用域的方法。这里我将注释简化一下:

 1 (function(modules){
 2     //module缓存对象
 3     var installedModules = {};
 4     //require函数
 5     function __webpack_require__(moduleId){
 6         //检查module是否在cache中
 7         if(installedModules[moduleId]){
 8             return installedModules[moduleId].exports;
 9         }
10         //若不在cache中则新建module并放入cache中
11         var module = installedModules[moduleId] = {
12             exports: {},
13             id: moduleId,
14             loaded: false
15         };
16         //执行module函数
17         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
18         //标记module已经加载
19         module.loaded = true;
20         //返回module的导出模块
21         return module.exports;
22     }
23
24     //暴露modules对象(__webpack_modules__)
25     __webpack_require__.m = modules;
26     //暴露modules缓存
27     __webpack_require__.c = installedModules;
28     //设置webpack公共路径__webpack_public_path__
29     __webpack_require__.p = "";
30     //读取入口模块并且返回exports导出
31     return __webpack_require__(0);
32
33 })([function(module, exports, __webpack_require__){ /*模块Id为0*/
34     var text = __webpack_require__(1);
35     console.log(text);
36 },function(module, exports){ /*模块Id为1*/
37     module.exports = ‘Hello world‘;
38 }]);

这个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整合开发》

时间: 2024-08-10 17:03:35

解读webpack的bundle.js的相关文章

webpack最简单的入门教程里bundle.js之运行单步调试的原理解析

读这篇文章的朋友,请确保对webpack有最基础的认识. 您可以阅读我前一篇文章:Webpack 10分钟入门 来在本地运行一个Webpack的hello world项目.https://www.toutiao.com/i6612879647568822788/ 我这里可以在回顾一下这个web pack的hello world项目. 用webpack打包之后,项目文件夹里包含了这些资源: index.html的源代码很简单,就包含了一个webpack打包后生成的bundle.js文件: 那么运行

解决webpack因新版本打包失败问题--ERROR in multi ./src/main.js ./dist/bundle.js

最近在学习webpack打包过程中遇到的一个问题向大家分享下! 创建了一个webpacksty的目录,目录下放着dist,src子目录,然后通过node环境下,npm init -y 初始化项目出现package.json文件,src子目录下又存放着index.html和main.js文件,接下来尝试着在main.js输入一句代码当验证打包后续是否成功的过程: console.log("ok"); 接下就是执行webpack打包命令了 把src下的main.js打包到dist下的bun

webpack运行webpack .\src\main.js .\dist\bundle.js打包出错

打包的命令格式:webpack 要打包的未年检的路径  打包好的输出文件的路径 运行webpack .\src\main.js .\dist\bundle.js 提示错误,错误信息如下: WARNING in configurationThe 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'pro

vue-cli脚手架npm相关文件说明-2、webpack.prod.conf.js

下面介绍webpack.prod.conf.js中相关配置代码和配置的说明,建议先查阅build/webpack.prod.conf.js /* * Webpack 生产环境配置文件,用于生产环境执行Build * 执行Build 主要是用Webpack执行这里的配置 * 建议先查阅webapck.base.conf.js ../config/index.js */ var path = require('path') var utils = require('./utils') // 下面是u

vue-cli脚手架之webpack.prod.conf.js

webpack.prod.conf.js 生产环境配置文件: 'use strict'//js严格模式执行 const path = require('path')//这个模块是发布到NPM注册中心的NodeJS"路径"模块的精确副本 const utils = require('./utils')//utils.js文件 const webpack = require('webpack')//webpack模块 const config = require('../config')/

vue-cli脚手架build目录中的webpack.prod.conf.js配置文件

// 下面是引入nodejs的路径模块 var path = require('path') // 下面是utils工具配置文件,主要用来处理css类文件的loader var utils = require('./utils') // 下面引入webpack,来使用webpack内置插件 var webpack = require('webpack') // 下面是config目录下的index.js配置文件,主要用来定义了生产和开发环境的相关基础配置 var config = require

基于webpack和vue.js搭建开发环境

前言 在对着产品高举中指怒发心中之愤后,真正能够解决问题的是自身上的改变,有句话说的好:你虽然改变不了全世界,但是你有机会改变你自己.秉承着“不听老人言,吃亏在眼前”的优良作风,我还是决定玩火自焚. 问题所在 之前的项目总结为以下内容: 1.AMD模块规范开发,使用requirejs实现,使用rjs打包,最终导致的结果是,输出的项目臃肿,肿的就像一坨狗不理……不忍直视2.使用gulp进行打包,这一点貌似没有可吐槽的地方,毕竟都是被grunt折磨过来的……3.数据的渲染使用模板引擎,这就意味着你要

基于webpack和vue.js搭建的H5端框架(其实主要用于Hybrid开发H5端框架,但是依然能够作为纯web端使用)

人类的发展得益于对追求不断的提升,在能活着的基础上是否要活得潇洒一点,技术的发展亦如是.在公司作为一个最最最最最最最底层的搬砖码农,经历了两个版本的铸(zhe)炼(mo)之后,我痛下决心今后一定要:…………..一定要和产品惺(shi)惺(bu)相(liang)惜(li). 开始之前 本文包含以下技术,文中尽量给与详细的描述,并且附上参考链接,读者可以深入学习: 1.webpack2.Vue.js3.npm4.nodejs —- 这个就不给连接了,因为上面的连接都是在你实践的过程中要去不断访问的5

webpack配合vue.js实现完整的单页面demo

本篇文章主要是我在开发前研究了webpack+vue.js的单页面应用,因为需要用到node的npm,所以确保安装了node,建议官网安装最新的稳定版本.并且在项目中需要加载一些npm包,由于npm的服务器在国外,可能我们下载的过程会比较慢,所以建议用阿里的镜像cnpm安装,10分钟实时更新一次npm的镜像.具体的下载配置参考阿里的cnpm官网.本文章只是和大家探讨怎么利用webpack配合vue.js做一个单页面应用,具体关于vue里面的内容怎么写并不在本篇文章的介绍范围. 1. 定义我们de