Vite背后的技术原理🚀:为什么选择Vite作为你的前端构建工具💥

构建工具

什么是构建工具

vite和webpack一样都是一个构建工具,是一个可以让我们不用关心代码是如何在浏览器中运行的一个工具,构建工具帮我们解决了所有生产环境会遇到的问题,里面对一些处理工具进行了集成,我们只需要给构建工具提供配置一个文件即可帮助我们完成很多复杂的操作。市面上主流的构建工具有webpack、vite、esbuild、rollup、gulp等。

作用

  1. 在开发项目的过程中我们会用到很多不同的开发语言(vue、react、ts...),但是浏览器只认识html、css和js,在这个过程中构建工具就会自动帮我们完成代码的编译工作,也不需要我们手动来执行,比如vue中会把模板编译成render函数、ts中执行tsc命令转换成浏览器可以识别的代码。
  2. 模块化开发支持,并且支持多种模块化(CommonJS),下面这种引入方式是我们在做项目过程中经常使用的,但是在原生script标签中这样使用会报错,原因是浏览器会把这种绝对路径识别为在引入第三方库,引入第三方库的话需要从node_modules中引入,但浏览器并不认识node_modules,这是因为浏览器遵循的是esmodule语法,esmodule去导入资源的时候要么是绝对路径要么是相对路径,不会默认帮我们去搜寻node_modules,所以会报错,因此这里必须是一个相对路径浏览器才能识别,这个问题构建工具也帮助我们完成了。
js 复制代码
<script type="module">
      // 浏览器中运行会报错,因为浏览器并不认识node_modules,至于为什么不认识后文会解释原因
      import $ from 'jquery';
      // CommonJS
      const jquery = require('jquery');
</script>

这里稍微拓展一下,为什么浏览器不尝试支持这种方式呢?因为浏览器并不知道被引入的模块中是否引入了更多的依赖,如果浏览器一旦支持自动识别node_modules文件夹,因为浏览器支持esmodule语法(使用import引入)就会把被引入的第三方库依赖的模块一并加载进来,非常消耗资源,拿上面的例子来说jquery自身可能还会依赖其他模块中的文件,引入jquery的同时它自身所依赖的模块也会被加载进来,这样非常消耗网络资源的性能。但是CommonJS规范却可以这样做,因为CommonJS是运行在服务端的,查找文件的过程不是通过网络而是直接读取本地的文件。

  1. 兼容低版本的浏览器需要进行的语法降级(不是构建工具做的,构建工具中的处理工具会自动处理)。
  2. 提高项目性能:打包过程中会进行压缩文件、代码分割。
  3. 优化开发体验:自动监听文件变化自动调用对应的集成工具重新运行(热更新 hot replacement).

vite VS webpack

首先了解一下vite出现的背景以及解决了什么问题,下面是官网中的一段描述 vite背景

当我们开始构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。我们开始遇到性能瓶颈 ------ 使用 JavaScript 开发的工具(构建工具)通常需要很长时间(甚至是几分钟!)才能启动开发服务器,即使使用 HMR,文件修改后的效果也需要几秒钟才能在浏览器中反映出来。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和幸福感。

意思就是当项目越来越庞大时构建工具所要处理的代码就越多,这时候项目的启动包括修改后重新运行都会受到影响。 这其实跟webpack的构建过程有关,并且webpack无法解决这个问题,原因在于webpack是支持多种模块化的,比如代码中有commonjs和ESmodule语法,经过构建工具处理后浏览器是可以正确识别两种语法的。

js 复制代码
const lodash = require('lodash'); // comonjs规范
import Vue from 'vue'; // ESmodule

webpack是允许我们这么写的,这里简单说下webpack的编译原理,在webpack内部会使用AST抽象语法分析的工具分析出js文件中有哪些导入导出操作并把他们进行转换。但浏览器只认识esModule语法,所以webpack一开始就需要统一模块化代码,这也意味着需要将所有的依赖文件读一遍,所以当项目越大,webpack需要读的文件越多, 需要转换的文件就越多。

webpack为什么要支持多种模块化? 原因是因为我们的代码不只是跑在浏览器端,还可以跑在服务端,在服务端也允许我们使用同样的写法,所以webpack考虑的更多的是兼容性的问题,vite关注的是浏览器端的开发体验 ,vite是基于esModules的,所以不需要对所有的依赖文件进行读取和统一,两者侧重点不同,所以说vite是无法直接替代webpack的。

对比官网中的两张图可以看出两者在启动开发服务器上的区别,webpack会先把入口文件中依赖的模块全部编译打包后再启动开发服务器,而vite则会先启动开发服务器然后根据当前页面按需加载所需模块。

区分vite脚手架和vite

在vite的官网中有写到安装vite的命令为npm create vite或者也可以用yarn,那么下面就来梳理一下执行这行命令后中间都经历了什么。

执行该命令后会全局帮我们安装一个东西:create-vite(vite的脚手架),就类似于安装react时的npm create react-app一样会把create后面的拼接起来。然后直接运行这个create-vite bin目录下的执行配置,其实create-vite和vue-cli一样,共同点都只是在里面做好了一些预设,比如我们要搭建一个项目,create-vite就可以帮助我们安装好vue、vite这些资源并且还会生成src、assets等文件,这就是预设的概念,它们之间只是create-vite中内置了vite,vue-cli中内置了webpack的区别,所以这里有个误区就是使用npm create构建项目的过程不是vite在做的事情而是create-vite脚手架在做的事情,vite只是一个用来打包的工具。

vite路径自动补全

在上面提到浏览器无法直接读取这样的路径,但在vite中会提供自动补全路径的功能。

js 复制代码
import $ from 'jquery';

demo

下面来做一个小的demo,新建一个名为test的文件夹,首先执行初始化项目的命令npm init -y(该命令为一键生成json文件,也可以使用 npm init命令)生成package.json文件,然后使用npm i jquery命令来安装jquery第三方组件库,接着尝试在index.html文件中引入并进行打印。

这就是最终的目录结构,在index.html中使用开启模块化的方式对index.js文件进行引入,在index.js文件中引入jquery并进行输出。

html 复制代码
// index.html
<script src='index.js' type='module'></script>
js 复制代码
// index.js
import $ from 'jquery'
console.log($)

在index.js中直接使用import $ from jquery的方式进行引入的话会报路径的错误,原因上面已经说过就不再赘述,所以现在我们要来借助vite来帮助我们进行处理。

首先要使用vite就需要先使用npm i vite的命令来进行安装,安装完成后接着在package.json文件中配置启动命令

json 复制代码
  "scripts": {
   "dev":"vite"
  },

这样直接使用npm run dev的方式就可以使用vite启动一个开发服务器,打开localhost:5173后惊奇的发现打印出了jquery的信息。

vite在处理的过程中如果看到了有绝对路径或相对路径的引用会自动开启路径的自动补全,下面在浏览器中看一下上面例子中vite处理后的结果。

vite依赖预构建

背景

我们在导入一些第三方库的时候第三方库中可能会使用commonjs规范的语法,这时esmodule是不认识的,vite又是基于esmodule规范的,所以vite会先进行依赖预构建来对这些依赖进行处理,这就是依赖与预构建的由来

过程

依赖预构建的过程首先vite会找到对应的依赖,然后调用esbuild(使用go语言编写的对js语法进行处理的一个库,可以将其他规范的代码转为esmodule规范的代码)将其规范的代码转为esmodule规范的代码,然后放到当前目录下的node_modules/.vite/deps文件夹中,同时对esmodule规范的各个模块进行统一集成。

作用

  1. 不同的第三方包会有不同的导出格式,vite没办法约束别人,统一集成esmodule规范的代码;
  2. 对路径的处理上可以直接使用/vite/.deps,方便路径重写,不再受使用相对路径或绝对路径资源引入的限制;
  3. 网络多包传输的性能问题;当引入的第三方资源引入了更多外部模块资源时,vite只会对当前的模块进行处理。

补充一个小知识点: vite.config.js是在node环境下运行的,node环境使用的是commonjs规范,为什么vite.config.js可以书写成esmodule格式,是因为vite在读取这个vite.config.js文件的时候会事先用node去解析文件语法,如果发现是esmodule规范会直接将esmodule规范替换变成common规范(因为node读取文件读出来的是一个字符串,可以使用字符串的replace方法直接将字符串中的export default 为module.exports)

vite中的环境变量处理

首先来了解一下什么是环境变量,会根据当前的代码环境产生值的变化的变量叫做环境变量。 代码环境又分为开发环境、测试环境、预发布环境、灰度环境、生产环境,项目中为什么需要使用到环境变量呢?开发过程中我们在跟后端同学对接的时候,我们在开发环境中请求的后端接口地址和生产环境中请求的后端接口地址是不一样的,之所以要进行区分是因为要避免大量测试数据出现在线上从而导致引起一些不必要的麻烦。

vite会使用一个叫dotenv的第三方库(它能将环境变量中的变量从 .env 文件加载到 process.env 中),dotenv会在启动项目时会自动读取当前文件夹下的.env文件并解析这个文件中的环境变量并将其注入到process对象

npm run dev ==> npm run dev --mode development会将mode设置为development

loadEnv()的作用: 直接找到.env文件并解析其中的环境变量并放进一个对象中,然后会根据传进来的mode这个变量的值进行拼接.env.development,并根据我们提供的目录去取对应的配置文件并解析放进另一个对象,最终合并成为一个对象(服务端获取环境变量)

在客户端vite会将环境变量放在import.meta.env中,在这个过程中vite做了一个拦截,为了防止我们将隐私性的变量直接放在import中,所以做了一层拦截,如果环境变量不是以VITE开头的vite是不会帮你注入到客户端中去的,如果想要更改这个前缀可以使用envPrefix配置。

相关推荐
老神在在0013 分钟前
SpringMVC1
java·前端·学习·spring
薛定谔的算法3 小时前
# 从0到1构建React项目:一个仓库展示应用的架构实践
前端·react.js
Tina学编程3 小时前
HTML基础P1 | HTML基本元素
服务器·前端·html
一只小风华~5 小时前
Web前端:JavaScript和CSS实现的基础登录验证功能
前端
90后的晨仔5 小时前
Vue Router 入门指南:从零开始实现前端路由管理
前端·vue.js
LotteChar5 小时前
WebStorm vs VSCode:前端圈的「豆腐脑甜咸之争」
前端·vscode·webstorm
90后的晨仔5 小时前
零基础快速搭建 Vue 3 开发环境(附官方推荐方法)
前端·vue.js
洛_尘5 小时前
Java EE进阶2:前端 HTML+CSS+JavaScript
java·前端·java-ee
吹牛不交税6 小时前
Axure RP Extension for Chrome插件安装使用
前端·chrome·axure