# 深入 vite

# vite 与 webpack

  1. 大型项目中 webpack 构建需要更多时间才能启动开发服务器。即使使用 HMR(热更新),文件修改后也需要更多时间才能在浏览器反应出来。
  2. 缘于 webpack 的编译是基于 AST 抽象语法分析工具,每次编译都会分析所有文件的导入和导出操作,且完全编译后才能开启开发服务器。
  3. vite 基于 es modules(ESM),使用 esbuild 预构建依赖,让浏览器接管了部分打包工作,在浏览器请求源码时才进行转换并按需提供源码(无需像 webpack 那样编译完就能开启开发服务器了)。
  4. 总结,vite 更快、但默认构建目标是支持 ESM 的浏览器;webpack 则兼容性更好,也支持浏览器外的更多平台。

# create-vite 脚手架

# 安装 create-vite 脚手架,并创建项目(在终端中箭头选择)
npm create vite@latest

# 或使用模板创建一个 vite + vue 的项目
npm create vite@latest my-vue-app --template vue

# 或在一个简单的项目下安装vite并运行
npm install vite -D

# 也可在全局安装 vite 后使用命令运行,以前文件夹构建为服务器 
npx vite

# 要在局域网中使用本地 IP 访问,还需要指定 host
npx vite --host 0.0.0.0 --port 8080


# 依赖预构建

vite 调用 esbuild 将其他规范的依赖(如 CommonJS 等都转为 ESM 格式),并重写导入语句为合法的路径,以便浏览器能正确导入。

解决了三个问题:

  1. 不同的三方包可能使用不同的导出规范
  2. 预构建的依赖都在 .vite/deps/.. 下,方便重写导入语句
  3. 导入一个依赖只产生一次请求,(原生 esm 规范要支持 node_modules 的话就有可能产生导入一个依赖时还需要产生更多请求来导入依赖的依赖,这样的传输性能太差了,但 vite 解决了)

# 多环境配置

vite.base.config.js
vite.dev.config.js
vite.prod.config.js
.env
.env.development
.env.production
// vite.config.js
import { defineConfig } from "vite";
import viteBaseConfig from "./vite.base.config.js"; // 默认配置
import viteDevConfig from "./vite.dev.config.js"; // 开发配置
import viteProdConfig from "./vite.prod.config.js"; // 生产配置

const envResolver = {
  serve: (mode) => Object.assign(viteBaseConfig, viteDevConfig(mode)), // vite
  build: () => Object.assign(viteBaseConfig, viteProdConfig), // vite build
};

export default defineConfig(({ command, mode }) => {
  // 服务端加载环境变量:加载 .env 的变量 + .env.[mode] 的变量,并且默认前缀为 VITE_
  // config.mode 与启动命令中参数相关 vite --mode xxx
  const env = loadEnv(mode, process.cwd(), "VITE_"); // https://cn.vitejs.dev/guide/api-javascript.html#loadenv
  return envResolver[command](mode);
});
// vite.dev.config.js
// 可以接受一个回调函数作为参数
export default defineConfig(({ mode }) => {});
// vite.prod.config.js
// 也可以接收一个对象作为参数
export default defineConfig({});
// api.js
const env = import.meta.env; // 客户端中加载环境变量,默认只加载 "VITE_" 前缀的变量(可以修改配置中的 config.envPrefix 更改)

# 配置 css 处理器

import autoprefixer from "autoprefixer";// 样式属性根据浏览器自动添加前缀,增加兼容宽容度

export default defineConfig(({
  ...
    css: {
    postcss: {// postcss 处理器像 babel 一样,保证众多css新特性能够转译为旧浏览器所执行的样式
      plugins: [autoprefixer],
    },
    preprocessorOptions: {
      scss: {
        additionalData: `@import '@/scss/common.scss';`,// 公共全局样式
      },
    },
  },
  ...
});

# 配置 import 快捷前缀

export default defineConfig(({
  ...
  // 文件夹别名 @ 为src目录
  resolve: {
    alias: {
      "@": resolve(__dirname, "../src"),
      "~@": resolve(__dirname, "../src"),// 使 css可以用 ~@/assets/img.png 引入图片
    },
    extensions: [".mjs", ".js", ".tsx", ".json", ".sass", ".scss", ".ts"],
  },
  ...
});