相信大多数人都体验过Vite,知道它快。但是你知道为什么它比Webpack更快,有什么不同吗?今天我们就来全面了解一下Vite,特别适合初学者。让我们一起学习吧!什么是构建工具很多人对构建工具没有概念,只知道是用来打包的。那么构建工具到底是什么?大家都知道浏览器只支持Html、CSS、JavaScript,但是一个企业级的项目可能会用到各种前端技术,比如Less、Sass、TS、Vue组件、语法降级、体量优化等等。这时候,我们需要相应的工具来处理这些内容:使用less-loader/sass-loader来处理less/sass。使用tsc将typescript转换为javascript。使用vue-complier将vue组件模板转换为渲染函数。使用babel将es的新语法转换为旧浏览器可识别的语法。使用uglifyjs将我们的代码压缩成更小的文件。我们可以手动对代码进行一个一个的处理,但是这样效率很低。当我们稍微修改一下代码,流程就得重新走一遍,很麻烦。有一个神奇的东西可以把上面的工具整合在一起,让它自动处理整个过程。并且当代码发生变化时,它会自动帮我们重新过一遍。这个东西叫做构建工具。当然,构建工具的作用远不止于此,比如:模块化开发支持:支持直接从node_modules导入代码。提高项目性能:压缩文件、代码拆分。优化开发体验:热更新、跨域问题。......构建工具减轻了我们的精神负担,让我们不必关心自己写的代码在浏览器中运行的怎么样,只需要关心代码是怎么写的。市面上主流的构建工具有Webpack、Vite、esbuild、Rollup、Parcel,以及最近发布的turbopack,但最受欢迎的还是Webpack和Vite。Vite相对于Webpack的优势当项目规模越来越大时,构建工具需要处理的代码量呈指数级增长,包含数千个模块的项目非常普遍。像Webpack这样的构建工具会遇到性能瓶颈:项目通常需要很长时间,甚至几分钟才能启动。热更新(HMR)也可能需要几秒,甚至十几秒。我不知道你现在的项目怎么样。反正我们公司稍微大一点的Vue2项目,速度实在是太慢了,等的着急。这种情况极大地影响了我们的开发效率和幸福感。Webpack有没有办法优化它?难的。Webpack首先递归分析每个模块的依赖关系——构建依赖图,然后打包,然后启动本地服务器。此外,Webpack支持多种模块化规范,例如CommonJS和ES-Module。从一开始就需要统一模块化代码,处理所有的依赖。整个流程如下图所示:即便是按需加载,也还有一系列的工作要做,所以Webpack基本没有优化的余地。那么为什么Vite可以解决这个问题呢?底层语言。Vite使用esbuild预构建依赖。用Go编写的esbuild比用JS编写的捆绑器预构建依赖项快10-100倍。先启动服务器,然后请求模块,按需编译。Vite利用了现代浏览器支持ES-Module的特性,直接向依赖的模块发送请求。Vite在启动时不需要分析模块之间的依赖关系,也不需要打包。项目越大,优势越明显。这是Vite的启动过程:这样大家应该明白Vite为什么这么快了吧!Relyingonpre-build上面提到依赖pre-build。这个可能很多兄弟不太理解,这里也说一下。现代浏览器已经支持ES-Module,但是导入模块只能使用相对路径或者绝对路径,直接使用模块名是行不通的://main.js//假设我们安装了lodash模块importafrom'./a.js'//Supportimportbfrom'/b.js'//Supportimport_from'lodash'//报错依赖pre-build可以很好的解决这个问题。Vite会先找到依赖的模块,然后调用esbuild将CommonJS等规范的代码转换成ES-Module规范,然后放到node_modules/.vite/deps目录下,然后修改对应的导入路径。由于浏览器通过HTTP请求模块文件,一旦模块依赖较多,就会发起很多网络请求。例如,lodash-es有600多个内置模块,这些模块之前相互导入。当我们执行下面的代码时,浏览器会同时发出600多个HTTP请求!大量请求导致网络拥塞,导致页面加载非常慢。import{debounce}from'lodash-es'此时依赖于pre-build,而pre-build将lodash-es作为一个整体转化为一个模块,所以我们只需要发起一个HTTP请求!综上所述,依靠pre-build解决了以下三个让我们头疼的问题:与其他规范的兼容性。不同的第三方依赖包会有不同的导出格式(比如CommonJS规范)。覆盖导入路径。例如lodash或重写为/node_modules/.vite/deps/lodash.js?v=fef37e66以便浏览器可以正确导入它。网络性能优化。Vite会将内部依赖较多的ES-Module模块转换为一个模块,以提高页面加载性能。学习一项技术的最好方法是单独使用它。除了脚手架工具,Vite的使用也非常简单,直接在项目中安装vite并给出配置即可。当然,你不给也没关系,Vite会使用内置的默认配置:npminstallvite-D//vite.config.jsimport{defineConfig}from'vite'exportdefaultdefineConfig({//...})为了方便,你可以在package.json中加入启动和打包命令。"scripts":{"dev":"vite","build":"vitebuild"}然后在根目录新建index.html,npmrundev项目就可以运行了!CSS的处理“CSSModules”在不同的模块中定义了相同的类名,会导致样式被覆盖。这时候就要用到CSS模块了。以.module.css结尾的文件被认为是CSS模块文件。导入这样的文件会返回相应的对象:/*example.module.css*/.red{color:red;}//main.jsimportexamplefrom'./example.module.css'console.log(example)//{red:'_red_te83z_1'}document.getElementById('foo').className=example.red"CSSPreprocessor"Vite还提供了对.scss、.sass、.less、.styl和.stylus文件的内置支持,安装相应的预处理器即可:#.lessnpminstallless-D#.scssand.sassnpminstallsass-D#.styland.stylusnpminstallstylus-D感觉这个比Webpack简单多了,Webpack需要针对不同类型的配置不同的loader要处理的文件,Vite内部直接为我们配置。如果你使用的是Vue单文件组件,它可以通过自动启用。《PostCSS》PostCSS也是用来处理CSS的,但更像是一个工具箱,可以添加各种插件来处理CSS。我们经常遇到的样式兼容性问题,比如高级CSS语法的退化、前缀补全等,都可以通过PostCSS来解决。Vite对PostCSS有很好的支持,我们只需要安装我们需要使用的插件即可。npminstallpostcss-preset-env-Dpostcss-preset-env是一个预设环境插件,包含高级CSS语法降级、前缀补全等诸多功能。接下来,让我们在vite.config.js中进行配置:postcssPresetEnv()]}}})然后我们写一些特殊的样式:/*index.css*/.content{width:clamp(100px,30%,200px);user-select:none;}//main.jsimport'./index.css'打开浏览器,可以看到CSS已经帮我们处理好了:总体来说,PostCSS还是很实用的,可以帮助我们处理各种CSS问题。静态资源的处理将资源作为URL引入。默认情况下,导入一个静态资源会返回这个资源的URL路径,也就是绝对路径。importimgUrlfrom'./img.png'console.log(imgUrl)///src/img.pngdocument.getElementById('hero-img').src=imgUrl我们可以通过添加后缀来修改文件的导入方式.默认的导入方式相当于加上?url后缀。importimgUrlfrom'./img.png?url'将资源作为字符串导入。使用?raw后缀将资源以字符串形式导入,其实就是源文件信息。importimgUrlfrom'./img.png?raw'console.log(imgUrl)//源文件信息document.getElementById('hero-img').src=imgUrlimportscriptasWorker.JS脚本可以作为带有?worker或?sharedworker后缀的网络工作者导入。//workerimportWorkerfrom'./shader.js?worker'constworker=newWorker()//sharedworkerimportSharedWorkerfrom'./shader.js?sharedworker'constsharedWorker=newSharedWorker()json处理json文件即可import直接地。它还支持命名导入,以帮助我们更好地利用treeshaking://Importtheentireobjectimportjsonfrom'./example.json'//对根属性使用命名导入,这有效地帮助了treeshaking!import{field}from'./example.json'Vue处理Vite对Vue提供了优先支持,直接使用对应的插件即可:Vue3支持:@vitejs/plugin-vueVue3JSX支持:@vitejs/plugin-vue-jsxVue2.7支持:@vitejs/vite-plugin-vue2Vue<2.7支持:underfin/vite-plugin-vue2//vite.config.jsimport{defineConfig}from'vite'importvuefrom'@vitejs/plugin-vue'exportdefaultdefineConfig({plugins:[vue()]})TSVite的处理自然支持导入.ts文件。Vite使用esbuild将TypeScript翻译成JavaScript,比tsc快20-30倍左右,HMR热更新也很快。Vite只执行.ts文件的翻译,不执行任何类型检查。也就是说,即使IDE提示错误,也不会影响正常的开发生产环境打包。这肯定是不行的,否则很难对代码进行有效的约束。我们可以使用插件来实现这个功能:#Pluginsforcheckingnpminstallvite-plugin-checker-D#typescriptisadependencyofvite-plugin-checkernpminstalltypescript-D//vite.config.jsimport{defineConfig}from'vite'importcheckerfrom'vite-plugin-checker'exportdefaultdefineConfig({plugins:[checker({typescript:true})]})然后在根目录下创建tsconfig.json文件://tsconfig.json{"include":["src/**/*"]//需要验证的文件夹}这样命令行和页面都会显示TS的错误信息,不修正就无法继续开发!如果想在类型检查失败时阻止生产环境打包,只需在构建命令中添加一条指令://package.json"scripts":{"dev":"vite","build":"tsc--noEmit&&vitebuild"}环境变量类似于Vite和Webpack模式,都使用dotenv从特定文件加载额外的环境变量:.env#将在所有情况下加载。env.development#开发环境将被加载(名称可以通过配置修改).env.production#会加载生产环境(同上)。在客户端中,我们使用import.meta.env获取环境变量。为了防止某些环境变量不慎泄露给客户端,只有以VITE_为前缀的变量才会暴露给客户端,例如使用如下环境变量:VITE_SOME_KEY=123DB_PASSWORD=foobar客户端控制台打印结果:console.log(import.meta.env.VITE_SOME_KEY)//123console.log(import.meta.env.DB_PASSWORD)//undefined在服务端,即vite.config.js中,通过process.env获取环境变量.但是,考虑到与其他配置的一些冲突,Vite不会直接将环境变量注入到process.env对象中。这个时候我们可以手动处理://vite.config.jsimport{defineConfig,loadEnv}from'vite'exportdefaultdefineConfig(({command,mode})=>{//loadEnv()第一个参数是当前mode//第二个参数为环境变量文件所在目录,process.cwd()返回当前节点进程的工作目录//第三个参数表示加载xxx开头的环境变量,''表示加载所有环境变量constenv=loadEnv(mode,process.cwd(),'')console.log(env.VITE_SOME_KEY)//123console.log(env.DB_PASSWORD)//foobarreturn{//配置信息}})In实际开发中,我们也可能会用到测试环境和预发布环境。这时候需要创建两个环境变量文件:.env.test和.env.staging。//.env.testNODE_ENV=developmentVITE_SOME_KEY=456//.env.stagingNODE_ENV=productionVITE_SOME_KEY=789然后在package.json中添加一个运行命令。"scripts":{"test":"vite--modetest","staging":"vitebuild--modestaging"}生产环境搭建虽然原生ES-Module现在已经得到了广泛的支持,但是由于嵌套导入会产生额外的费用网络往返,在生产中发布未打包的ES模块仍然非常低效(即使使用HTTP/2)。为了在生产环境中获得最佳的加载性能,更好地利用tree-shaking、懒加载、分块等技术,Vite将生产环境的搭建交给了Rollup。我们可以通过构建配置选项自定义构建流程,例如直接通过build.rollupOptions调整底层Rollup选项,使用build.assetsInlineLimit修改图片转base64的阈值。//vite.config.jsexport默认defineConfig({build:{rollupOptions:{//https://rollupjs.org/guide/en/#big-list-of-options},assetsInlineLimit:4096,//4kb}})在生产环境中,我们不得不考虑一个问题,那就是浏览器兼容性。默认情况下,Vite目标浏览器支持原生ESM脚本标签,原生ESM动态导入和import.meta:Chrome>=87Firefox>=78Safari>=13Edge>=88但是我们可以使用@vitejs/plugin-legacy插件来兼容使用旧版本的浏览器。#必须安装Terser,@vitejs/plugin-legacy将使用Terser进行压缩npminstallterser-D//vite.config.jsimportlegacyfrom'@vitejs/plugin-legacy'exportdefault{plugins:[legacy({//defaults是Browserslist推荐的值targets:['defaults','notIE11']})]}生产环境中有很多实用的配置,我就不一一介绍了,大家可以上官方网站。总结今天分享的内容很多,不知道大家吸收得怎么样。其实Vite还有很多话要说。本次主要是帮助大家对Vite有一个整体的了解。后面我会继续分享Vite的配置和性能优化。