谈谈webpack和vite
谈谈webpack和vite对比
webpack和vite有很大的区别,比如在热更新、打包、预构建等
- 打包方面:
- webpack是对项目进行整体的打包,随着项目复杂增大,打包的速度也会变慢,而vite在开发环境中是利用浏览器ESModule按需加载,不会因为项目变大而变慢
- 热更新和按需编译:
- webpack:webpack通过webpack-dev-server等工具实现热更新,但在某些情况下需要重新编译和打包整个应用,因此可能会有一定的性能损耗。
- Vite: Vite利用浏览器原生支持的ES模块特性,可以实现按需编译和热更新,因此具有更快的热更新速度和开发体验
- 预构建:
- vite使用了esbuild进行预构建,将依赖项转换为ES模块,以提高开发时的性能和体验。
vite的快体现在哪里?
- 快速的冷启动:
- Vite 之所以快,借助了浏览器对 ESM规范的支持
- vite不需要做
bundle操作,即不需要构建 - 模块之间的依赖关系的解析由浏览器实现
- 文件的转换由
dev server的middlewares实现并做缓存
- 快速的热更新:
- 由于
Vite采用unbundle机制,所以dev server在监听到文件发生变化以后,只需要通过 websocket 连接通知浏览器去重新加载变化的文件,剩下的工作就交给浏览器去做
- 由于
- 按需编译:
- Vite只编译需要的模块,而不是整体打包,这可以提高开发时的编译速度,尤其在项目规模较大时效果更为明显。
- 预构建缓存:
- Vite 将预构建的依赖项缓存到
node_modules/.vite,避免重复编译打包 - 什么情况会重新进行预构建?
- 包管理的锁文件变化,例如
package-lock.json,yarn.lock,pnpm-lock.yaml vite.config.js中的相关字段NODE_ENV的值,预构建只针对开发环境
- 包管理的锁文件变化,例如
- Vite 将预构建的依赖项缓存到
vite的缺点有吗,说说什么方面?
- 首屏性能 【首次启动加载慢】
- 不对源文件做合并捆绑操作,导致大量的
http请求; dev server运行期间对源文件做resolve、load、transform、parse操作;- 预构建、二次预构建操作也会阻塞首屏请求,直到预构建完成为止;
- 不对源文件做合并捆绑操作,导致大量的
不过首屏性能差只发生在
dev server启动以后第一次加载页面时发生。之后再reload页面时,首屏性能会好很多。原因是dev server会将之前已经完成转换的内容缓存起来
- 懒加载性能
- 和首屏一样,由于
unbundle机制,动态加载的文件,需要做resolve、load、transform、parse操作,并且还有大量的http请求,导致懒加载性能也受到影响
- 和首屏一样,由于
如何优化?
- 可以通过
prefetch、持久化缓存等手段做优化 - 减少http请求
- 预构建:将第三方依赖代码的多个文件模块合并为一个模块,也是减少http请求
- 代码分割
- 做到按需加载、利用缓存
谈谈weppack打包过程
- 1、解析入口文件,分析内容, 获取AST抽象语法树
- 2、找出所有依赖模块
- 3、AST转化编码code
- 4、递归解析所有依赖项、生成依赖关系图
- 5、输出bundle
谈谈你是如何使用webpack
配置webpack、优化webpack方案
参考
create-react-app脚手架源码配置,里面集成了webpack的配置和优化
对webpack常规的配置,以及webpack的性能优化,如构建的速度进行优化、对包的体积大小优化、页面加载优化等
-
比如比较常规的优化 (静态资源优化、图片优化、css压缩、js压缩)
- 小图片的话 (小于5kb),进行base64格式产出
-
代码分割/代码拆分,
optimization.splitChunks- 提取公共模块, 移除了重复的依赖模块, 减轻了大小 (比如lodash)
- 防止一些依赖包重复打包
- 把第三方依赖包打包成vendor
- 核心是把第三方依赖抽离出来,和业务代码js分开
- 可以更好利用缓存,因为第三方库通常不会经常变化,可以利用缓存,减少了初始加载时间
- 浏览器去请求资源的时候,会从缓存中获取vendor
- 提取公共模块, 移除了重复的依赖模块, 减轻了大小 (比如lodash)
-
组件异步加载分包优化
- 利用
optimization.runtimeChunks设置为true- 运行时代码单独打包出来
- 对于异步加载的代码,在webpack中称为运行时代码
- 如果不将它提取出来的话,每次修改这个异步加载的文件, app.js每次都会改变,导致浏览器缓存失效,如果提取出来之后,app.js就不会被影响到,只是runtime.js会发生改变
- 但是也有个缺点:异步加载单独打包出来的runtime文件,浏览器需要请求,会增加http请求
- 解决办法:可以把打包出来的runtime文件内联到index.html中,就不会增加http请求问题了
- 运行时代码单独打包出来
- 组件按需加载 (异步加载)
- 如react中, 利用
lazy和Suspense - 如通过
import('组件/库')来动态加载组件和库
- 如react中, 利用
- 利用
-
css和js分离拆分
- 利用mini-css-extract-plugin插件, 可以更好地利用缓存,CSS 文件的缓存,页面访问速度自然会加快
-
持久化缓存提高构建速度,将缓存设置在文件系统中,存储在磁盘,下次构建利用缓存的构建内容
-
配置cache, cache支持
memory'|'filesystem, 默认是memory内存- 支持缓存设置为内存和文件系统
- 内存肯定是比文件系统快,但是注意,内存缓存的话,也会损失可持久性,webpack关了就没了,而文件系统是一直存在在硬盘中
-
一般设置 持久缓存会将缓存存储到文件系统磁盘中
-
打包出来的文件加hash
- 打包后的文件,加上hash,利用浏览器的缓存机制,那么在加载资源会从缓存中获取,就不用重新加载一遍新资源
- 没有发生变化的文件,hash值不会变,就可以利用缓存
- 推荐使用
contenthash,文件内容发生变化,hash就会发生变化
- 打包后的文件,加上hash,利用浏览器的缓存机制,那么在加载资源会从缓存中获取,就不用重新加载一遍新资源
-
设置sideEffects,标记副作用
- 如果代码存在副作用,不要被tree shaking掉,否则代码被删掉
- 如一些全局的css,这些就是副作用
-
dll分包: 只需要一次构建就好,不需要每次都构建,完全没必要,会导致构建速度慢
-
预加载优化
- 通过组件异步加载打包优化
-
预获取优化
- 比如在页面A 可能要去B页面
你是怎么分析webpack的性能
-
使用了webpack构建编译速度测量的插件:
speed-measure-webpack-plugin- 可查看构建编译所花费的时长
-
当开启了cache缓存之后,构建速度效果是非常明显的,通过查看构建编译时间可以知道, 提升30倍的构建速度!
谈谈你是如何使用vite
1、如何做配置vite
2、如何优化vite
如何优化vite
- 预构建优化,针对开发环境
- 网络优化,开启http2
- 代码分割
- manualChunks进行分包,是基于rollup
- 把第三方依赖进行分包,vite默认代码分包,是单独打包在vendor中,而vendor随之项目复杂依赖的包越多会变得越大,需要自定义分包,把vendor拆出来
- 提高了对第三方依赖包的缓存
谈谈vite预构建
预构建仅适用于开发模式, 通过optimizeDeps开启预构建
- 将非
ESM格式的代码转换为符合ESM规范格式的代码; - 将第三方依赖代码的多个文件模块合并为一个模块,减少
http请求数量- 比如lodash-es,里面内置了几百个模块,比如用了get方法,这个方法会依赖了很多工具函数,而每个import都会触发一次请求,导致触发了很多请求,大量的请求会造成网络阻塞,导致页面加载十分缓慢
- 在进行依赖的预构建之后,
lodash-es这个库的代码被打包成了一个文件,这样请求的数量会减少,页面加载也快了许多
- 在进行依赖的预构建之后,
- 比如lodash-es,里面内置了几百个模块,比如用了get方法,这个方法会依赖了很多工具函数,而每个import都会触发一次请求,导致触发了很多请求,大量的请求会造成网络阻塞,导致页面加载十分缓慢
Vite热更新为什么比Webpack热更新快?
Webpack热更新运行机制:
Webpack会遍历你的应用程序中的所有文件,并启动一个开发服务器(Webpack-dev-server),然后将整个代码渲染到开发环境中。从entry入口文件开始,将其依赖的资源文件通过loader打包成一个文件夹,然后通过server传递到客户端运行;也正是因为这样的运行机制,也必将导致项目代码量增多,应用体积增大之后,Webpack热更新需要等待较久的时间才能反映到浏览器中;
Vite热更新运行机制:
Vite会在本地启动一个Vite Server服务,对于第三方依赖使用了速度更快的esbuild预构建,对于业务代码使用原生的ESM,访问这个服务,加载对应模块的服务端资源,绕过了构建打包过程,对请求的模块进行实时按需编译,热更新时仅需重新请求改动过的模块即可,而且热更新的速度不会随着模块增多而变慢
vite是直接启动开发服务器,请求哪个模块再对该模块进行实时编译。 而webpack会先打包, 然后再启动开发服务器。webpack打包过程中,会分析模块依赖、转换代码,编译代码
vite在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快