常见loader
在webpack5之后,我们可以直接使用资源模块类型(asset module type),来替代url-loader、file-loader;
常见plugin
webpack的工作流程
webpack的工作流程是一个串行的过程,从启动到结束会依次执行下面的步骤
1.初始化参数:从命令行或者配置文件中获取参数,得到最终的配置对象
这一步由webpack-cli来操作它的本质就是将所有的配置参数进行合并
2.开始编译:从上一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法开始执行编译
执行compile方法的时候会实例化一个compilation对象
3.确定入口:根据配置中的entry找到所有的入口文件,从入口文件出发,调用所有配置文件的loader对模块进行编译,
4.并找出模块依赖的模块,再递归本步骤直到所有的入口文件依赖的模块都执行了此步骤(是通过AST对模块的源代码进行解析找到require表达式分析出所依赖的文件路径)
5.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的chunk(每个入口对应一个chunk,一个chunk对应多个模块),再把每个chunk转换成一个单独的文件加入到输出列表中(assets中属性是文件名,值是文件内容)
6.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件写入到文件系统中
在以上过程中,webpack会在特定的时间点执行对应的插件
2.AST:
webpack的核心通过JavaScript Parser把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,然后对AST进行遍历修改之后,然后再将AST变成修改后的代码
AST:抽象语法树
loader的执行顺序
loader可能有两部分组成一个是pitch一个是normal
相同优先级的情况下pitchLoader的执行顺序是从前往后,normalLoader的执行顺序是从后往前
可以在规则里面设置enforce属性设置pre或者post来改变他们的执行的优先级顺序
优先级为pre>normal>inline>post
总结:loader的执行顺序是先从右向左 在从左向右执行
原理:具体实现在loader-runner的库里面的runLoader方法里面
先去执行IteratePitchingLoader 在执行迭代pitchLoader的时候有将loaderIndex进行++的操作,处理完所有的pitch就会去处理文件,然后在迭代normalLoader的在迭代normalLoader的时候是根据这个loaderIndex取出当前loader执行然后把loaderindex进行--的操作
note:如果有一个pitchloader有返回值则将loaderIndex--,去迭代执行normalLoader
webpack的babel的原理
https://blog.csdn.net/qq_33207292/article/details/122507786
webpack如何优化
一:优化构建速度:
- 配置别名alias
- 配置扩展名extensions、
- 缩小范围使用exclude、
- 使用cdn(在生产环境中第三方库使用cdn引入 (webpack不会对cdn资源进行打包))
- 利用缓存
babel-loader 开启缓存
babel 在转译 js 过程中时间开销比价大,将 babel-loader 的执行结果缓存起来,重新打包的时候,直接读取缓存
其他loader编译后的用cache-loader进行缓存
二、优化运行时体验
运行时优化的核心就是提升首屏的加载速度,主要的方式就是降低首屏加载文件体积,首屏不需要的文件进行预加载或者按需加载
- 代码懒加载
- 可以通过魔法注释的方式用prefetch 与 preload
prefetch是在浏览器闲置的情况下才会下载资源、preload是在父文件加载时,以并行方式开始加载该文件
三、 优化构建结果
- 压缩css、css-minimizer-webpack-plugin
- 清除无用css:purgecss-webpack-plugin
- 压缩js、terser-webpack-plugin
- Tree-shaking
Compiler和Compilation的区别:
Compiler是在webpack构建之初就会创建的对象它都是一个独一无二,并且在webpack整个生命周期都会存在
它有以下主要属性:
compiler.options 可以访问本次启动 webpack 时候所有的配置文件,包括但不限于 loaders 、entry 、output 、plugin 等等完整配置信息
compiler.inputFileSystem 和 compiler.outputFileSystem 可以进行文件操作,相当于 Nodejs 中 fs
compiler.hooks 可以注册 tapable 的不同种类 Hook,从而可以在 compiler 生命周期中植入不同的逻辑
Compilation ,每次资源变化都会生成新的compilation对象
它会对构建依赖图中所有模块,进行编译。 在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、 分块(chunk)、哈希(hash)和重新创建(restore)
Compilation是准备编译模块的时候才会创建的对象
它有以下主要属性:
compilation.modules :可以访问所有模块,打包的每一个文件都是一个模块。
compilation.chunks:chunk 即是多个 modules 组成而来的一个代码块。入口文件引入的资源组成一个 chunk,通过代码分割的模块又是另外的 chunk
compilation.assets:可以访问本次打包生成所有文件的结果。
compilation.hooks:可以注册 tapable 的不同种类 Hook,用于在 compilation 编译模块阶段进行逻辑添加以及修改
自定义loader
loader本质是一个函数然后loader runner库(是一个执行loader链条的模块)会调用这个函数,然后将上一个loader产生的结果或者资源文件传入进去,返回一个buffer格式的数据或者JavaScript语法的字符串如果返回多个值可以调用this.callback方法。
自定义plugin
自定义插件我们需要知道Tapable这个模块,它是webpack的一个非常重要的核心模块,Tapable提供了许多钩子(hooks),这些钩子会被应用到插件中,这样开发者就可以通过注册插件来修改Webpack的行为,从而实现各种功能。webpack 在编译代码过程中,会触发一系列 Tapable 钩子事件,插件所做的,就是找到相应的钩子,往上面挂上自己的任务,也就是注册事件,这样当 webpack 构建的时候,会适时的触发相应的钩子,因此也就触发了插件的方法。
插件可以是一个类也可以是一个函数,但是大部分情况下都是一个类
如果插件是一个类需要在类的prototype 上定义一个 apply 方法,接受一个webpack compiler对象的引用。 compiler上有很多钩子比如afterEmit(等资源输出到output文件中后执行),在apply方法里面去监听(订阅)这些钩子,在webpack的工作流中通过call去发布这些钩子
实现CleanWebpackPlugin:
实现AnalyzeWebpackPlugin
vite
在开发环境下基于浏览器原生 ES module开发,将代码通过esbuild构建成es module。在生产环境下基于 Rollup 打包。
vite的优点是不需要自己配置loader
Vite 天然支持引入 .ts .css文件。
快的原因:使用了ESBuild构建工具、进行预打包(对一些node_module里面的模块)
vite的原理
vite会建立一个本地服务器使用的是Connect搭建的服务器,浏览器去请求ts、less这些资源的时候,本地的服务器会进行拦截,然后对这些请求进行转发,返回给浏览器的资源是vite构建后的es module js代码,这些代码浏览器是可以识别的