webpack打包的整个过程,webpack打包作用
Webpack是如何实现打包的?下面这篇文章就带你深入了解一下Webpack的打包原理,希望对你有所帮助!
作为前端“攻城狮”,Webpack是非常熟悉的。Webpack可以做的事情太多了。你可以打包所有的资源(包括JS,TS,JSX,图片,字体和CSS等。)并将它们置于依赖关系中,这样你就可以根据自己的需求引用依赖关系来使用资源。Webpack在前端翻译各种文件资源和分析复杂模块的依赖关系方面做得非常好。此外,我们可以自定义加载器,自由加载自己的资源。今天我们来看看Webpack 是如何实现打包的呢?。
想要知道 Webpack 打包原理的我们需要提前知道两个知识点
1、什么是 require?
说到require,首先想到的可能是import,这是es6的一个语法标准。
require是一个运行时调用,所以require理论上可以应用在代码的任何地方;
import是在编译时调用的,所以必须放在文件的开头;
当我们用Webpack编译时,我们将使用babel把import翻译成require。在CommonJS中,有一个加载模块的全局方法require(),AMD和CMD也用require方法引用它。
例如:
var add=require(。/a . js’);
简单地添加(1,2)看起来require实际上是一个函数,而引用的。/a.js只是函数的一个参数。
2、什么是 exports?
这里我们可以把导出看作一个对象,MDN导出可以看它的具体用法。
了解了require 和 exports,接下来我们就可以开始打包
我们来看看下面的打包后的代码结构。我们可以发现包装后会出现需求和出口。
不是所有的浏览器都可以执行需求导出。您必须自己实现require和exports,以确保代码的正常运行。打包的代码是一个自执行函数,其参数是依赖信息和文件的代码。被执行的函数体通过eval执行代码。
总体设计图如下:
第一步:编写我们的配置文件
配置文件是用我们打包的入口和打包的出口输出配置的,为后续生成的文件做准备。
const path=require( path );
模块.导出={
条目:。/src/index.js ,
输出:{
Path: path.resolve (_ _ dirname,。/dist ),//打包输出文件的地址需要绝对路径,因此需要path。
文件名:“main.js”
},
模式:“开发”第二步:模块分析
整体思路:总结一下就是用fs文件读取入口文件,通过AST获取导入所依赖的文件的路径。如果依赖文件仍然有依赖关系,它将继续递归,直到依赖关系分析清楚为止,并且它将被维护在一个映射中。
细节拆解:有人会奇怪为什么用AST,因为AST天生就有这个功能。它的ImportDeclaration可以帮助我们快速筛选出导入语法,当然常规匹配也是可以的。毕竟文件读完是字符串,写牛逼的规则就能得到文件依赖路径,但是不够优雅。
step1:新建 index.js,a.js,b.js 依赖关系如下
index.js文件
从导入{ str }。/a . js ;
console . log(` $ { str } web pack `)a . js文件
从导入{ b}。/b.js
导出const str=hellob.js文件
export const b= BBB
step2:编写 Webpack
模块分析:使用AST的@babel/parser将文件读取的字符串转换成AST树,@babel/traverse做语法分析,使用ImportDeclaration过滤掉导入,找出文件依赖关系。
const content=fs . read file sync(entry file, utf-8 );
const ast=parser.parse(content,{ source type: module });
const dirname=path . dirname(entry file);
const dependencies={ };
遍历(ast,{
ImportDeclaration({ node }) {
//过滤掉导入
const newPathName=。/ path.join(dirname,node . source . value);
dependencies[node . source . value]=new pathname;
}
})
const { code }=transformFromAst(ast,null,{
预设:[@babel/preset-env]
})
返回{
entryFile,
家属,
密码
}结果如下:
使用递归或循环逐个分析导入文件的依赖关系。注意,我们使用for循环来分析所有的依赖关系。loop之所以能分析所有依赖,是因为模块的长度是变化的。有依赖的时候。modules.push新的依赖项,modules.length将更改。
for(设I=0;I this . modules . length;i ) {
const item=this . modules[I];
const { dependents }=item
如果(受抚养人){
对于(让j在家属中){
this . modules . push(this . parse(dependents[j]);
}
}
}第三步:编写 WebpackBootstrap 函数+生成输出文件
编写WebpackBootstrap函数:这里我们首先要做的是WebpackBootstrap函数。编译后,我们的源代码的导入将被解析为需要浏览器。既然我们不知道要求,我们应该先声明它。毕竟,要求是一种方法。写函数的时候也要注意范围隔离,防止变量污染。我们代码中的导出也需要我们声明它,这样才能保证代码执行时导出已经存在。
生成输出文件:我们已经在配置文件中写入了生成文件的地址,然后使用fs.writeFileSync将其写入输出文件夹。
文件(代码){
const file path=path . join(this . output . path,this.output.filename)
const new code=JSON . stringify(code);
//生成捆绑文件的内容
const bundle=`(函数(模块){
功能需求(模块){
函数pathRequire(relativePath){
返回要求(模块[模块])。家属[相对路径])
}
const exports={}
(函数(要求、导出、代码){
评估(代码)
})(pathRequire,exports,modules[模块]。码);
退货出口
}
要求( ${this.entry} )
})($ { new code })`;
//web pack bootstrap
//生成一个文件。将它放在dist目录中
fs.writeFileSync(文件路径,捆绑包,“utf-8”)
}
第四步:分析执行顺序
我们可以在浏览器的控制台上运行打包的结果。如果工作正常,应该可以打印hello Webpack。
总结
通过上面的分析,我们应该对Webpack的大致流程有了一个基本的了解。使用AST解析代码只是这个演示的一种方式,并不是Webpack的真正实现。Webpack有自己的AST解析方法,它总是依赖于模块。Webpack生态非常完整。感兴趣的童鞋可以考虑以下三个问题:
有组件循环引用怎么办?Webpack如何加载加载程序?强烈推荐的Vite,可以按需打包,大大提高了开发时的打包速度。如果是webapck,应该如何实现?有关编程的更多信息,请访问:编程视频!以上是对webpack的打包流程和原理的详细分析。请多关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。