×

Vite 基础知识

独孤求败 独孤求败 发表于2026-02-14 09:22:40 浏览18 评论0

抢沙发发表评论

https://cn.vitejs.dev/config/

依赖浏览器自动解析 ESM 的能力

Q:为什么 vite.config.js 可以写成 ESM 的形式?
A:因为 vite 在读取该文件时会先用 node 去解析该文件,将其转换为 commonjs 规范,然后再去执行。

Q:vite 是怎么让浏览器识别.vue 文件的?
A: 因为 vite 会将所有的资源文件都视为模块,包括.vue 文件。当浏览器请求一个.vue 文件时,vite 会将其转换为 ESM 规范的模块,然后返回给浏览器。

0 环境变量

vite 内置了第三方库 dotenv,用于加载环境变量。

dotenv 会自动读取项目根目录下的 .env 文件,将.env 文件中定义的环境变量通过配置加载到 process.env 中。

相关配置:rootenvDirenvPrefix

1 预构建(开发环境)

1.1 依赖预构建

esbuild

  • • 绝对路径转换

import _ from 'lodash' 会被转换为 import _ from '/node_modules/.vite/lodash.js'

  • • cjs 规范统一转换

将 cjs 规范的依赖包转换为 ESM 规范,并缓存在 node_modules/.vite/dep/ 目录下

  • • 瀑布依赖处理(解决网络多包传输性能问题)

例如 lodash-es 中的方法会循环依赖多个包的其他方法

import { debounce } from 'lodash-es'

vite 会将这些循环的依赖打包到一个文件中,避免网络传输多个包的问题

1.2 处理 css

  1. 1. 检测到 css 文件的引用路径
  2. 2. 根据该路径读取 css 文件内容
  3. 3. 创建 style 标签,将 css 内容插入到标签中
  4. 4. 将 style 标签插入到 head 标签中
  5. 5. 将 css 文件中的内容替换为 js 脚本,方便后续热更新和 css 模块化,同时设置请求头 Content-Type: javascript,使浏览器按照 js 脚本执行该文件

Q:css 模块化是什么?
约定文件命名 xxx.module.css,将原来的类名附带上哈希值,解决多个文件 class 类命名重复导致的样式覆盖问题。

vite 相关配置:

  • • css.modules.localsConvention 类名单词连接方式
  • • css.modules.scopeBehaviour 模块化行为方式
  • • css.modules.generateScopedName 生成的类名展示方式
  • • css.modules.hashPrefix 生成 hash 的前缀
  • • css.modules.globalModulePaths 排除不想参与 css 模块化的路径

css 预处理器全局配置:

  • • css.preprocessorOptions.less 预处理器 less 选项

1.3 配置 postcss

主要解决浏览器兼容性问题

  1. 1. 处理 css 变量、函数、嵌套语法:var()
  2. 2. 前缀补全:--webkit-xxx
  3. 3. 高级 css 语法降级

预设环境插件: postcss-preset-env

vite 相关配置:

  • • css.postcss.plugins:[postcssPresetEnv()]

1.4 处理静态资源

  • • resolve.alias 设置别名
  • • build.rollupOptions.output.assetFileNames 静态资源文件名配置规则
  • • build.assetsInlineLimit 内联资源体积限制,默认 4096 字节(4kb),超过该值的资源会被单独打包
  • • build.outDir 构建输出目录,默认 dist
  • • build.assetsDir 静态资源输出目录,默认 assets

Q:别名 resolve.alias 的原理是什么?

根据别名配置对文件中使用别名的地方进行字符串替换。

Q:为什么解析路径一定要使用 path.resolve()?

node 端读文件的时候,如果发现是相对路径(./a.css),则会用 process.pwd()来拼接。但我们希望是基于当前文件去生成 a.css 的绝对路径,所以要用__dirname 拼接,还要处理不同系统反斜杠等其他问题,而 path.resolve()可以帮我们处理这些问题。

__dirname 始终返回的是当前文件所在目录的绝对路径。
__filename 始终返回的是当前文件的绝对路径。

2 构建打包(生产环境)

rollup

3 vite 插件

Q:什么是插件?

在生命周期不同阶段调用不同的插件实现不同的目的。enforce: pre/post 控制插件的执行时机。

vite 独有钩子:

  • • config 在解析 vite 配置前调用,必须返回配置对象,vite 会自动合并这些配置
  • • configResolved 在解析 vite 配置后调用
  • • configureServer 用于自定义配置开发服务器
  • • transformIndexHtml 转换 index.html,支持异步,返回的内容会更新到 html 模板
  • • configPreviewServer 自定义预览相关的配置
  • • handleHotUpdate 自定义热更新行为

通用钩子:

  • • options rollupOptions 相关的配置
  • • ...

常用插件:

  • • vite-aliases 检测当前目录下的所有文件,帮我们自动生成别名。等同于 resolve.alias 配置
  • • vite-plugin-html 动态控制 html 模板的内容
  • • vite-plugin-mock 生成 mock 数据

vite 相关配置:

  • • plugins: [viteAliases(), createHtmlPlugin(), viteMockServe()]
// 手写vite-aliases插件
import
 path from "path";
import
 fs from "fs";

export
 default function (keyPrefix = "@"): Plugin {
  return
 {
    name
: "MyViteAliases",
    config
(config, env) {
      // const { mode, command } = env;


      // 获取所有目录

      const
 dirs = [];
      const
 result = fs.readdirSync(path.resolve(__dirname, "../src"));
      result.forEach((name) => {
        const
 currentFileStat = fs.statSync(
          path.resolve(__dirname, "../src", name)
        );
        const
 isDir = currentFileStat.isDirectory();
        if
 (isDir) {
          dirs.push(name);
        }
      });

      // 生成别名配置

      const
 resolve = {};
      dirs.forEach((dir) => {
        resolve[`${keyPrefix}/${dir}`] = path.resolve(__dirname, "../src", dir);
      });

      return
 {
        resolve,
      };
    },
  };
}

4 共享选项

root

默认: process.cwd()

项目根目录(index.html 文件所在的位置)

envDir

默认: root

环境变量文件所在目录,默认是项目根目录

envPrefix

默认: VITE_

环境变量前缀,以该前缀开头的变量会通过 import.meta.env 暴露在客户端代码中,也可以通过 loadEnv 函数获取。

5 依赖优化选项(开发环境)

optimizeDeps.exclude

在预构建中强制排除的依赖项。

CommonJS 的依赖不应该排除在优化外。如果一个 ESM 依赖被排除在优化外,但是却有一个嵌套的 CommonJS 依赖,则应该为该 CommonJS 依赖添加 optimizeDeps.include。

export default defineConfig({
  optimizeDeps
: {
    include
: ["esm-dep > cjs-dep"],
  },
});

optimizeDeps.include

在预构建中强制包含的依赖项。

6 构建选项(生产环境)

不想写了,看官网文档吧。。。

7 性能优化

开发相关:

  • • 构建速度优化:vite 预构建
  • • 动态导入:按需加载

构建相关:

  • • 体积优化:gzip 压缩、tree shaking、图片资源压缩、分包策略
  • • 带宽优化:cdn 加速(vite-plugin-cdn-import,在 head 中动态插入 script)

页面性能指标:

  • • 首屏渲染时长 fcp:
    • • 懒加载
    • • http 优化
    • • 协商缓存:与服务器协商,服务器会查看文件是否发生变化,没变化返回 304
    • • 强缓存:服务端给响应头设置的一些字段 expires
  • • 页面最大元素渲染时长 lcp

js 逻辑:

  • • 副作用清除:定时器、事件监听
  • • 浏览器:重绘、重排、浏览器帧率(requestAnimationFrame、requestIdleCallback)
  • • 写法上:用 lodash 等工具

css:

  • • 能继承的不要重复写
  • • 嵌套层级不要过深

 

结语

框架作为我们大前端人工程化的工具,可一定要学好哦


群贤毕至

访客