Vite 入门篇:学会它,一起提升开发幸福感。

news2024/11/16 13:44:28

相信大部分兄弟都体验过 Vite 了,知道它很快。但你知道它为什么快,相比 Webpack 有哪些不同吗?今天咱们就来全面了解一下 Vite ,尤其适合新手兄弟。话不多说,开整!

什么是构建工具

很多人对构建工具没有什么概念,只知道是用来打包的。那么到底什么是构建工具呢?

大家都知道浏览器只支持 Html、CSS、JavaScript,但一个企业级项目可能会用到各种各样的前端技术,如 Less、Sass、TS、Vue组件、语法降级、体积优化等,这时候我们就需要相应的工具去处理这些内容:

  • 使用 less-loader / sass-loader 处理 less / sass
  • 使用 tsc 将 typescript 转换为 javascript
  • 使用 vue-complier 将 vue 组件模板转换为 render 函数
  • 使用 babel 将 es 的新语法转换为旧版浏览器认识的语法
  • 使用 uglifyjs 将我们的代码压缩成体积更小的文件
  • ......

我们可以手动把代码挨个处理一遍,但这样效率非常低,当我们稍微修改一点代码,这个流程又要重新走一遍,非常的麻烦。有个神奇的东西,可以把以上工具集成到一起,整个流程交给它自动处理,而且当代码发生变化时,自动帮我们重新走一遍,这个东西就叫做构建工具。当然构建工具做的事情远不止于此,比如:

  1. 模块化开发支持:支持直接从 node_modules 里引入代码
  2. 处理代码兼容性:比如 less、sass、ts、语法降级
  3. 提高项目性能:压缩文件、代码分割
  4. 优化开发体验:热更新、跨域问题

构建工具减轻了我们的心智负担,让我们不用关心我们写的代码如何在浏览器运行,只用关心代码怎么写就可以了。市面上主流的构建工具有 Webpack、Vite、esbuild、Rollup、Parcel,以及最近刚出的 turbopack ,但目前最流行的依然是 Webpack 和 Vite 。

Vite 相较于 Webpack 的优势

当项目体积越来越庞大时,构建工具需要处理的代码量呈指数级增长,包含数千个模块的项目也是相当普遍。类似 Webpack 的构建工具就会遇到性能瓶颈:通常需要很长时间,甚至几分钟项目才能启动起来。即便使用热更新(HMR),也可能需几秒,甚至十几秒页面才能更新。不知道大家目前的项目怎么样,反正我们公司稍微大一点的 Vue2 项目是真的慢,等的捉急,这种情况已经很大程度影响到了我们的开发效率和幸福感。

Webpack 有没有办法进行优化呢?很难。Webpack 先递归分析各模块依赖关系-构建依赖图谱,然后进行打包,再启动本地服务器。而且 Webpack 支持多种模块化规范,比如 CommonJS 、ES-Module ,一开始就要统一模块化代码,将所有的依赖全部处理一遍。整个流程如下图:

即使使用按需加载,也有一系列工作需要做,所以 Webpack 基本没有优化空间。

那么 Vite 为什么能解决这个问题呢?

  1. 底层语言。Vite 使用 esbuild 预构建依赖。esbuild 使用 Go 编写,比用 JS 编写的打包器预构建依赖快 10-100 倍。
  2. 先启动服务器,再按需请求模块并编译。Vite 利用的是现代浏览器本身支持 ES-Module 这个特性,直接向依赖的模块发出请求。Vite 启动时不需要分析模块之间的依赖关系,也不用打包,项目越大,优势越明显。

这个是 Vite 的启动过程:

这样大家应该看得出来 Vite 为什么快了吧!

依赖预构建

上面提到了依赖预构建,可能很多兄弟对这个不太理解,这里我也来讲一下。现代浏览器已经支持 ES-Module ,但导入模块只能用相对路径或绝对路径,直接使用模块名称的方式是行不通的:

// main.js
// 假设我们已经安装了 lodash 模块
import a from './a.js' // 支持
import b from '/b.js' // 支持
import _ from 'lodash' // 报错
复制代码

依赖预构建就可以很好的解决这个问题。Vite 首先会找到依赖的模块,然后调用 esbuild,将 CommonJS 等其他规范的代码转换成 ES-Module 规范,然后把它放在 node_modules/.vite/deps 目录下,接着修改相应的引入路径。

由于浏览器是通过 HTTP 来请求模块文件的,一旦模块的依赖关系比较多的话,就会发起很多个网络请求。例如,lodash-es 内置模块超过 600 个,它们之前相互导入。当我们执行以下代码时,浏览器会同时发出 600 多个 HTTP 请求!大量的请求造成网络堵塞,导致页面的加载非常的慢。

import { debounce } from 'lodash-es'
复制代码

这时候还得靠依赖预构建,预构建将 lodash-es 整体转换为一个模块,这样我们就只需要发起一个 HTTP 请求了!

总结一下,依赖预构建为我们解决了以下三个头痛的问题:

  1. 兼容其他规范。不同的第三方依赖包会有不同的导出格式(如 CommonJS 规范)。
  2. 重写导入路径。例如 lodash 或重写为 /node_modules/.vite/deps/lodash.js?v=fef37e66 ,以便浏览器能够正确导入。
  3. 网络性能优化。Vite 会将内部有众多依赖关系的 ES-Module 模块转换为一个模块,提高页面的加载性能。

对不同内容的处理

学习一项技术,最好的方式是单独使用它。抛开脚手架工具,Vite 使用起来也非常的简单,直接在项目中安装 vite ,给个配置就可以了。当然不给也可以,Vite 会使用内置的默认配置:

npm install vite -D
复制代码
// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  // ...
})
复制代码

为了方便使用,可以在 package.json 添加启动和打包命令。

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

然后在根目录下新建一个 index.htmlnpm run dev 项目就跑起来了!

对 CSS 的处理

CSS Modules

在不同模块中定义相同类名,会导致样式被覆盖,这时候就要用到 CSS module 。以 .module.css 结尾的文件都被认为是一个 CSS modules 文件。导入这样的文件会返回一个相应的对象:

/* example.module.css */
.red {
  color: red;
}
复制代码
// main.js
import example from './example.module.css'
console.log(example) // { red: '_red_te83z_1' }
document.getElementById('foo').className = example.red
复制代码

CSS 预处理器

Vite 同时提供了对 .scss.sass.less.styl 和 .stylus 文件的内置支持,仅需安装相应的预处理器就可以了:

# .less
npm install less -D

# .scss and .sass
npm install sass -D

# .styl and .stylus
npm install stylus -D
复制代码

感觉这块要比 webpack 简单的多,webpack 需要给不同类型的文件配置不同的 loader 去处理,而 Vite 内部直接帮我们配置好了。如果使用的是 Vue 单文件组件,可以通过 <style lang="less"> 自动开启。

PostCSS

PostCSS 也是用来处理 CSS 的,只不过它更像是一个工具箱,可以添加各种各样的插件来处理 CSS 。像我们经常遇到的样式兼容性问题,如高级 CSS 语法的降级、前缀补全等,都可以通过 PostCSS 来解决。

Vite 对 PostCSS 有良好的支持,我们只需安装需要使用的插件就可以了。

npm install postcss-preset-env -D
复制代码

postcss-preset-env 是一个预设环境插件,包含高级 CSS 语法的降级、前缀补全等众多功能。接下来我们在 vite.config.js 中配置一下:

// vite.config.js
import { defineConfig } from 'vite'
import postcssPresetEnv from 'postcss-preset-env'

export default defineConfig({
  css: {
    postcss: {
      plugins: [postcssPresetEnv()]
    }
  }
})
复制代码

然后我们来写一些特别的样式:

/* index.css */
.content {
  width: clamp(100px, 30%, 200px);
  user-select: none;
}
复制代码
// main.js
import './index.css'
复制代码

打开浏览器,可以看到 CSS 已经帮我们处理好了:

整体来说 PostCSS 还是非常实用的,可以帮助我们处理各种各样的 CSS 问题。

对静态资源的处理

  1. 将资源引入为 URL 。默认情况下引入一个静态资源,会返回这个资源的 URL 路径,也就是绝对路径。

    import imgUrl from './img.png'
    console.log(imgUrl) // /src/img.png
    document.getElementById('hero-img').src = imgUrl
    复制代码

    我们可以通过添加后缀的方式,修改文件的引入方式。默认的引入方式等同于添加 ?url 后缀。

    import imgUrl from './img.png?url'
    复制代码
  2. 将资源引入为字符串。使用 ?raw 后缀可以将资源作为字符串引入,这个字符串其实就是源文件信息。

    import imgUrl from './img.png?raw'
    console.log(imgUrl) // 源文件信息
    document.getElementById('hero-img').src = imgUrl
    复制代码
  3. 导入脚本作为 Worker 。js 脚本可以通过 ?worker 或 ?sharedworker 后缀导入为 web worker。

    // worker
    import Worker from './shader.js?worker'
    const worker = new Worker()
    复制代码
    // sharedworker
    import SharedWorker from './shader.js?sharedworker'
    const sharedWorker = new SharedWorker()
    复制代码

对 JSON 的处理

JSON 文件可以被直接导入。同时也支持具名导入,帮助我们更好地利用 treeshaking :

// 导入整个对象
import json from './example.json'
// 对一个根属性使用具名导入 有效帮助 treeshaking!
import { field } from './example.json'
复制代码

对 Vue 的处理

Vite 为 Vue 提供第一优先级支持,直接使用相应的插件就好了:

  • Vue 3 支持:@vitejs/plugin-vue
  • Vue 3 JSX 支持:@vitejs/plugin-vue-jsx
  • Vue 2.7 支持:@vitejs/vite-plugin-vue2
  • Vue <2.7 支持:underfin/vite-plugin-vue2
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()]
})
复制代码

对 TS 的处理

Vite 天然支持引入 .ts 文件。Vite 使用 esbuild 将 TypeScript 转译到 JavaScript,约是 tsc 速度的 20~30 倍,同时 HMR 热更新也是非常的快 。

Vite 仅执行 .ts 文件的转译工作,并不执行任何类型检查。换句话来说,即使 IDE 提示报错,也不影响正常开发和生成环境打包。这样肯定是不行的,不然很难对代码进行有效约束。我们可以使用插件来实现这个功能:

# 用于检查的插件
npm install vite-plugin-checker -D
# typescript 是 vite-plugin-checker 的依赖
npm install typescript -D
复制代码
import { defineConfig } from 'vite'
import checker from 'vite-plugin-checker'

export default defineConfig({
  plugins: [checker({
    typescript: true
  })]
})

复制代码

然后在根目录创建 tsconfig.json 文件:

// tsconfig.json
{
  "include": ["src/**/*"] // 需要校验的文件夹
}
复制代码

这样 TS 的报错信息就会在命令行和页面上显示出来,不修正就无法继续往下开发了。

如果要在类型检查不通过时阻止生产环境打包,直接在 build 命令中添加一个指令即可:

// package.json
"scripts": {
  "dev": "vite",
  "build": "tsc --noEmit && vite build"
},
复制代码

环境变量与模式

Vite 和 Webpack 类似,都是使用 dotenv 从特定的文件中加载额外的环境变量:

.env # 所有情况下都会加载
.env.development # 开发环境会加载(名称可以通过配置修改)
.env.production # 生成环境会加载(同上)
复制代码

在客户端中我们使用 import.meta.env 获取环境变量。为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露到客户端,例如使用以下环境变量:

VITE_SOME_KEY=123
DB_PASSWORD=foobar
复制代码

客户端控制台打印结果:

console.log(import.meta.env.VITE_SOME_KEY) // 123
console.log(import.meta.env.DB_PASSWORD) // undefined
复制代码

在服务端,也就是 vite.config.js 中通过 process.env 获取环境变量。但是 vite 考虑到和其他配置的一些冲突问题, 不会将环境变量直接注入到 process.env 对象下。这时候我们可以手动进行处理:

// vite.config.js
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ command, mode }) => {
  // loadEnv() 第一个参数为当前模式
  // 第二个参数为环境变量文件所在目录,process.cwd() 返回当前 node 进程的工作目录
  // 第三个参数表示加载以 xxx 开头的环境变量,'' 代表加载所有的环境变量
  const env = loadEnv(mode, process.cwd(), '')
  console.log(env.VITE_SOME_KEY) // 123
  console.log(env.DB_PASSWORD) // foobar
  return {
    // 配置信息
  }
})
复制代码

实际开发中,我们可能还会用到测试环境和预发布环境,这时候需要创建两个环境变量文件:.env.test 和 .env.staging 。

// .env.test
NODE_ENV=development
VITE_SOME_KEY=456
复制代码
// .env.staging
NODE_ENV=production
VITE_SOME_KEY=789
复制代码

然后在 package.json 中添加一下运行指令就可以了。

"scripts": {
  "test": "vite --mode test",
  "staging": "vite build --mode staging"
}
复制代码

生产环境构建

尽管原生 ES-Module 现在得到了广泛支持,但由于嵌套导入会导致额外的网络往返,在生产环境中发布未打包的 ES-Module 效率仍然非常低(即使使用 HTTP/2)。为了在生产环境中获得最佳的加载性能,更好的利用 tree-shaking、懒加载和 chunk 分割等,Vite 把生产环境构建全权交给了 Rollup 。

我们可以通过 构建配置选项 自定义构建过程,比如,通过 build.rollupOptions 直接调整底层的 Rollup 选项 ,使用 build.assetsInlineLimit 修改图片转 base64 的阈值。

// vite.config.js
export default defineConfig({
  build: {
    rollupOptions: {
      // https://rollupjs.org/guide/en/#big-list-of-options
    },
    assetsInlineLimit: 4096, // 4kb
  }
})
复制代码

默认情况下,Vite 的目标是支持 原生 ESM script 标签 、支持原生 ESM 动态导入 和 import.meta 的现代浏览器:

  • Chrome >=87
  • Firefox >=78
  • Safari >=13
  • Edge >=88

如果要兼容旧版本的浏览器,可以使用 Vite 自带的 @vitejs/plugin-legacy 插件。

# 必须安装 Terser,@vitejs/plugin-legacy 会使用 Terser 进行压缩
npm install terser -D
复制代码
// vite.config.js
import legacy from '@vitejs/plugin-legacy'

export default {
  plugins: [
    legacy({
      // defaults 是 Browserslist 推荐的值
      targets: ['defaults', 'not IE 11']
    })
  ]
}
复制代码

小结

今天的分享内容比较多,不知道大家吸收的怎么样。其实 Vite 还是有很多东西可以讲的,这次主要是帮助大家对 Vite 有一个整体的了解,后面我会继续分享 Vite 配置篇和性能优化篇。有兴趣的兄弟欢迎关注我,关注我的专栏 Vue3 特训营 。

如果本文对你有所帮助,记得点赞支持一下哦!💕

参考资料:

  • Vite 官方中文文档

  • Vite 世界指南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RE转NFA转DFA

https://github.com/Nightmare4214/re_nfa_dfa 前置知识 ϵ\epsilonϵ代表空串 语言 某个给定字母表上一个任意的可数的串集合 正则语言/正则表达式 正则语言&#xff08;regular language&#xff09;/正则表达式&#xff08;regular expression&#xff09; 每个正则表达…

2022 SpeechHome 语音技术研讨会-回顾

2022年11月13日&#xff0c;第二届SpeechHome语音技术研讨会和第七届Kaldi技术交流会圆满落幕。本届SpeechHome语音技术研讨会由中国计算机学会、深圳市人工智能学会、小米集团、腾讯天籁实验室、语音之家主办&#xff0c;CCF语音对话与听觉专委会作为指导单位&#xff0c;由内…

【Java开发】 Spring 03:云服务器 Docker 环境下安装 MongoDB 并连接 Spring 项目实现简单 CRUD

接下来介绍一下 NoSQL &#xff0c;相比于 Mysql 等关系型的数据库&#xff0c;NoSQL &#xff08;文档型数据库&#xff09;由于存储的数据之间无关系&#xff0c;因此具备大数据量&#xff0c;高性能等特点&#xff0c;用于解决大规模数据集合多重数据种类带来的挑战&#xf…

点击化学试剂1609736-43-7,TCO-NH2 hydrochloride,反式环辛烯-氨基HCL盐

TCO-amine hydrochloride物理数据&#xff1a; CAS&#xff1a;1609736-43-7| 中文名&#xff1a; 反式环辛烯-氨基盐酸盐&#xff0c;反式环辛烯-氨基HCL盐 | 英文名&#xff1a;TCO-amine hydrochloride 结构式&#xff1a; 中文别名&#xff1a; 环辛-4-烯-1-基 (3-氨基丙…

Mvvm中的Lifecycle

lifecycle&#xff1a;一个持有activity/fragment生命周期信息的类&#xff0c;允许其他对象观察此对状态 Event:从框架和lifecycle类派发的生命周期事件&#xff0c;也就是activity和fragment的各个状态会发Event state:这个就好理解了&#xff0c;就是activity和fragment当…

工业互联与MQTT

、工业互联网 新一代信息通信技术与工业经济深度融合的新型基础设施、应用模式和工业生态&#xff0c;通过对人、机、物、系统等的全面连接&#xff0c;构建起覆盖全产业链、全价值链的全新制造和服务体系&#xff0c;为工业乃至产业数字化、网络化、智能化发展提供了实现途径&…

论文阅读-Dr.Deep_基于医疗特征上下文学习的患者健康状态可解释评估

论文地址&#xff1a;Dr.Deep&#xff1a;基于医疗特征上下文学习的患者健康状态可解释评估 (ict.ac.cn) 代码地址&#xff1a;GitHub - Accountable-Machine-Intelligence/Dr.Deep 简介&#xff1a; 深度学习是当前医疗多变量时序数据分析的主流方法。临床辅助决策关乎病人生…

深入浅出Nodejs中的大文件读写

笔者最近在做一些node端的文件读写和分片上传工作&#xff0c;在这个过程中&#xff0c;发现node读取的文件如果超过2G&#xff0c;超过了读取Blob最大值&#xff0c;会出现读取异常&#xff0c;此外在node中读写文件也受服务器RAM的限制等&#xff0c;需要分片读取&#xff0c…

2022年认证杯SPSSPRO杯数学建模A题(第二阶段)人员的紧急疏散求解全过程文档及程序

2022年认证杯SPSSPRO杯数学建模 A题 人员的紧急疏散求解 原题再现&#xff1a; 在过去的几十年里&#xff0c;由于大规模集会活动的数量和规模的增加&#xff0c;紧急疏散的问题变得越来越重要。通过有限宽度的门或狭窄通道进行疏散是最值得关注的情况之一。为了更好地理解各…

.Net Maui 开发之路(1): APP基本设置(图标、应用名称)

.Net Maui APP基本设置(图标、应用名称) 前言一、App显示名称设置二、App显示图标设置三、App加载动画设置四、App透明状态栏设置总结前言 最终实现的显示效果如下图 提示:以下是本篇文章正文内容,下面案例可供参考 一、App显示名称设置 1、在项目上右键,选择编辑项目文…

02 DevOps 之 Jenkins

1. 什么是CICD 推荐阅读&#xff1a;CICD原理及流程 CICD面试题 在要介绍jenkins之前&#xff0c;我们需要了解CICD是什么&#xff1f; Continuous Integration (CI) 持续集成 Continuous Delivery (CD) 持续交付 Continuous Deployment (CD) 持续部署 1.1 持续集成 持续集成…

Echarts折线图隐藏markPoint只显示最大值和最小值的文本,且只在该两点显示symbol

算是一个比较偏门的需求吧&#xff0c;具体UED给的设计图效果如下&#xff1a; 看起来非常简单&#xff0c;但实际实现起来……也确实简单&#xff0c;就是步骤多一点~ 我们知道Echarts提供的markPoint标注最大值和最小值是会有一个水滴图案的&#xff1a; 首先要做的就是隐藏这…

进程状态和优先级【Linux】

1.进程状态的分类 在Linux内核中&#xff0c;进程状态分为七大类&#xff0c;不同的状态有不同的含义。 下面的状态在kernel中定义&#xff1a; /* * The task state array is a strange "bitmap" of * reasons to sleep. Thus "running" is zero, and *…

深度学习笔记--Transformer中position encoding的源码理解与实现

1--源码 import torch import math import numpy as np import torch.nn as nnclass Pos_Embed(nn.Module):def __init__(self, channels, num_frames, num_joints):super().__init__()# 根据帧序和节点序生成位置向量pos_list [] for tk in range(num_frames):for st in ran…

感知机的认识和简单的实现

一、感知机perceptron 1.1 感知机的信号 只有0和1两种取值 1.2 神经元会计算传递过来的信号总和 只有当信号总和超过某个界限的时候&#xff0c;神经元才会被激活 1.3 信号权重 不同的权重对应的信号的重要性越高 二、常见的逻辑电路 与门与非门或门 2.1 思考 使用感…

@Scope与@RefreshScope注解

在SpringIOC中&#xff0c;我们熟知的BeanScope有单例&#xff08;singleton&#xff09;、原型&#xff08;prototype&#xff09;&#xff0c; Bean的Scope影响了Bean的管理方式&#xff0c;例如创建Scopesingleton的Bean时&#xff0c;IOC会保存实例在一个Map中&#xff0c;…

nest.js创建以及error相关问题

开始之前&#xff0c;你可以使用 Nest CLI 创建项目&#xff0c;也可以克隆一个 starter project&#xff08;两者的结果是一样的&#xff09;。 若要使用 Nest CLI 构建项目&#xff0c;请运行以下命令。这将创建一个新的项目目录&#xff0c;并使用核心的 Nest 文件和支撑模…

我把 CPU 三级缓存的秘密,藏在这 8 张图里

本文已收录到 GitHub AndroidFamily&#xff0c;有 Android 进阶知识体系&#xff0c;欢迎 Star。技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 进 Android 面试交流群。 前言 大家好&#xff0c;我是小彭。 在上一篇文章里&#xff0c;我们聊到了计算机存储器系统的金…

盘点机PDA搭配蓝牙便携打印机,条码标签打印,超市仓库条码管理,条码标签纸

null使用盘点机PDA&#xff0c;搭配蓝牙便携打印机&#xff0c;移动打印条码标签的操作和设置。对于商品本身没有条码的商品&#xff0c;比如&#xff1a;外购回来无条码的商品&#xff0c;工厂自己生产出来的成品&#xff0c;那么这种就需要打印商品条码进行粘贴&#xff0c;即…

Spring Security认证之登录表单配置

本文内容来自王松老师的《深入浅出Spring Security》&#xff0c;自己在学习的时候为了加深理解顺手抄录的&#xff0c;有时候还会写一些自己的想法。 自定义登录页面 文接上篇&#xff0c;这一篇学习如何自定义登录表单。我们创建一个Spring Boot项目之后&#xff0c;还是一样…