@fchc8/vite-plugin-multi-page
Version:
A powerful Vite plugin for building multi-page applications with smart file routing and multi-strategy builds
492 lines (376 loc) • 13 kB
Markdown
# @fchc8/vite-plugin-multi-page
> English Documentation | [English Documentation](./README-EN.md)
一个强大的 Vite 插件,支持多页面应用开发,提供多策略构建、TypeScript 配置支持和命令行工具。
## 特性
- 🎯 **多页面支持**: 自动发现页面入口文件
- 🔧 **多策略构建**: 支持为不同页面配置不同的构建策略
- 📝 **TypeScript 配置**: 支持 TypeScript 配置文件
- 🚀 **CLI 工具**: 提供命令行批量构建工具
- 🔄 **热重载**: 开发服务器支持页面热重载
- 📦 **智能合并**: 自动合并多策略构建结果
## 安装
```bash
npm install @fchc8/vite-plugin-multi-page --save-dev
```
## 快速开始
### 1. 配置 Vite
在 `vite.config.ts` 中添加插件:
```typescript
import { defineConfig } from 'vite';
import { viteMultiPage } from '@fchc8/vite-plugin-multi-page';
export default defineConfig({
plugins: [viteMultiPage()],
});
```
### 2. 创建配置文件(可选)
插件提供了合理的默认配置,你可以选择:
**选项 A:无配置文件(使用默认配置)**
- 自动扫描 `src/pages/**/*.{ts,js}` 下的页面文件,目录下含有文件名main的文件作为页面入口
- 使用 `index.html` 作为模板
- 创建默认构建策略
**选项 B:最简配置**
创建 `multipage.config.ts`:
```typescript
import { defineConfig } from '@fchc8/vite-plugin-multi-page';
// 使用所有默认值
export default defineConfig(() => ({}));
```
**选项 C:完整配置**
创建 `multipage.config.ts` 或 `multipage.config.js`:
```typescript
import { defineConfig } from 'vite-plugin-multi-page';
// 方式1: 对象配置(推荐)
export default defineConfig({
entry: 'src/pages/**/*.{ts,js}',
template: 'index.html',
strategies: {
// 策略配置...
},
});
// 方式2: 函数配置(动态配置)
export default defineConfig(context => {
const { mode, command, isCLI } = context;
const isProduction = mode === 'production';
return {
// 页面入口匹配规则
entry: 'src/pages/**/*.{ts,js}',
// HTML 模板
template: 'index.html',
// 模板占位符
placeholder: '{{ENTRY_FILE}}',
// 排除的文件
exclude: ['src/shared/**/*.ts'],
// 调试模式
debug: !isProduction || isCLI,
// 构建策略
strategies: {
default: {
define: {
IS_DEFAULT: true,
API_BASE: isProduction ? '"https://api.example.com"' : '"http://localhost:3001/api"',
},
build: {
sourcemap: !isProduction,
minify: isProduction ? 'esbuild' : false,
},
},
mobile: {
define: {
IS_MOBILE: true,
API_BASE: isProduction
? '"https://mobile-api.example.com"'
: '"http://localhost:3001/mobile-api"',
},
build: {
target: ['es2015', 'chrome58', 'safari11'],
minify: isProduction ? 'terser' : false,
},
},
},
// 页面配置函数
pageConfigs: context => {
// 根据文件路径判断应用的策略
if (context.relativePath.includes('/mobile/')) {
return {
strategy: 'mobile',
define: {
PAGE_NAME: context.pageName,
MOBILE_PAGE: true,
},
};
}
// 默认策略
return {
strategy: 'default',
define: {
PAGE_NAME: context.pageName,
DEFAULT_PAGE: true,
},
};
},
};
});
```
### 3. 创建页面文件
按照约定创建页面文件:
**注意**:即使使用空配置 `defineConfig({})`,插件也会自动使用默认策略处理所有页面,确保最大兼容性。
```
src/pages/
├── home.js # → /home.html
├── about.js # → /about.html
├── mobile/
│ └── main.ts # → /mobile.html (移动端策略)
└── admin/
└── main.ts # → /admin.html
```
## 页面发现规则
插件按照以下规则发现页面入口:
1. **第一级文件** (优先级 1): `src/pages/home.js` → `/home.html`
2. **目录main文件** (优先级 2): `src/pages/mobile/main.ts` → `/mobile.html`
**目录优先原则**: 如果同时存在 `src/pages/about.js` 和 `src/pages/about/main.ts`,将使用 `src/pages/about/main.ts`。
## 构建策略
### 策略配置
策略配置支持所有 Vite 配置选项:
```typescript
strategies: {
mobile: {
define: {
IS_MOBILE: true,
},
build: {
target: ['es2015'],
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
},
},
},
// 其他 Vite 配置...
},
}
```
### 构建产物合并策略
通过 `merge` 选项控制构建产物的组织方式:
```typescript
export default defineConfig({
// ... 其他配置
merge: 'all' | 'page',
});
```
#### 可用模式
- **`all`** (默认): 所有HTML文件放在根目录,资源合并到 `/dist/assets/`
```
dist/
├── home.html
├── about.html
├── mobile.html
└── assets/
├── home-xxx.js
├── about-xxx.js
└── shared-resource.svg
```
- **`page`**: 每个页面独立打包,各自拥有完整的资源副本
```
dist/
├── home/
│ ├── index.html
│ ├── assets/
│ │ ├── home-xxx.js
│ │ └── button-loading.svg
│ └── images/
├── about/
│ ├── index.html
│ ├── assets/
│ │ ├── about-xxx.js
│ │ └── button-loading.svg
│ └── images/
└── mobile/
├── index.html
├── assets/
│ ├── mobile-xxx.js
│ └── button-loading.svg
└── images/
```
#### Page模式的优势
- ✅ **完全独立**: 每个页面目录包含所有必需资源,可独立部署
- ✅ **避免冲突**: 彻底解决了共享资源的归属问题
- ✅ **简洁命名**: 资源文件使用干净的文件名,无页面前缀
- ✅ **部署友好**: 支持CDN分发、微前端等架构模式
> **注意**:
>
> - Page模式会为每个页面创建资源副本,可能增加总体构建产物大小
> - 适合需要独立部署或有严格资源隔离需求的场景
> - `public/` 目录中的静态资源会自动复制到每个页面目录中
### 页面策略分配
通过 `pageConfigs` 函数为页面分配策略:
```typescript
pageConfigs: context => {
const { pageName, relativePath } = context;
if (relativePath.includes('/mobile/')) {
return { strategy: 'mobile' };
}
if (pageName.startsWith('admin')) {
return { strategy: 'admin' };
}
return { strategy: 'default' };
};
```
## 命令行工具
### 批量构建
```bash
# 构建所有策略
npx vite-mp
# 传递额外的 Vite 参数
npx vite-mp --host --port 3000
# 启用调试模式
npx vite-mp --debug
```
### 开发服务器
```bash
# 启动开发服务器 (所有页面)
npm run dev
# 只显示特定策略的页面
npm run dev -- --strategy mobile
```
## 使用示例
### Page模式独立部署
配置Page模式,每个页面获得完整的独立资源:
```typescript
// multipage.config.ts
export default defineConfig({
entry: 'src/pages/**/*.{ts,js}',
template: 'index.html',
merge: 'page', // 启用Page模式
strategies: {
default: {
build: {
sourcemap: false,
minify: 'esbuild',
},
},
mobile: {
build: {
target: ['es2015'],
minify: 'terser',
},
},
},
pageConfigs: context => {
if (context.relativePath.includes('/mobile/')) {
return { strategy: 'mobile' };
}
return { strategy: 'default' };
},
});
```
构建结果:每个页面都有独立的资源文件,避免共享资源缺失问题。
### 共享资源处理
在Page模式下,共享资源(如图标、样式文件)会被复制到每个页面目录:
```typescript
// src/pages/about/main.ts
import buttonIcon from '../button-loading.svg'; // 共享资源
// src/pages/mobile/main.ts
import buttonIcon from '../button-loading.svg'; // 相同的共享资源
```
构建后两个页面都会有自己的资源副本:
- `dist/about/assets/button-loading-xxx.svg`
- `dist/mobile/assets/button-loading-xxx.svg`
## 环境变量
- `VITE_BUILD_STRATEGY`: 指定单个策略构建
- `VITE_MULTI_PAGE_BUILD_SINGLE_PAGE`: 指定单个页面构建(Page模式内部使用)
- `VITE_MULTI_PAGE_STRATEGY`: 当前构建策略(自动设置)
- `VITE_MULTI_PAGE_CURRENT_PAGE`: 当前页面名称(Page模式下自动设置)
- `VITE_MULTI_PAGE_MERGE_MODE`: 当前合并模式(Page模式下自动设置)
- `IS_MOBILE`: 移动端标识 (在 define 中配置)
- `API_BASE`: API 基础地址 (在 define 中配置)
### Page模式环境变量注入
在Page模式(`merge: 'page'`)下,您可以通过 `pageEnvs` 函数为每个页面注入特定的环境变量:
```typescript
// multipage.config.ts
export default defineConfig({
merge: 'page', // 启用Page模式
// 页面环境变量注入函数
pageEnvs: context => {
const { pageName, strategy, relativePath } = context;
// 返回该页面特定的环境变量
const envs: Record<string, string> = {
VITE_CURRENT_PAGE_NAME: pageName,
VITE_CURRENT_STRATEGY: strategy || 'default',
VITE_BUILD_TIMESTAMP: new Date().toISOString(),
};
// 根据页面路径添加特定变量
if (relativePath.includes('/mobile/')) {
envs.VITE_IS_MOBILE = 'true';
envs.VITE_API_URL = 'https://mobile-api.example.com';
}
return envs;
},
});
```
#### 页面上下文 (PageContext)
`pageEnvs` 函数接收一个页面上下文对象,包含以下信息:
- `pageName`: 页面名称 (如 'home', 'mobile')
- `strategy`: 分配给该页面的策略名称
- `filePath`: 页面入口文件的绝对路径
- `relativePath`: 页面入口文件的相对路径
#### 使用场景
1. **页面特定的API配置**: 为不同页面设置不同的API端点
2. **页面标识**: 在运行时识别当前页面类型
3. **构建信息**: 注入构建时间戳、版本号等信息
4. **功能开关**: 为特定页面启用或禁用功能
#### 在代码中使用
注入的环境变量可以在代码中通过 `import.meta.env` 访问:
```typescript
// src/pages/mobile/main.ts
console.log('当前页面:', import.meta.env.VITE_CURRENT_PAGE_NAME);
console.log('当前策略:', import.meta.env.VITE_CURRENT_STRATEGY);
console.log('构建时间:', import.meta.env.VITE_BUILD_TIMESTAMP);
if (import.meta.env.VITE_IS_MOBILE === 'true') {
// 移动端特定逻辑
}
```
**注意**: `pageEnvs` 功能仅在Page模式(`merge: 'page'`)下生效,因为only这种模式下每个页面是独立构建的。
## TypeScript 支持
插件完全支持 TypeScript 配置文件:
```typescript
// multipage.config.ts
import type { ConfigFunction } from '@fchc8/vite-plugin-multi-page';
const config: ConfigFunction = context => {
return {
entry: 'src/pages/**/*.{ts,js}',
// ... 其他配置
};
};
export default config;
```
## API 参考
### 配置选项
| 选项 | 类型 | 默认值 | 描述 |
| ------------- | -------------------------- | -------------------------- | ---------------------------------- |
| `entry` | `string` | `'src/pages/**/*.{ts,js}'` | 页面入口匹配规则 |
| `template` | `string` | `'index.html'` | HTML 模板文件 |
| `placeholder` | `string` | `'{{ENTRY_FILE}}'` | 模板占位符 |
| `exclude` | `string[]` | `[]` | 排除的文件模式 |
| `debug` | `boolean` | `false` | 启用调试日志 |
| `merge` | `'all' \| 'page'` | `'all'` | 构建产物合并策略 |
| `strategies` | `Record<string, Strategy>` | `{}` | 构建策略配置 |
| `pageConfigs` | `Function \| Object` | `{}` | 页面配置 |
| `pageEnvs` | `Function` | `() => null` | 页面环境变量注入函数(仅Page模式) |
### 工具函数
```typescript
import { defineConfig, defineConfigTransform } from '@fchc8/vite-plugin-multi-page';
// 定义配置
export default defineConfig(context => ({
// 配置选项
}));
// 配置转换
const transform = defineConfigTransform((config, context) => {
// 修改配置
return config;
});
```
## 示例项目
查看 [example](./example) 目录获取完整的示例项目。
## 许可证
MIT License