-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
面试官:webpack原理都不会? #48
Labels
Comments
compiler.js 的 run 方法里面,迭代构建modules的时候,上面的写法仅支持一层依赖,如果 greeting.js 中也有依赖的话打包完运行会报错的吧? |
弔图一堆 |
从逻辑上看是会报错,但是这个文章的目的是让大致了解学习webpack打包的思路,所以实现起来肯定不会考虑那么全面 |
没有讲到插件哦 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
引言
前一段时间我把
webpack
源码大概读了一遍,webpack
到4.x
版本后,其源码已经比较庞大,对各种开发场景进行了高度抽象,阅读成本也愈发昂贵。过度分析源码对于大家并没有太大的帮助。本文主要是想通过分析
webpack
的构建流程以及实现一个简单的webpack
来让大家对webpack
的内部原理有一个大概的了解。(保证能看懂,不懂你打我 🙈)webpack 构建流程分析
首先,无须多言,上图~
webpack
的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:首先会从配置文件和Shell
语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数;初始化完成后会调用Compiler
的run
来真正启动webpack
编译构建过程,webpack
的构建流程包括compile
、make
、build
、seal
、emit
阶段,执行完这些阶段就完成了构建过程。初始化
entry-options 启动
从配置文件和
Shell
语句中读取与合并参数,得出最终的参数。run 实例化
compiler
:用上一步得到的参数初始化Compiler
对象,加载所有配置的插件,执行对象的run
方法开始执行编译编译构建
entry 确定入口
根据配置中的
entry
找出所有的入口文件make 编译模块
从入口文件出发,调用所有配置的
Loader
对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理build module 完成模块编译
经过上面一步使用
Loader
翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系seal 输出资源
根据入口和模块之间的依赖关系,组装成一个个包含多个模块的
Chunk
,再把每个Chunk
转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会emit 输出完成
在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
分析完构建流程,下面让我们自己动手实现一个简易的
webpack
吧~实现一个简易的 webpack
准备工作
目录结构
我们先来初始化一个项目,结构如下:
这里我先解释下每个文件/文件夹对应的含义:
dist
:打包目录lib
:核心文件,主要包括compiler
和parser
compiler.js
:编译相关。Compiler
为一个类, 并且有run
方法去开启编译,还有构建module
(buildModule
)和输出文件(emitFiles
)parser.js
:解析相关。包含解析AST
(getAST
)、收集依赖(getDependencies
)、转换(es6转es5
)index.js
:实例化Compiler
类,并将配置参数(对应forstpack.config.js
)传入test.js
:测试文件,用于测试方法函数打console
使用src
:源代码。也就对应我们的业务代码forstpack.config.js
: 配置文件。类似webpack.config.js
package.json
:这个就不用我多说了~~~(什么,你不知道??)先完成“造轮子”前 30%的代码
项目搞起来了,但似乎还少点东西~~
对了!基础的文件我们需要先完善下:
forstpack.config.js
和src
。首先是
forstpack.config.js
:内容很简单,定义一下入口、出口(你这也太简单了吧!!别急,慢慢来嘛)
其次是
src
,这里在src
目录下定义了两个文件:greeting.js
:index.js
:ok,到这里我们已经把需要准备的工作都完成了。(问:为什么这么基础?答:当然要基础了,我们的核心是“造轮子”!!)
梳理下逻辑
短暂的停留一下,我们梳理下逻辑:
Q
: 我们要做什么?A
: 做一个比webpack
更强的super webpack
(不好意思,失态了,一不小心说出了我的心声)。还是低调点(防止一会被疯狂打脸)Q
: 怎么去做?A
: 看下文(23333)Q
: 整个的流程是什么?A
: 哎嘿,大概流程就是:AST
语法树。AST
语法树,生成浏览器能够运行的代码正式开工
compile.js 编写
compile.js
主要做了几个事情:forestpack.config.js
配置参数,并初始化entry
、output
run
方法。处理构建模块、收集依赖、输出文件等。buildModule
方法。主要用于构建模块(被run
方法调用)emitFiles
方法。输出文件(同样被run
方法调用)到这里,
compiler.js
的大致结构已经出来了,但是得到模块的源码后, 需要去解析,替换源码和获取模块的依赖项, 也就对应我们下面需要完善的parser.js
。parser.js 编写
看完这代码是不是有点懵(说好的保证让看懂的 😤)
别着急,你听我辩解!!😷
这里要先着重说下用到的几个
babel
包:@babel/parser
:用于将源码生成AST
@babel/traverse
:对AST
节点进行递归遍历babel-core
/@babel/preset-env
:将获得的ES6
的AST
转化成ES5
parser.js
中主要就三个方法:getAST
: 将获取到的模块内容 解析成AST
语法树getDependencies
:遍历AST
,将用到的依赖收集起来transform
:把获得的ES6
的AST
转化成ES5
完善 compiler.js
在上面我们已经将
compiler.js
中会用到的函数占好位置,下面我们需要完善一下compiler.js
,当然会用到parser.js
中的一些方法(废话,不然我上面干嘛要先把parser.js
写完~~)直接上代码:
关于
compiler.js
的内部函数,上面我说过一遍,这里主要来看下emitFiles
:这里的
bundle
一大坨,什么鬼?我们先来了解下
webpack
的文件 📦 机制。下面一段代码是经过webpack
打包精简过后的代码:简单分析下:
webpack
将所有模块(可以简单理解成文件)包裹于一个函数中,并传入默认参数,将所有模块放入一个数组中,取名为modules
,并通过数组的下标来作为moduleId
。modules
传入一个自执行函数中,自执行函数中包含一个installedModules
已经加载过的模块和一个模块加载函数,最后加载入口模块并返回。__webpack_require__
模块加载,先判断installedModules
是否已加载,加载过了就直接返回exports
数据,没有加载过该模块就通过modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
执行模块并且将module.exports
给返回。(你上面说的这一坨又是什么鬼?我听不懂啊啊啊啊!!!)
那我换个说法吧:
webpack
打包出来的是一个匿名闭包函数(IIFE
)modules
是一个数组,每一项是一个模块初始化函数__webpack_require__
用来加载模块,返回module.exports
WEBPACK_REQUIRE_METHOD(0)
启动程序(小声 bb:怎么样,这样听懂了吧)
lib/index.js 入口文件编写
到这里,就剩最后一步了(似乎见到了胜利的曙光)。在
lib
目录创建index.js
:这里逻辑就比较简单了:实例化
Compiler
类,并将配置参数(对应forstpack.config.js
)传入。运行
node lib/index.js
就会在dist
目录下生成bundle.js
文件。和上面用
webpack
打包生成的js
文件作下对比,是不是很相似呢?来吧!展示
我们在
dist
目录下创建index.html
文件,引入打包生成的bundle.js
文件:此时打开浏览器:
如你所愿,得到了我们预期的结果~
总结
通过对
webpack
构建流程的分析以及实现了一个简易的forestpack
,相信你对webpack
的构建原理已经有了一个清晰的认知!(当然,这里的forestpack
和webpack
相比还很弱很弱,,,,)参考
本文是看过极客时间程柳锋老师的「玩转 webpack」课程后整理的。这里也十分推荐大家去学习这门课程~
❤️ 爱心三连击
1.如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~
2.关注公众号前端森林,定期为你推送新鲜干货好文。
3.特殊阶段,带好口罩,做好个人防护。
4.添加微信fs1263215592,拉你进技术交流群一起学习 🍻
The text was updated successfully, but these errors were encountered: