Vite跟学笔记

正经人谁学Vite啊

Vite系列课程前言

冰山一角

  1. Vite: 思维比较前卫而且先进的构建工具 他确实解决了一些webpack解决不了的问题, 同时降低了一些心智负担

  2. 已经有一些大厂在使用Vite去构建项目

  3. Vite基于自己得天独厚的优势, 他未来一定会占有一席之地 前段时间阿里的面试已经在问Vite了

  4. Vite是Vue团队的官方出品, 背靠这么大的生态, Vue-cli会在下面两个版本中将vite作为预设构建工具

  5. 未来你使用vue-cli去构建vue项目的时候你要写的vue.config.js不再是webpack的配置而是vite的配置(目前只基于浏览器项目)

  6. Vite也支持直接构建react项目, 也支持构建angular项目, svelte项目也支持构建

学习模块

  1. 什么是构建工具?
  2. webpack的一个缺点在哪
  3. es module的规范
  4. vite他到底是什么东西
  5. vite的基本安装和使用
  6. vite的编译结果
  7. vite编译结果的分析
  8. vite的配置文件(可能会有节课程)
  9. vite中处理css, 静态资源怎么去做
  10. vite的插件以及常用插件的使用
  11. vite与ts的结合
  12. vite生产打包
  13. vite构建react项目, svelte项目, vue3项目
  14. vite的一个构建原理

什么是构建工具

浏览器它只能识别html css js

企业及项目可能具备哪些功能

  1. typescript: 如果遇到ts文件我们需要使用tsc将typescript代码转换为js代码
  2. React/Vue: 安装react-compiler / vue-complier, 将我们写的jsx文件或者.vue文件转换为render函数
  3. less/sass/postcss/component-style: 我们又需要安装less-loader, sass-loader等一系列编译工具
  4. 语法降级: babel —> 将es的新语法转换旧版浏览器可以接受的语法
  5. 体积优化: uglifyjs —> 将我们的代码进行压缩变成体积更小性能更高的文件
  6. …..

稍微改一点点东西, 非常麻烦

e.g.将App.tsx —> tsc —> App.jsx —> React-complier —> js文件

有一个东西能够帮你把tsc, react-compiler, less, babel, uglifyjs全部集成到一起,让我们只需要关心我们写的代码就好了

e.g.我们写的代码一变化 —> 有人帮我们自动去tsc, react-compiler, less, babel, uglifyjs全部挨个走一遍 —> js

↑这个东西就叫做构建工具

打包: 将我们写的浏览器不认识的代码 交给构建工具进行编译处理的过程就叫做打包, 打包完成以后会给我们一个浏览器可以认识的文件

构建工具承担的工作

  1. 模块化开发支持: 支持直接从node_modules里引入代码 + 多种模块化支持
  2. 处理代码兼容性: 比如babel语法降级, less,ts 语法转换(不是构建工具做的, 构建工具将这些语法对应的处理工具集成进来自动化处理)
  3. 提高项目性能: 压缩文件, 代码分割
  4. 优化开发体验:
    • 构建工具会帮你自动监听文件的变化, 当文件变化以后自动帮你调用对应的集成工具进行重新打包, 然后再浏览器重新运行(整个过程叫做热更新, hot replacement
    • 开发服务器: 跨域的问题, 用react-cli create-react-element vue-cli 解决跨域的问题,

每次改一点 —> 这个顺序还不能错

构建工具的作用

  1. 构建工具让我们可以不用每次都关心我们的代码在浏览器中如何运行,我们只需要首次给构建工具提供一个配置文件(必须),有了这个集成的配置文件以后,我们就可以在下次需要更新的时候调用一次对应的命令就好了。

  2. 如果我们再结合热更新,我们就更加不需要管任何东西了。

==它让我们不用关心生产的代码,也不用担心代码如何在浏览器运行,只需要关心我们开发怎么写得爽。==

市面上主流构建工具

  • webpack-国内主流
  • vite-国内主流,本次学习
  • parcel
  • esbuild-国内主流
  • rollup
  • grunt
  • gulp

vite相较于webpack的优势

然而,当我们开始构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长。

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

Vite 旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持 ES 模块,且越来越多 JavaScript 工具使用编译型语言编写。

  • ==采取先开启开发服务器==
  • ==不会把所有依赖都解析完==

构建工具存在的问题

项目越大,构建工具所需要处理的js代码就越多=>构建工具需要很长时间才能启动开发服务器

举一个webpack栗子

众所周知,==webpack支持多种模块化==,你的工程可能不止泡在浏览器端。

那webpack能不能改?一旦要改,将会动到它的大动脉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const loadsh = require("loadsh")//commonjs规范
import Vue from "vue"//es6规范
|
|经过一定过程,webpack转换(构建工具是运行在服务端的)

const loadsh = webpack_require("loadsh")
const Vue = webpack_require("vue")

延伸原理(不需要看懂)
(function(modules){
function webpack_require(){}
//入口是index.js
//通过webpack的配置文件得来的:webpack.config.js ./src/index.js
modules[entry](webpack_require);
},({
"./src/index.js": (webpack_require)=>{
const lodash = webpack_require("lodash");
const Vue = webpack_require("vue");
}
}))

因为webpack支持多种模块化,它一旦开始必须要统一模块化代码,意味着它需要将所有的依赖全部读一遍。

Vite呢?

当然不!

两者侧重点不一样。Vite基于es module,更关注浏览器端的开发体验;而webpack更多关注兼容性。

vite和webpack启动工程比较

  1. 是通过使用vue-cli去构建一个基于webpack的vue工程
  2. 使用vite去构建一个基于vite的vue工程
1
2
3
npm install -g @vue/cli
# OR
yarn global add @vue/cli
  • 全局安装: 这个依赖会被安装到你的用户目录, 某些依赖还会自动给你注入环境变量 别名注入一个vue
    • webpack去找寻依赖的时候他并不会只找寻当前目录的node_modules, 他会依次往上找直到在根目录都没有找到对应的依赖, 他才会报错
    • 所以我们全局安装的话无论在哪个文件夹下里都可以访问到这个依赖
  • 非全局安装
    • 生产状态: -S
    • 开发状态: -D eslint

搭建一个vite项目

必须要理解的vite脚手架和vite

  1. 全局安装create-vite ——vite脚手架
1
yarn create vite
  1. 直接运行create-vite bin目录下的一个执行配置
  • ​ 误区:认为官网中使用对应yarn create构建项目的过程也是vite在做的事情
  • ​ create-vite和vite的关系:前者内置了后者

什么是精装修?(doge)

vue-cli/create-react-app:把vue/react都下好了,同时还帮忙把配置调整到了最佳实践

create-vite: 给你一套预设,下载了各种东西,并且做好了最佳实践的配置

区分

  • vite–>webpack
  • create-vite–>vue-cli

vite启动项目初体验

vite开箱即用(out of box):你不需要做任何额外的配置就可以使用vite来帮助你处理构建工作。

在默认情况下,esmodule去导入资源的时候,要么是绝对路径,要么是相对。

既然最佳实践就是node_modules,那么为什么es官方在给我们导入非绝对路径和绝对路径资源的饿时候不默认帮我们搜寻node_modules呢??

通过网络请求去找的,太消耗性能了。

vite的预加载

1
import _ from "lodash"; // lodash可能也import了其他的东西

在处理的过程中如果说看到了有非绝对路径或者相对路径的引用, 他则会尝试开启路径补全

1
2
3
import _ from "/node_modules/.vite/lodash"; // lodash可能也import了其他的东西

import __vite__cjsImport0_lodash from "/node_modules/.vite/deps/lodash.js?v=ebe57916";

找寻依赖的过程是自当前目录依次向上查找的过程, 直到搜寻到根目录或者搜寻到对应依赖为止 /user/node_modules/lodash, ../

生产和开发

yarn dev —> 开发(每次依赖预构建所重新构建的相对路径都是正确的)

vite会全权交给一个叫做rollup的库去完成生产环境的打包

缓存 —>

实际上vite在考虑另外一个问题的时候就顺便把这个问题解决了

commonjs 规范的导出 module.exports

有的包他是以commonjs规范的格式导出 axios

依赖预构建: 首先vite会找到对应的依赖, 然后调用esbuild(对js语法进行处理的一个库), 将其他规范的代码转换成esmodule规范, 然后放到当前目录下的node_modules/.vite/deps, 同时对esmodule规范的各个模块进行统一集成

1
2
3
4
// a 
export default function a() {}

export { default as a } from "./a.js"

vite重写以后

1
function a() {}

他解决了3个问题:

  1. 不同的第三方包会有不同的导出格式(这个是vite没法约束人家的事情)
  2. 对路径的处理上可以直接使用.vite/deps, 方便路径重写
  3. 叫做网络多包传输的性能问题(也是原生esmodule规范不敢支持node_modules的原因之一), 有了依赖预构建以后无论他有多少的额外export 和import, vite都会尽可能的将他们进行集成最后只生成一个或者几个模块

vite.config.js === webpack.config.hs

vite 配置文件处理细节

  1. vite配置文件的语法提示
    1. 如果你使用的是webstorm, 那你可以得到很好的语法补全
    2. 如果你使用是vscode或者其他的编辑器, 则需要做一些特殊处理
  2. 关于环境的处理
    过去我们使用webpack的时候, 我们要区分配置文件的一个环境
    • webpack.dev.config
    • webpack.prod.config
    • webpack.base.config
    • webpackmerge

vite和ts的结合

vite他天生就对ts支持非常良好, 因为vite在开发时态是基于esbuild, 而esbuild是天生支持对ts文件的转换的

那么对ts的校验呢?

vite只对ts文件进行转换, 并不会对ts文件进行类型检查

  1. 安装一个插件: vite-plugin-eslint

我们的这个插件只会在开发时态帮助我们校验ts语法

为什么我们在vite.config.js里可以使用esmodule: 主要是因为vite在读取配置文件并执行的前一刻会进行替换

vite环境变量配置

环境变量: 会根据当前的代码环境产生值的变化的变量就叫做环境变量

代码环境:

  1. 开发环境
  2. 测试环境
  3. 预发布环境
  4. 灰度环境
  5. 生产环境

举个例子: 百度地图sdk, 小程序的sdk

APP_KEY: 测试环境和生产还有开发环境是不一样的key

  • 开发环境: 110
  • 生产环境: 111
  • 测试环境: 112

我们去请求第三方sdk接口的时候需要带上的一个身份信息

我们在和后端同学对接的时候, 前端在开发环境中请求的后端API地址和生产环境的后端API地址是一个吗? 肯定不是同一个

在vite中的环境变量处理:

vite内置了dotenv这个第三方库

dotenv会自动读取.env文件, 并解析这个文件中的对应环境变量 并将其注入到process对象下(但是vite考虑到和其他配置的一些冲突问题, 他不会直接注入到process对象下)

涉及到vite.config.js中的一些配置:

  • root
  • envDir: 用来配置当前环境变量的文件地址

vite给我们提供了一些补偿措施:我们可以调用vite的loadEnv来手动确认env文件

process.cwd方法: 返回当前node进程的工作目录

.env: 所有环境都需要用到的环境变量
.env.development: 开发环境需要用到的环境变量(默认情况下vite将我们的开发环境取名为development)
.env.production: 生产环境需要用到的环境变量(默认情况下vite将我们的生产环境取名为production)

yarn dev –mode development 会将mode设置为development传递进来

当我们调用loadenv的时候, 他会做如下几件事:

  1. 直接找到.env文件不解释 并解析其中的环境变量 并放进一个对象里
  2. 会将传进来的mode这个变量的值进行拼接: .env.development, 并根据我们提供的目录去取对应的配置文件并进行解析, 并放进一个对象
  3. 我们可以理解为
    1
    2
    3
    const baseEnvConfig = 读取.env的配置
    const modeEnvConfig = 读取env相关配置
    const lastEnvConfig = { ...baseEnvConfig, ...modeEnvConfig }

如果是客户端, vite会将对应的环境变量注入到import.meta.env里去

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

补充一个小知识: 为什么vite.config.js可以书写成esmodule的形式, 这是因为vite他在读取这个vite.config.js的时候会率先node去解析文件语法, 如果发现你是esmodule规范会直接将你的esmodule规范进行替换变成commonjs规范

【原理篇】vite是怎么让浏览器可以识别.vue文件的

1
yarn install vite

yarn create 实际上就等于在安装create-vite脚手架 然后使用脚手架的指令去构建项目

1
yarn create vite my-vue-app --template vue

我们来实现一套简单的vite的开发服务器

  1. 解决我们刚刚的这个问题
  2. 让大家对开发服务器的原理层面有一个基础的简单的认识

会涉及到node的一些知识

koa: node端的一个框架

那么我们平时去访问一个网页的时候, 我们敲下域名: baidu.com

在vite中处理css

vite天生就支持对css文件的直接处理

  1. vite在读取到main.js中引用到了Index.css
  2. 直接去使用fs模块去读取index.css中文件内容
  3. 直接创建一个style标签, 将index.css中文件内容直接copy进style标签里
  4. 将style标签插入到index.html的head中
  5. 将该css文件中的内容直接替换为js脚本(方便热更新或者css模块化), 同时设置Content-Type为js 从而让浏览器以JS脚本的形式来执行该css后缀的文件

场景:

  • 一个组件最外层的元素类名一般取名 : wrapper
  • 一个组件最底层的元素雷明明我们一般取名: .footer

你取了footer这个名字, 别人因为没有看过你这个组件的源代码, 也可能去取名footer这个类名

最终可能会导致样式被覆盖(因为类名重复), 这就是我们在协同开发的时候很容易出现的问题

cssmodule就是来解决这个问题的

大概说一下原理:

全部都是基于node

  1. module.css (module是一种约定, 表示需要开启css模块化)
  2. 他会将你的所有类名进行一定规则的替换(将footer 替换成 _footer_i22st_1)
  3. 同时创建一个映射对象{ footer: “_footer_i22st_1” }
  4. 将替换过后的内容塞进style标签里然后放入到head标签中 (能够读到index.html的文件内容)
  5. 将componentA.module.css内容进行全部抹除, 替换成JS脚本
  6. 将创建的映射对象在脚本中进行默认导出

less(预处理器): less给我们提供了一些方便且非常实用的方法

vite.config.js中css配置(modules篇)

在vite.config.js中我们通过css属性去控制真个vite对于css的处理行为

  • localConvention: 修改生成的配置对象的key的展示形式(驼峰还是中划线形式)
  • scopeBehaviour: 配置当前的模块化行为是模块化还是全局化 (有hash就是开启了模块化的一个标志, 因为他可以保证产生不同的hash值来控制我们的样式类名不被覆盖)
  • generateScopedName: 生成的类名的规则(可以配置为函数, 也可以配置成字符串规则: https://github.com/webpack/loader-utils#interpolatename)
  • hashPrefix: 生成hash会根据你的类名 + 一些其他的字符串(文件名 + 他内部随机生成一个字符串)去进行生成, 如果你想要你生成hash更加的独特一点, 你可以配置hashPrefix, 你配置的这个字符串会参与到最终的hash生成, (hash: 只要你的字符串有一个字不一样, 那么生成的hash就完全不一样, 但是只要你的字符串完全一样, 生成的hash就会一样)
  • globalModulePaths: 代表你不想参与到css模块化的路径

vite配置文件中css配置流程(preprocessorOptions篇)

主要是用来配置css预处理的一些全局参数

假设没有使用构建工具, 我们又想去编译less文件的话

1
yarn add less # lessc的编译器

你只要安装了node, 你就可以使用node index.js

你只要安装了less 你就可以使用lessc去编译less文件

less是可以定义变量的

sourceMap

文件之间的索引:

假设我们的代码被压缩或者被编译过了, 这个时候假设程序出错, 他将不会产生正确的错误位置信息 如果设置了sourceMap, 他就会有一个索引文件map

sourceMap解决的问题极其的微小, 但是他的实现过程非常的复杂

postcss

vite天生对postcss有非常良好的支持

全屋净水系统有一个了解

水龙头里来的水是自来水

自来水 从 管道里 先到这个全屋净水系统 给全屋净水系统做一些插槽 —> 去除砂砾 –> 净化细菌微生物 —> … –> 输送到水龙头 –> 我们可以喝的纯净水 (为了保证到我们嘴里喝的水是万无一失)

postcss 他的工作基本和全屋净水系统一致: 保证css在执行起来是万无一失的

都对postcss有一个误区: 他们认为postcss和less sass是差不多级别

我们写的css代码(怎么爽怎么来) –> postcss —> less –> 再次对未来的高级css语法进行降级 –> 前缀补全 –> 浏览器客户端

目前来说 less和sass等一系列预处理器的postcss插件已经停止维护了 less插件 你自己去用less和sass编译完了, 然后你把编译结果给我

所以业内就产生了一个新的说法: postcss是后处理器 less的postcss的插件就ok了

我们写的js代码(怎么爽怎么来) –> babel –> 将最新的ts语法进行转换js语法 –> 做一次语法降级 –> 浏览器客户端去执行

babel –> 帮助我们让js执行起来万无一失

1
2
3
class App {} // es6的写法

function App() {} // es3的语法

浏览器的兼容性你能考虑到吗, 预处理器并不能够解决这些问题:

  1. 对未来css属性的一些使用降级问题
  2. 前缀补全: Google非常卷 –webkit

使用postcss

  1. 安装依赖

    1
    yarn add postcss-cli postcss -D
  2. 书写描述文件

postcss配置文件的格式

  • postcss.config.js

为什么我们在服务端处理路径的时候一定要用path

vite配置文件中css配置流程(postcss篇)

直接在css.postcss中进行配置, 该属性直接配置的就是postcss的配置

  • postcss-preset-env: 支持css变量和一些未来css语法 自动补全(autoprefixer)

vite加载静态资源

什么是静态资源?

​ 图片, 视频资源

除了动态API以外, 百分之九十九资源都被视作静态资源 API –> 来了一个请求 /getUserName

vite对静态资源基本上是开箱即用的, 除了一些特殊情况(svg)

resolve.alias的原理

vite中处理svg资源

特点

  • vite对svg有特殊处理 (❌)

  • vite对svg依旧是开箱即用的

  • svg: scalable vector graphics 可伸缩矢量图形 (新的图片格式)

  • 传统图片格式: jpg, jpeg…

svg特点

  1. svg是不会失真的

  2. 尺寸小

SVG缺点

​ 没法很好的去表示层次丰富的图片信息

前端领域里更多的是用svg 去做图标

vite在生产环境对静态资源的处理

当我们将工程进行打包以后, 会发现找不到原来的资源

baseUrl: “/“

打包后的静态资源为什么要有hash

浏览器是有一个缓存机制 静态资源名字只要不改, 那么他就会直接用缓存的

刷新页面: 请求的名字是不是同一个 读取缓存

所以我们要尽量去避免名字一致

hash算法: 将一串字符串经过运算得到一个新的乱码字符串 全世界独一无二(uuid才是独一无二的 )

利用好hash算法 可以让我们更好的去控制浏览器的缓存机制

base64图片

vite插件

插件是什么?

vite会在生命周期的不同阶段中去调用不同的插件以达到不同的目的

  1. 生命周期: 其实就和我们人一样, vite从开始执行到执行结束, 那么着整个过程就是vite的生命周期

  2. webpack: 输出html文件的一个插件 清除输出目录: clean-webpack-plugin

  3. 中间件 , 插件

  4. redux中间件是干嘛的: redux会在整个生命周期的不同阶段去调用不同的中间件以达到不同的目的

vite-aliases

插件学习由简入繁

vite-aliases可以帮助我们自动生成别名: 检测你当前目录下包括src在内的所有文件夹, 并帮助我们去生成别名

{

“@”: “/**/src”,

“@aseets”: “/**/src/assets”,

“@components”: “/**/src/components”,

}

nvm: node的一个版本管理工具

手写vite-alias插件

整个插件就是在vite的生命周期的不同阶段去做不同的事情

比方说vue和react会给你提供一些生命周期函数:

  • created

  • mounted

生命周期钩子

我们去手写Vite-aliases其实就是抢在vite执行配置文件之前去改写配置文件

通过vite.config.js 返回出去的配置对象以及我们在插件的config生命周期中返回的对象都不是最终的一个配置对象

vite会把这几个配置对象进行一个merge合并

{…defaultConfig, …specifyConfig}

vite常用插件之vite-plugin-html

webpack –> webpack-html-plugin / clean-webpack-plugin (clean: true)

其实就是因为vite他内置了非常多的插件, 然后我们作为普通的开发者不需要承担这么高的心智负担

vue react

vite也集成了vue团队一贯的作风 减少心智负担 css-loader less-loader ts-loader

vite将很多核心插件全部内置了

就是帮我们动态的去控制整个html文件中内容

ejs在服务端会用的比较频繁 因为服务端可能经常会动态的去修改index.html的内容

vite常用插件之vite-plugin-mock

mock数据: 模拟数据

前后端一般是并行开发 用户列表 ( 接口文档 )

mock数据 去做你前端的工作

  1. 简单方式: 直接去写死一两个数据 方便调试
  • 缺陷:

    • 没法做海量数据测试
    • 没法获得一些标准数据
    • 没法去感知http的异常

    axios: http请求库

  1. mockjs: 模拟海量数据的, vite-plugin-mock的依赖项就是mockjs

https://github.com/vbenjs/vite-plugin-mock

# 手写vite-plugin-mock

- config

- configureSever

- transformIndexHtml