# Uni App Vite 项目基础配置

<p align="center">
  <img src="https://img.shields.io/npm/dw/@plugin-light/project-config-uni-vite">
  <img src="https://img.shields.io/npm/unpacked-size/@plugin-light/project-config-uni-vite">
  <img src="https://img.shields.io/npm/v/@plugin-light/project-config-uni-vite">
  <img src="https://img.shields.io/npm/l/@plugin-light/project-config-uni-vite">
  <img src="https://img.shields.io/badge/TypeScript-strict-blue?logo=typescript&logoColor=white" alt="TypeScript strict">
  <img src="https://img.shields.io/badge/created-2022--01-blue?logo=github&logoColor=white">
</p>

封装 `vite.config.ts` 的基本配置，开箱即用。

## 1. 作者

**novlan1**

## 2. 如何使用

安装

```bash
pnpm add @plugin-light/project-config-uni-vite -D
```

在 `vite.config.ts` 中添加如下设置：


```js
import { getUniVue3ViteConfig } from '@plugin-light/project-config-uni-vite';

import { defineConfig } from 'vite';

export default defineConfig(({ mode }) => {
  return getUniVue3ViteConfig({ mode });
});
```

## 3. 参数

[完整类型定义](https://github.com/novlan1/plugin-light/blob/master/packages/project-config-uni-vite/src/types.ts)。

| 属性 | 类型 |  <p style="width:300px">说明</p>  |  <p style="width:300px">默认值</p>  |
| --- | --- | --- | --- |
| mode | `string` | 模式 | - |
| uni | `any` | `uni` 插件 | - |
| port | `CommonServerOptions['port']` | 端口，传递给 `server.port`。⚠️ `uni-app` 项目下**不生效**，端口由 `manifest.json` 的 `h5.devServer.port` 决定，详见[常见问题 4.10](#_4-10-如何修改-dev-server-端口) | `443` |
| https | `Server` | `https` 配置，传递给 `server.https`。⚠️ `uni-app` 项目下同样由 `manifest.json` 的 `h5.devServer.https` 决定 | - |
| host | `CommonServerOptions['host']` | `host` 配置，传递给 `server.host` | `true` |
| useMkcert | `boolean \| IMkcertOptions` | 是否启用 [vite-plugin-mkcert](https://www.npmjs.com/package/vite-plugin-mkcert)，为本地 dev server 生成受系统信任的 HTTPS 证书，仅 H5 下生效。使用 `whistle` 等代理中转 HTTPS 请求到本地时**强烈推荐开启**，详见[常见问题 4.11](#_4-11-usemkcert-何时需要开启) | `true` |
| prePlugins | `Array<Plugin>` | 前置插件 | - |
| postPlugins | `Array<Plugin>` | 后置插件 | - |
| optimizeDepsIncludes | `Array<string>` | 对应 `optimizeDeps.include` | - |
| removeVueDirectionOptions | `IRemoveVueDirectionOptions` | [remove-vue-direction](./vite-plugin-remove-vue-directive.html) 插件参数 | - |
| hmr | `ServerOptions['hmr']` | `hmr` 选项 | `{ timeout: 1000 * 60 * 5 }` |
| warnList | `ICrossGameStyleOptions['warnList']` | 语法警报列表，比如 `v-model`，`destroyed` | - |
| transformWebTagOptions | `boolean \| TransformWebTagOptions` | [transform-web-tag](./postcss-plugin-transform-web-tag.html) `postcss` 插件参数 | - |
| removeSelectorOptions | `boolean \| RemoveSelectorOptions` | [remove-selector](./postcss-plugin-remove-selector.html) `postcss` 插件参数 | - |
| uniTailwindOptions | `boolean \| UniTailwindPluginUserOptions` | [uni-tailwind](https://www.npmjs.com/package/@uni-helper/vite-plugin-uni-tailwind) 插件参数 | - |
| tailwindcssOptions | `boolean \| Parameters<typeof tailwindcss>[0]` | [tailwindcss](https://www.npmjs.com/package/tailwindcss) `postcss` 插件参数 | - |
| buildOptions | `BuildOptions` | 构建选项 | - |
| useChunkSplit | `boolean` | 是否使用 [chunk-split](./vite-plugin-chunk-split.html) | `false` |
| useLegacy | `boolean \| LegacyOptions` | 是否使用 [@vitejs/plugin-legacy](https://www.npmjs.com/package/@vitejs/plugin-legacy)，传递对象格式将作为插件参数 | `false` |
| uniOptions | `any` | 传递给 [uni](https://www.npmjs.com/package/@dcloudio/vite-plugin-uni) 插件的参数 | - |
| useESBuildPlugin | `boolean \| ESBuildOptions` | 是否使用 [rollup-plugin-esbuild](https://www.npmjs.com/package/rollup-plugin-esbuild)，传递对象格式将作为插件参数 | - |
| usePMDNetworkV2 | `boolean` | 是否使用 `pmd-network-v2` 替代 `pmd-network` | `false` |
| usePolling | `boolean` | 是否使用文件轮询监听（`usePolling`），轮询比原生 `fs.watch` 慢且 CPU 占用高，仅在 Docker/WSL 等不支持 inotify 的环境下需要开启 | `true` |
| useVisualizer | `boolean` | 是否开启 `visualizer` 产物分析插件，设为 `false` 可跳过 gzip/brotli 计算，加快构建速度 | `true` |
| useNodeResolve | `boolean` | 是否使用 `@rollup/plugin-node-resolve`，Vite 内部已有 resolve 能力，关闭可减少重复解析开销 | `true` |
| buildTarget | `string` | 构建目标，传递给 `build.target`（仅 H5 生效）。不需要兼容旧浏览器时可设为 `es2020` 或 `esnext` 以减少 polyfill，加快构建 | `'es2015'` |

## 4. 常见问题

### 4.1. 支持的 `node.js` 版本

`node.js` 版本 >= 16

### 4.2. 环境变量如何注入

支持在环境变量文件中配置 `VUE_APP_DIR`，环境变量文件可以是 `.env`, `.env.local` 等，举例如下：

```bash
UNI_INPUT_DIR = './src/project/guandan-match'
VUE_APP_DIR = project/guandan-match
```

### 4.3. 对外脚本怎么用

本插件导出了几个脚本，外部可以使用。

1. 修复 `uni-app` 中 `monorepo` 仓库下打包路径问题

原理是修改了 `node_modules/@dcloudio/uni-cli-shared/dist/utils.js` 源码中的 `normalizeNodeModules` 方法，增加了下面这句：

```ts
str = str.replace(/^[./]*/, '');
```

使用方式：

```ts
require('@plugin-light/project-config-uni-vite/public-script/uni/fix-uni-dir');
```

2. 修复 `uni-app` 小程序下样式文件变化无法重新编译的问题


小程序开发时，独立的 `sass` 文件改动后并不会重新编译，用一个全新的示例工程也不可以。看了下源码，`uni-app` 是用 `import('vite').then({build}=>{})` 这种方式来启动的。

解决办法是利用 `gulp.watch`，监听 `./src/**/*.scss` 文件，然后修改下 `main.ts`，然后这样就能重新编译了。同时加上了 `debounce`。

使用方式：

```ts
require('@plugin-light/project-config-uni-vite/public-script/watch/watch-sass')();
```

### 4.4. SCSS 警告说明是怎么做的

配置中屏蔽了 [import](https://sass-lang.com/documentation/breaking-changes/import/)、[legacy-js-api](https://sass-lang.com/documentation/breaking-changes/legacy-js-api/)、[mixed-decls](https://sass-lang.com/documentation/breaking-changes/mixed-decls/) 的相关警告信息。

原因如下：

1. `uni-app` 会把 `uni.scss` 放到业务每个 `scss` 前面，所以 `@import` 改成 `@use` 后，会报错 `@use rules must be written before any other rules`

2. `legacy-js-api` 问题，也是 `uni-app` 中使用了 `node-sass` 的 `renderSync`

3. `mixed-decls` 问题，涉及到样式优先级问题，业务自己判断即可

### 4.5. useChunkSplit 含义是什么

设置 `useChunkSplit` 为 `true` 后，将会开启：

1. 将 `aegis-v2`、`axios` 作为外链
2. 将一些库单独拆包
   - `t-comm、press-ui、press-plus、 pmd-npm` => `pmd-pkg`
   - `@dcloudio/uni-h5` => `uni-h5`

仅在 H5 下有效。

### 4.6. 低版本浏览器兼容是怎么做的

使用方式为，设置 `useLegacy` 为 `true`。

原理，使用了 [@vitejs/plugin-legacy](https://www.npmjs.com/package/@vitejs/plugin-legacy) 这个三方库，以及[修复了它不支持 `CDN` 的问题](./vite-plugin-legacy-polyfill.html)。

是否会影响 H5 在高版本浏览器的性能？基本不会，具体可自行搜索 [@vitejs/plugin-legacy](https://www.npmjs.com/package/@vitejs/plugin-legacy) 的原理。

如何判断当前项目是运行的的 `module` 产物，还是 `legacy` 产物？控制台打印 `window.__vite_is_modern_browser`，为 `true` 则表示运行的是 `module` 产物，否则为 `legacy` 产物。

### 4.7. 业务中获取分支名等变量

流水线会注入以下环境变量：

```bash
# 分支
VITE_PUBLISH_BRANCH

# 发布人
VITE_PUBLISH_AUTHOR
```

业务可以参考下面的方式获取：

```ts
const CUR_BRANCH = (import.meta.env.VITE_PUBLISH_BRANCH || 'develop').replace(/\//, '.');

const shareUrl = `https://foo/bar.${CUR_BRANCH}/`
```

### 4.8. 监听样式文件变动

UI开发某些情况会遇到下面的问题：样式文件改动，但需重新编译才能生效。这里其实是 `uni-app` 自己的问题。

解决办法如下：

1. `packages.json` 修改或添加下面的 `script`

```json
{
  "dev": "concurrently \"npm run watch:sass\" \"npm run dev:h5\"",
  "dev:mp": "concurrently \"npm run watch:sass\" \"npm run dev:mp-weixin\"",
  "watch:sass": "node script/watch-sass"
}
```

2. 增加监听脚本

```js
// script/watch-sass.js

require('@plugin-light/project-config-uni-vite/public-script/watch/watch-sass')();
```

### 4.9. HMR 失效处理方案

如果使用 `whistle` 代理时，造成 HMR 失效，解决方案如下。

在 `whistle` 中增加对 `websocket` 的代理。

```bash
# 之前配置，代理 443 端口
127.0.0.1:443  https://h5-test.igame.qq.com

# 新增配置，代理 websocket
wss://h5-test.igame.qq.com wss://127.0.0.1:443 
```

HMR 成功示例如下：

<img src="https://mike-1255355338.cos.ap-guangzhou.myqcloud.com/article/2025/7/own_mike_Ymwdnj25JbNPjnWR.gif" width="600">

HRM 失败示例如下：

<img src="https://mike-1255355338.cos.ap-guangzhou.myqcloud.com/article/2025/7/own_mike_W83TitzYiWmJGp4h.png" width="600">

另外，成功后通过浏览器“网络”面板也能看到对应的 `websocket` 链接。

<img src="https://mike-1255355338.cos.ap-guangzhou.myqcloud.com/article/2025/7/own_mike_7wSiB8mwhnBNFiXT.png" width="600">

<img src="https://mike-1255355338.cos.ap-guangzhou.myqcloud.com/article/2025/7/own_mike_bdrBEmhsBS5EMRNA.png" width="600">

注意，发现 `src/local-component/xx` 组件 以下面方式引入 `scss` 时，HMR 正常：

```scss
<style lang="scss" scoped>
@import './scss/index.scss';
</style>
```

下面形式不可以

```scss
<style lang="scss" src="./scss/index.scss" scoped></style>
```

推测是 `vite` 或其依赖模块内部问题。

解决方案，参考 [监听样式文件变动](#_4-8-监听样式文件变动)。

### 4.10. 如何修改 dev server 端口

**先说结论：`vite.config.ts` 里传 `port` 或修改 `server.port` 都不会生效**，必须改
项目的 `manifest.json`。

#### 4.10.1. 原因

`uni-app` 强行覆盖了 Vite 的 server 配置，链路如下：

1. `@dcloudio/uni-h5-vite` 插件的 `createConfig` 通过 Vite plugin config 钩子注入
   server 配置
2. server 内容来自 `manifest.json` 的 `h5.devServer` 字段
3. 关键在合并逻辑（`@dcloudio/uni-h5-vite/dist/plugin/config.js:52-63`）：**只允许
   用户的 `vite.config.ts.server` 覆盖 `host / fs / watch` 三个字段**，其他字段
   （`port / https / proxy / disableHostCheck` 等）一律以 `manifest.json` 为准

也就是说 `vite.config.ts` 里的 `server.port = 8443` 会被 `manifest.json` 里的
`h5.devServer.port = 443` 覆盖，最终 dev server 还是跑在 443。

#### 4.10.2. 正确改法

修改项目下 `manifest.json` 的 `h5.devServer`：

```json
{
  "h5": {
    "devServer": {
      "port": 8443,
      "https": true,
      "disableHostCheck": true
    }
  }
}
```

保存后重启 `dev` 脚本即可。

#### 4.10.3. 常见配合场景

配合 `whistle` 代理时，规则里的端口要与 `manifest.json` 保持一致：

```bash
# manifest.json 里 h5.devServer.port 改为 8443 后，whistle 规则同步改
127.0.0.1:8443  https://h5-test.igame.qq.com
```

### 4.11. useMkcert 何时需要开启

**推荐场景**：使用 `whistle` 等代理把 HTTPS 请求（如 `https://h5-test.igame.qq.com/`）
中转到本地 dev server 时，需要开启。

#### 4.11.1. 原因

- `whistle` 会用自己的 CA 对外承担 TLS，然后**以 HTTP 或 HTTPS 方式回源**到本地
  dev server
- 本插件默认使用 `@vitejs/plugin-basic-ssl` 生成的临时自签名证书。这类证书**不受
  系统信任**、每次启动随机变化、Node.js TLS 握手容易不稳定，导致 `socket hang up`
  等错误
- `vite-plugin-mkcert` 会生成一个受 macOS/Windows 系统信任的 root CA + `localhost`
  证书（存在 `~/.vite-plugin-mkcert/`），首次启动会弹出系统密码框做授权

#### 4.11.2. 使用方式

```ts
import { getUniVue3ViteConfig } from '@plugin-light/project-config-uni-vite';

export default defineConfig(({ mode }) => {
  return getUniVue3ViteConfig({
    mode,
    uni,
    useMkcert: true,          // 使用默认 { source: 'coding' }（内网友好）
    // useMkcert: { source: 'coding', hosts: ['localhost', 'my-dev.local'] },
  });
});
```

#### 4.11.3. 首次启动步骤

1. `pnpm dev:h5` 启动后，`vite-plugin-mkcert` 会：
   - 从 `source: 'coding'` 镜像下载 `mkcert` 二进制
   - 生成 root CA 并调用系统钥匙串将其标为"始终信任"（**首次会弹密码框**）
   - 签发 `localhost / 127.0.0.1` 证书给 Vite dev server 使用
2. 之后 whistle 中转 HTTPS 请求到本地时 TLS 握手正常，浏览器打开代理域名也不再有
   证书警告

#### 4.11.4. 如何验证是否生效

```bash
# 命令行验证 —— 证书链应该显示 mkcert 的 root CA
openssl s_client -connect localhost:443 -showcerts < /dev/null | grep Issuer
```

浏览器打开 `https://localhost:{port}/` 应该看到"连接是安全的"，没有证书警告。

## 5. 更新日志

[点此查看](../changelog/project-config-uni-vite.md)
