@minar-kotonoha/vite-plugin-miko 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -0
- package/index.ts +523 -0
- package/package.json +32 -0
- package/tsconfig.json +11 -0
- package/types.ts +437 -0
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# @minar-kotonoha/vite-plugin-miko
|
|
2
|
+
|
|
3
|
+
Miko 总控插件 — 一行搞定 Vue 3 SSG 项目的全部 Vite 配置。**零配置即可运行。**
|
|
4
|
+
|
|
5
|
+
## 内置
|
|
6
|
+
|
|
7
|
+
| 类别 | 插件 | 说明 |
|
|
8
|
+
|------|------|------|
|
|
9
|
+
| Vue 生态 | Vue / Vue JSX / Vue Macros / Vue Router | 文件系统路由、TSX 支持 |
|
|
10
|
+
| 布局 | vite-plugin-vue-layouts-next | 默认布局 + 项目布局 |
|
|
11
|
+
| 组件 | unplugin-vue-components | Vant 4 / Element Plus 自动导入 |
|
|
12
|
+
| 样式 | UnoCSS | 原子化 CSS |
|
|
13
|
+
| 兼容 | @vitejs/plugin-legacy | chrome 49, ios 10 |
|
|
14
|
+
| 检查 | @minar-kotonoha/linter | 构建时 Oxlint + ESLint |
|
|
15
|
+
| 启动 | vite-plugin-bootstrap | virtual:bootstrap 自动发现入口 |
|
|
16
|
+
| 外部化 | vite-plugin-external | 生产环境 CDN 加载 |
|
|
17
|
+
| 入口 | vite-plugin-index-html | dev/prod root 分离 |
|
|
18
|
+
| SSG | vite-ssg | beasties + flat 目录 |
|
|
19
|
+
| 可选 | Janus | 接口拦截器,安装后自动发现 |
|
|
20
|
+
|
|
21
|
+
## 用法
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// vite.config.ts
|
|
25
|
+
import { defineMikoConfig } from '@minar-kotonoha/vite-plugin-miko'
|
|
26
|
+
export default await defineMikoConfig()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
可选创建 `miko.config.ts` 覆盖默认值:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import type { MikoUserConfig } from '@minar-kotonoha/vite-plugin-miko'
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
uiLibrary: 'vant',
|
|
36
|
+
proxy: [
|
|
37
|
+
{ context: ['/api/**'], target: 'https://dev.example.com', changeOrigin: true },
|
|
38
|
+
],
|
|
39
|
+
} satisfies MikoUserConfig
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 配置参考
|
|
43
|
+
|
|
44
|
+
以下所有字段均为可选,包含完整默认值。
|
|
45
|
+
|
|
46
|
+
### 基础路径
|
|
47
|
+
|
|
48
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
49
|
+
|------|------|--------|------|
|
|
50
|
+
| `template` | `string` | 自动探测 | 模板目录(含 App.vue, main.ts, index.html, layouts/) |
|
|
51
|
+
| `entry` | `string` | `<template>/main.ts` | 应用入口文件路径 |
|
|
52
|
+
| `outDir` | `string` | `'./dist'` | 构建输出目录 |
|
|
53
|
+
| `pagesDir` | `string` | `'./pages'` | 文件系统路由的页面目录 |
|
|
54
|
+
|
|
55
|
+
### UI 框架
|
|
56
|
+
|
|
57
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
58
|
+
|------|------|--------|------|
|
|
59
|
+
| `uiLibrary` | `'vant' \| 'element-plus'` | `'vant'` | UI 组件库 |
|
|
60
|
+
|
|
61
|
+
### 布局
|
|
62
|
+
|
|
63
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
64
|
+
|------|------|--------|------|
|
|
65
|
+
| `layout` | `string` | `'flexible'` | 默认布局名(`layouts.defaultLayout` 的快捷方式) |
|
|
66
|
+
| `layouts.defaultLayout` | `string` | `'flexible'` | 默认布局名(与 `layout` 等效,优先级更高) |
|
|
67
|
+
| `layouts.layoutsDirs` | `string \| string[]` | `['<template>/layouts', '<cwd>/layouts']` | 布局文件目录 |
|
|
68
|
+
| `layouts.pagesDirs` | `string \| string[]` | `'<cwd>/pages'` | 页面文件目录 |
|
|
69
|
+
|
|
70
|
+
### 开发服务器
|
|
71
|
+
|
|
72
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
73
|
+
|------|------|--------|------|
|
|
74
|
+
| `proxy` | `ProxyConfig[]` | `[]` | 开发服务器代理规则 |
|
|
75
|
+
| `dev.bundledDev` | `boolean` | `true` | 启用 Rolldown bundledDev |
|
|
76
|
+
| `dev.port` | `number` | 自动分配 | 开发服务器端口 |
|
|
77
|
+
| `dev.open` | `boolean \| string` | `false` | 自动打开浏览器 |
|
|
78
|
+
|
|
79
|
+
### Vue 核心
|
|
80
|
+
|
|
81
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
82
|
+
|------|------|--------|------|
|
|
83
|
+
| `vue` | `VuePluginOptions` | `{}` | `@vitejs/plugin-vue` 选项透传 |
|
|
84
|
+
| `vueJsx` | `VueJsxPluginOptions` | `{}` | `@vitejs/plugin-vue-jsx` 选项透传 |
|
|
85
|
+
|
|
86
|
+
### 路由
|
|
87
|
+
|
|
88
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
89
|
+
|------|------|--------|------|
|
|
90
|
+
| `vueRouter.extensions` | `string[]` | `['.vue', '.setup.tsx']` | 路由文件扩展名 |
|
|
91
|
+
| `vueRouter.routesFolder` | `string` | `<pagesDir>` | 路由扫描目录 |
|
|
92
|
+
| `vueRouter.dts` | `string` | `'<cwd>/types/routes.d.ts'` | 路由类型声明路径 |
|
|
93
|
+
|
|
94
|
+
### 组件自动导入
|
|
95
|
+
|
|
96
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
97
|
+
|------|------|--------|------|
|
|
98
|
+
| `components.dirs` | `string \| string[]` | `['./components']` | 组件扫描目录 |
|
|
99
|
+
| `components.extensions` | `string[]` | `['vue', 'tsx', 'ts']` | 组件文件扩展名 |
|
|
100
|
+
| `components.dts` | `string \| boolean` | `'<cwd>/types/components.d.ts'` | 组件类型声明路径 |
|
|
101
|
+
|
|
102
|
+
### UnoCSS
|
|
103
|
+
|
|
104
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
105
|
+
|------|------|--------|------|
|
|
106
|
+
| `unoCSS` | `UnoCSSOptions \| false` | `{ configFile: false }` | 设为 `false` 禁用。`configFile: false` 使用默认预设 |
|
|
107
|
+
|
|
108
|
+
### 浏览器兼容
|
|
109
|
+
|
|
110
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
111
|
+
|------|------|--------|------|
|
|
112
|
+
| `legacy` | `LegacyOptions \| false` | `{ targets: ['chrome 49', 'ios 10'] }` | 设为 `false` 禁用 legacy |
|
|
113
|
+
|
|
114
|
+
### SSG
|
|
115
|
+
|
|
116
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
117
|
+
|------|------|--------|------|
|
|
118
|
+
| `ssg` | `SSGConfig \| false` | — | 设为 `false` 禁用 SSG(降级为纯 SPA) |
|
|
119
|
+
| `ssg.beastiesOptions` | `object` | `{ external: false }` | 资源内联与压缩 |
|
|
120
|
+
| `ssg.dirStyle` | `'flat' \| 'nested'` | `'flat'` | 输出目录结构 |
|
|
121
|
+
| `ssg.formatting` | `'none' \| 'prettier'` | `'none'` | HTML 格式化 |
|
|
122
|
+
|
|
123
|
+
### 代码检查
|
|
124
|
+
|
|
125
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
126
|
+
|------|------|--------|------|
|
|
127
|
+
| `linter` | `LinterOptions \| false` | `{ oxlint: true, eslint: true }` | 设为 `false` 禁用 linter |
|
|
128
|
+
|
|
129
|
+
### CDN 外部化
|
|
130
|
+
|
|
131
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
132
|
+
|------|------|--------|------|
|
|
133
|
+
| `external.frameworkCDN` | `string` | `unpkg` 自动地址 | Framework CDN 地址,覆盖 `.env` 中的 `VITE_FRAMEWORK_CDN` |
|
|
134
|
+
|
|
135
|
+
### Bootstrap
|
|
136
|
+
|
|
137
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
138
|
+
|------|------|--------|------|
|
|
139
|
+
| `bootstrap.entryFile` | `string` | `'index.ts'` | 启动入口文件名(相对于 cwd) |
|
|
140
|
+
|
|
141
|
+
### Janus
|
|
142
|
+
|
|
143
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
144
|
+
|------|------|--------|------|
|
|
145
|
+
| `janus` | `JanusOptions \| false` | 自动发现 | 设为 `false` 禁用。安装 `@janus/unplugin` 后自动启用 |
|
|
146
|
+
|
|
147
|
+
### 库模式
|
|
148
|
+
|
|
149
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
150
|
+
|------|------|--------|------|
|
|
151
|
+
| `lib.entry` | `string` | — | 库入口文件 |
|
|
152
|
+
| `lib.formats` | `('es' \| 'cjs' \| 'umd')[]` | `['es', 'cjs']` | 输出格式 |
|
|
153
|
+
| `lib.name` | `string` | — | 全局变量名(UMD) |
|
|
154
|
+
| `lib.fileName` | `string` | — | 输出文件名 |
|
|
155
|
+
|
|
156
|
+
## 导出
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import {
|
|
160
|
+
defineMikoConfig, // 统一入口 — await defineMikoConfig()
|
|
161
|
+
loadMikoConfig, // 加载 miko.config.ts
|
|
162
|
+
createLibConfig, // 库模式配置工厂
|
|
163
|
+
// 类型
|
|
164
|
+
type MikoUserConfig,
|
|
165
|
+
type ProxyConfig,
|
|
166
|
+
type LibConfig,
|
|
167
|
+
type SSGConfig,
|
|
168
|
+
type VueOptions,
|
|
169
|
+
type VueJsxOptions,
|
|
170
|
+
type VueRouterOptions,
|
|
171
|
+
type LayoutsUserOptions,
|
|
172
|
+
type LegacyOptions,
|
|
173
|
+
type ComponentsOptions,
|
|
174
|
+
type UnoCSSVitePluginConfig,
|
|
175
|
+
type LinterOptions,
|
|
176
|
+
type BootstrapOptions,
|
|
177
|
+
type ExternalOptions,
|
|
178
|
+
type DevOptions,
|
|
179
|
+
type JanusOptions,
|
|
180
|
+
} from '@minar-kotonoha/vite-plugin-miko'
|
|
181
|
+
```
|
package/index.ts
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # @minar-kotonoha/vite-plugin-miko
|
|
3
|
+
*
|
|
4
|
+
* `defineMikoConfig` — 一行搞定 Vue 3 SSG 项目的全部 Vite 配置。
|
|
5
|
+
*
|
|
6
|
+
* 所有插件直接展开在 defineConfig 中(不嵌套),兼容 vite-ssg。
|
|
7
|
+
*
|
|
8
|
+
* ===== 用法 =====
|
|
9
|
+
*
|
|
10
|
+
* vite.config.ts:
|
|
11
|
+
* import { defineMikoConfig } from '@minar-kotonoha/vite-plugin-miko'
|
|
12
|
+
* export default await defineMikoConfig()
|
|
13
|
+
*
|
|
14
|
+
* miko.config.ts(可选,零配置即可运行):
|
|
15
|
+
* export default {
|
|
16
|
+
* uiLibrary: 'vant',
|
|
17
|
+
* proxy: [{ context: ['/api/**'], target: 'https://dev.example.com' }],
|
|
18
|
+
* } satisfies import('@minar-kotonoha/vite-plugin-miko').MikoUserConfig
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { resolve } from 'node:path'
|
|
22
|
+
import { existsSync } from 'node:fs'
|
|
23
|
+
import { createRequire } from 'node:module'
|
|
24
|
+
import { fileURLToPath } from 'node:url'
|
|
25
|
+
import { remove } from 'fs-extra'
|
|
26
|
+
import { defineConfig, mergeConfig } from 'vite'
|
|
27
|
+
import type { PluginOption, ProxyOptions, UserConfig } from 'vite'
|
|
28
|
+
|
|
29
|
+
// Vue 生态
|
|
30
|
+
import vue from '@vitejs/plugin-vue'
|
|
31
|
+
import vueJsx from '@vitejs/plugin-vue-jsx'
|
|
32
|
+
import VueRouter from 'vue-router/vite'
|
|
33
|
+
import VueMacros from 'vue-macros/vite'
|
|
34
|
+
|
|
35
|
+
// Layouts
|
|
36
|
+
import Layouts from 'vite-plugin-vue-layouts-next'
|
|
37
|
+
|
|
38
|
+
// Linter
|
|
39
|
+
import linterPlugin from '@minar-kotonoha/linter/vite'
|
|
40
|
+
|
|
41
|
+
// Legacy
|
|
42
|
+
import legacy from '@vitejs/plugin-legacy'
|
|
43
|
+
|
|
44
|
+
// Components auto-import
|
|
45
|
+
import Components from 'unplugin-vue-components/vite'
|
|
46
|
+
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
|
47
|
+
import { VantResolver } from '@vant/auto-import-resolver'
|
|
48
|
+
|
|
49
|
+
// UnoCSS
|
|
50
|
+
import UnoCSS from 'unocss/vite'
|
|
51
|
+
|
|
52
|
+
// Miko 子插件
|
|
53
|
+
import { bootstrapPlugin } from '@minar-kotonoha/vite-plugin-bootstrap'
|
|
54
|
+
import { externalPlugin } from '@minar-kotonoha/vite-plugin-external'
|
|
55
|
+
import { indexHTMLPlugin } from '@minar-kotonoha/vite-plugin-index-html'
|
|
56
|
+
|
|
57
|
+
// 类型
|
|
58
|
+
import type {
|
|
59
|
+
MikoUserConfig,
|
|
60
|
+
ProxyConfig,
|
|
61
|
+
LibConfig,
|
|
62
|
+
SSGConfig,
|
|
63
|
+
VueOptions,
|
|
64
|
+
VueJsxOptions,
|
|
65
|
+
VueRouterOptions,
|
|
66
|
+
LayoutsUserOptions,
|
|
67
|
+
LegacyOptions,
|
|
68
|
+
ComponentsOptions,
|
|
69
|
+
UnoCSSVitePluginConfig,
|
|
70
|
+
LinterOptions,
|
|
71
|
+
BootstrapOptions,
|
|
72
|
+
ExternalOptions,
|
|
73
|
+
DevOptions,
|
|
74
|
+
JanusOptions,
|
|
75
|
+
} from './types'
|
|
76
|
+
|
|
77
|
+
// 重新导出类型供外部使用
|
|
78
|
+
export type {
|
|
79
|
+
MikoUserConfig,
|
|
80
|
+
ProxyConfig,
|
|
81
|
+
LibConfig,
|
|
82
|
+
SSGConfig,
|
|
83
|
+
VueOptions,
|
|
84
|
+
VueJsxOptions,
|
|
85
|
+
VueRouterOptions,
|
|
86
|
+
LayoutsUserOptions,
|
|
87
|
+
LegacyOptions,
|
|
88
|
+
ComponentsOptions,
|
|
89
|
+
UnoCSSVitePluginConfig,
|
|
90
|
+
LinterOptions,
|
|
91
|
+
BootstrapOptions,
|
|
92
|
+
ExternalOptions,
|
|
93
|
+
DevOptions,
|
|
94
|
+
JanusOptions,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const cwd = process.cwd()
|
|
98
|
+
|
|
99
|
+
// ===================================================================
|
|
100
|
+
// 默认值常量
|
|
101
|
+
// ===================================================================
|
|
102
|
+
|
|
103
|
+
const DEFAULTS = {
|
|
104
|
+
uiLibrary: 'vant' as const,
|
|
105
|
+
layout: 'flexible',
|
|
106
|
+
outDir: './dist',
|
|
107
|
+
pagesDir: './pages',
|
|
108
|
+
componentsDir: './components',
|
|
109
|
+
entryFile: 'index.ts',
|
|
110
|
+
extensionsRoute: ['.vue', '.setup.tsx'] as string[],
|
|
111
|
+
extensionsComponent: ['vue', 'tsx', 'ts'] as string[],
|
|
112
|
+
legacyTargets: ['chrome 49', 'ios 10'] as string[],
|
|
113
|
+
bundledDev: true,
|
|
114
|
+
} as const
|
|
115
|
+
|
|
116
|
+
// ===================================================================
|
|
117
|
+
// 路径探测
|
|
118
|
+
// ===================================================================
|
|
119
|
+
|
|
120
|
+
function detectTemplate(): string {
|
|
121
|
+
const local = resolve(cwd, 'template')
|
|
122
|
+
if (existsSync(local)) return local
|
|
123
|
+
const pkgRelative = fileURLToPath(new URL('../../template', import.meta.url))
|
|
124
|
+
if (existsSync(pkgRelative)) return pkgRelative
|
|
125
|
+
return local
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function detectEntry(template: string): string {
|
|
129
|
+
return resolve(template, 'main.ts')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ===================================================================
|
|
133
|
+
// 配置加载
|
|
134
|
+
// ===================================================================
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 从 `miko.config.ts` 加载用户配置。
|
|
138
|
+
* 文件不存在或解析失败时返回空对象。
|
|
139
|
+
*/
|
|
140
|
+
export async function loadMikoConfig(): Promise<MikoUserConfig> {
|
|
141
|
+
const configPath = resolve(cwd, 'miko.config.ts')
|
|
142
|
+
if (!existsSync(configPath)) return {}
|
|
143
|
+
try {
|
|
144
|
+
const mod = await import(configPath)
|
|
145
|
+
return (mod.default || mod) as MikoUserConfig
|
|
146
|
+
} catch {
|
|
147
|
+
return {}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ===================================================================
|
|
152
|
+
// 配置解析 —— 将用户配置与默认值合并
|
|
153
|
+
// ===================================================================
|
|
154
|
+
|
|
155
|
+
interface ResolvedConfig {
|
|
156
|
+
template: string
|
|
157
|
+
entry: string
|
|
158
|
+
outDir: string
|
|
159
|
+
pagesDir: string
|
|
160
|
+
uiLibrary: 'vant' | 'element-plus'
|
|
161
|
+
layout: string
|
|
162
|
+
layoutsDirs: string[]
|
|
163
|
+
proxy: ProxyConfig[] | undefined
|
|
164
|
+
lib: LibConfig | undefined
|
|
165
|
+
|
|
166
|
+
// 插件深度配置
|
|
167
|
+
vue: VueOptions
|
|
168
|
+
vueJsx: VueJsxOptions
|
|
169
|
+
vueRouter: VueRouterOptions
|
|
170
|
+
layouts: LayoutsUserOptions
|
|
171
|
+
components: ComponentsOptions
|
|
172
|
+
unoCSS: UnoCSSVitePluginConfig | false
|
|
173
|
+
legacy: LegacyOptions | false
|
|
174
|
+
ssg: SSGConfig | false
|
|
175
|
+
linter: LinterOptions | false
|
|
176
|
+
bootstrap: BootstrapOptions
|
|
177
|
+
external: ExternalOptions
|
|
178
|
+
dev: DevOptions
|
|
179
|
+
janus: JanusOptions | false
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function resolveConfig(cfg: MikoUserConfig): ResolvedConfig {
|
|
183
|
+
const template = cfg.template || detectTemplate()
|
|
184
|
+
const entry = cfg.entry || detectEntry(template)
|
|
185
|
+
const outDir = cfg.outDir ? resolve(cwd, cfg.outDir) : resolve(cwd, DEFAULTS.outDir)
|
|
186
|
+
const pagesDir = cfg.pagesDir ? resolve(cwd, cfg.pagesDir) : resolve(cwd, DEFAULTS.pagesDir)
|
|
187
|
+
|
|
188
|
+
// === 布局 ===
|
|
189
|
+
const layout = cfg.layouts?.defaultLayout ?? cfg.layout ?? process.env.VITE_LAYOUT ?? DEFAULTS.layout
|
|
190
|
+
const layoutsDirs = cfg.layouts?.layoutsDirs
|
|
191
|
+
? (Array.isArray(cfg.layouts.layoutsDirs) ? cfg.layouts.layoutsDirs : [cfg.layouts.layoutsDirs])
|
|
192
|
+
: [resolve(template, 'layouts'), resolve(cwd, './layouts')]
|
|
193
|
+
|
|
194
|
+
// === Vue Router ===
|
|
195
|
+
const vueRouter: VueRouterOptions = {
|
|
196
|
+
extensions: cfg.vueRouter?.extensions ?? DEFAULTS.extensionsRoute,
|
|
197
|
+
routesFolder: cfg.vueRouter?.routesFolder ?? pagesDir,
|
|
198
|
+
dts: cfg.vueRouter?.dts ?? resolve(cwd, 'types', 'routes.d.ts'),
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// === 组件 ===
|
|
202
|
+
const components: ComponentsOptions = {
|
|
203
|
+
dirs: cfg.components?.dirs ?? [resolve(cwd, DEFAULTS.componentsDir)],
|
|
204
|
+
extensions: cfg.components?.extensions ?? DEFAULTS.extensionsComponent,
|
|
205
|
+
dts: cfg.components?.dts ?? resolve(cwd, 'types', 'components.d.ts'),
|
|
206
|
+
resolvers: cfg.components?.resolvers ?? undefined,
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// === UnoCSS ===
|
|
210
|
+
const unoCSS: UnoCSSVitePluginConfig | false =
|
|
211
|
+
cfg.unoCSS === false
|
|
212
|
+
? false
|
|
213
|
+
: { configFile: false, ...cfg.unoCSS }
|
|
214
|
+
|
|
215
|
+
// === Legacy ===
|
|
216
|
+
const legacyResolved: LegacyOptions | false =
|
|
217
|
+
cfg.legacy === false
|
|
218
|
+
? false
|
|
219
|
+
: {
|
|
220
|
+
targets: DEFAULTS.legacyTargets,
|
|
221
|
+
...cfg.legacy,
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// === SSG ===
|
|
225
|
+
const ssg: SSGConfig | false =
|
|
226
|
+
cfg.ssg === false
|
|
227
|
+
? false
|
|
228
|
+
: (mergeConfig(
|
|
229
|
+
{
|
|
230
|
+
beastiesOptions: { external: false },
|
|
231
|
+
dirStyle: 'flat',
|
|
232
|
+
formatting: 'none',
|
|
233
|
+
includedRoutes(paths: string[]) {
|
|
234
|
+
return paths.filter((p) => !p.includes('node_modules'))
|
|
235
|
+
},
|
|
236
|
+
onPageRendered(_route: string, renderedHTML: string) {
|
|
237
|
+
return renderedHTML
|
|
238
|
+
},
|
|
239
|
+
async onFinished() {
|
|
240
|
+
await remove(resolve(outDir, '.vite'))
|
|
241
|
+
},
|
|
242
|
+
} as UserConfig,
|
|
243
|
+
cfg.ssg as UserConfig,
|
|
244
|
+
) as unknown as SSGConfig)
|
|
245
|
+
|
|
246
|
+
// === Linter ===
|
|
247
|
+
const linter: LinterOptions | false =
|
|
248
|
+
cfg.linter === false
|
|
249
|
+
? false
|
|
250
|
+
: { oxlint: true, eslint: true, ...cfg.linter }
|
|
251
|
+
|
|
252
|
+
// === Bootstrap ===
|
|
253
|
+
const bootstrap: BootstrapOptions = {
|
|
254
|
+
entryFile: DEFAULTS.entryFile,
|
|
255
|
+
...cfg.bootstrap,
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// === External ===
|
|
259
|
+
const external: ExternalOptions = {
|
|
260
|
+
...cfg.external,
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// === Dev ===
|
|
264
|
+
const dev: DevOptions = {
|
|
265
|
+
bundledDev: DEFAULTS.bundledDev,
|
|
266
|
+
...cfg.dev,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// === Janus ===
|
|
270
|
+
const janus: JanusOptions | false =
|
|
271
|
+
cfg.janus === false ? false : { ...cfg.janus }
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
template,
|
|
275
|
+
entry,
|
|
276
|
+
outDir,
|
|
277
|
+
pagesDir,
|
|
278
|
+
uiLibrary: cfg.uiLibrary || DEFAULTS.uiLibrary,
|
|
279
|
+
layout,
|
|
280
|
+
layoutsDirs,
|
|
281
|
+
proxy: cfg.proxy,
|
|
282
|
+
lib: cfg.lib,
|
|
283
|
+
vue: cfg.vue ?? {},
|
|
284
|
+
vueJsx: cfg.vueJsx ?? {},
|
|
285
|
+
vueRouter,
|
|
286
|
+
layouts: cfg.layouts ?? {},
|
|
287
|
+
components,
|
|
288
|
+
unoCSS,
|
|
289
|
+
legacy: legacyResolved,
|
|
290
|
+
ssg,
|
|
291
|
+
linter,
|
|
292
|
+
bootstrap,
|
|
293
|
+
external,
|
|
294
|
+
dev,
|
|
295
|
+
janus,
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ===================================================================
|
|
300
|
+
// 工具
|
|
301
|
+
// ===================================================================
|
|
302
|
+
|
|
303
|
+
function normalizeProxy(proxy: ProxyConfig[] | Record<string, string | ProxyOptions>): Record<string, string | ProxyOptions> {
|
|
304
|
+
if (Array.isArray(proxy)) {
|
|
305
|
+
const result: Record<string, string | ProxyOptions> = {}
|
|
306
|
+
for (const rule of proxy) {
|
|
307
|
+
const { context, ...options } = rule
|
|
308
|
+
for (const path of context) {
|
|
309
|
+
result[path.replace(/\/\*+$/, '')] = options as string | ProxyOptions
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return result
|
|
313
|
+
}
|
|
314
|
+
return proxy
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function loadJanus(opts: JanusOptions | false): PluginOption | null {
|
|
318
|
+
if (opts === false) return null
|
|
319
|
+
try {
|
|
320
|
+
const janusEntry = resolve(cwd, 'node_modules/@janus/unplugin/dist/unplugin.cjs')
|
|
321
|
+
if (!existsSync(janusEntry)) return null
|
|
322
|
+
const _require = createRequire(import.meta.url)
|
|
323
|
+
const mod = _require(janusEntry)
|
|
324
|
+
const janusOpts = Object.keys(opts).length > 0 ? opts : {}
|
|
325
|
+
const plugin = mod?.vite?.(janusOpts) || mod?.default?.vite?.(janusOpts)
|
|
326
|
+
if (plugin) console.log('[miko] Janus 接口拦截器已启用')
|
|
327
|
+
return plugin
|
|
328
|
+
} catch (e: unknown) {
|
|
329
|
+
console.warn('[miko] Janus 加载失败:', (e as Error)?.message)
|
|
330
|
+
return null
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ===================================================================
|
|
335
|
+
// 库模式配置工厂
|
|
336
|
+
// ===================================================================
|
|
337
|
+
|
|
338
|
+
export function createLibConfig(libOptions: {
|
|
339
|
+
entry: string
|
|
340
|
+
formats?: ('es' | 'cjs' | 'umd')[]
|
|
341
|
+
name?: string
|
|
342
|
+
fileName?: string
|
|
343
|
+
}) {
|
|
344
|
+
const { entry, formats = ['es', 'cjs'], name, fileName } = libOptions
|
|
345
|
+
|
|
346
|
+
return defineConfig({
|
|
347
|
+
build: {
|
|
348
|
+
outDir: resolve(cwd, './dist'),
|
|
349
|
+
emptyOutDir: true,
|
|
350
|
+
lib: { entry, formats, name, fileName },
|
|
351
|
+
rollupOptions: { external: ['vue', 'vue-router', 'pinia', 'axios', '@unhead/vue'] },
|
|
352
|
+
},
|
|
353
|
+
resolve: { alias: [{ find: '@', replacement: cwd }], tsconfigPaths: true },
|
|
354
|
+
plugins: [
|
|
355
|
+
VueMacros({ plugins: { vue: vue(), vueJsx: vueJsx() } }),
|
|
356
|
+
UnoCSS({ configFile: false }),
|
|
357
|
+
],
|
|
358
|
+
})
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ===================================================================
|
|
362
|
+
// 主入口
|
|
363
|
+
// ===================================================================
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* 统一配置入口 —— 直接展开所有插件和配置,不嵌套。
|
|
367
|
+
*
|
|
368
|
+
* 返回 sync defineConfig 工厂,兼容 viteSsgBuild。
|
|
369
|
+
*
|
|
370
|
+
* 配置读取优先级:`miko.config.ts`(项目根目录) > 默认值。
|
|
371
|
+
* 所有字段均可选,零配置即可运行。
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* // vite.config.ts
|
|
375
|
+
* import { defineMikoConfig } from '@minar-kotonoha/vite-plugin-miko'
|
|
376
|
+
* export default await defineMikoConfig()
|
|
377
|
+
*/
|
|
378
|
+
export async function defineMikoConfig() {
|
|
379
|
+
const raw = await loadMikoConfig()
|
|
380
|
+
const cfg = resolveConfig(raw)
|
|
381
|
+
|
|
382
|
+
// 解构已解析的配置
|
|
383
|
+
const {
|
|
384
|
+
template,
|
|
385
|
+
entry,
|
|
386
|
+
outDir,
|
|
387
|
+
pagesDir,
|
|
388
|
+
uiLibrary,
|
|
389
|
+
layout,
|
|
390
|
+
layoutsDirs,
|
|
391
|
+
proxy,
|
|
392
|
+
vue: vueOpts,
|
|
393
|
+
vueJsx: vueJsxOpts,
|
|
394
|
+
vueRouter: vueRouterOpts,
|
|
395
|
+
layouts: layoutsOpts,
|
|
396
|
+
components: componentsOpts,
|
|
397
|
+
unoCSS: unoCSSOpts,
|
|
398
|
+
legacy: legacyOpts,
|
|
399
|
+
ssg: ssgOpts,
|
|
400
|
+
linter: linterOpts,
|
|
401
|
+
bootstrap: bootstrapOpts,
|
|
402
|
+
external: externalOpts,
|
|
403
|
+
dev: devOpts,
|
|
404
|
+
janus: janusOpts,
|
|
405
|
+
} = cfg
|
|
406
|
+
|
|
407
|
+
// 设置环境变量(external 插件和 template/App.vue 通过 env 读取)
|
|
408
|
+
if (externalOpts.frameworkCDN) {
|
|
409
|
+
process.env.VITE_FRAMEWORK_CDN = externalOpts.frameworkCDN
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// 设置环境变量(自定义 bootstrap 入口文件)
|
|
413
|
+
if (bootstrapOpts.entryFile !== DEFAULTS.entryFile) {
|
|
414
|
+
process.env.MIKO_BOOTSTRAP_ENTRY = bootstrapOpts.entryFile
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
console.log(`[miko] UI 组件库: ${uiLibrary}`)
|
|
418
|
+
console.log(`[miko] 布局: ${layout}`)
|
|
419
|
+
console.log(`[miko] 模板目录: ${template}`)
|
|
420
|
+
console.log(`[miko] 入口文件: ${entry}`)
|
|
421
|
+
|
|
422
|
+
// ===== 构建 PluginOption 数组 =====
|
|
423
|
+
|
|
424
|
+
const plugins: PluginOption[] = []
|
|
425
|
+
|
|
426
|
+
// 1. Vue 生态
|
|
427
|
+
plugins.push(
|
|
428
|
+
VueMacros({
|
|
429
|
+
plugins: {
|
|
430
|
+
vue: vue(vueOpts),
|
|
431
|
+
vueJsx: vueJsx(vueJsxOpts),
|
|
432
|
+
vueRouter: VueRouter({
|
|
433
|
+
extensions: vueRouterOpts.extensions,
|
|
434
|
+
routesFolder: vueRouterOpts.routesFolder,
|
|
435
|
+
dts: vueRouterOpts.dts,
|
|
436
|
+
extendRoute(route: { path?: string; addAlias: (a: string[]) => void }) {
|
|
437
|
+
if (route.path) route.addAlias([route.path === '/' ? 'index.html' : `${route.path}.html`])
|
|
438
|
+
},
|
|
439
|
+
}),
|
|
440
|
+
},
|
|
441
|
+
}),
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
// 2. 布局
|
|
445
|
+
plugins.push(
|
|
446
|
+
Layouts({
|
|
447
|
+
defaultLayout: layout,
|
|
448
|
+
layoutsDirs,
|
|
449
|
+
pagesDirs: layoutsOpts.pagesDirs ?? pagesDir,
|
|
450
|
+
}),
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
// 3. 代码检查
|
|
454
|
+
if (linterOpts !== false) {
|
|
455
|
+
// linterPlugin 内部已处理 oxlint/eslint 开关,直接传入
|
|
456
|
+
plugins.push(linterPlugin)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// 4. Legacy 浏览器兼容
|
|
460
|
+
if (legacyOpts !== false) {
|
|
461
|
+
plugins.push(legacy({ targets: DEFAULTS.legacyTargets, ...legacyOpts }))
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// 5. 组件自动导入
|
|
465
|
+
const componentResolvers = cfg.components.resolvers
|
|
466
|
+
? cfg.components.resolvers
|
|
467
|
+
: uiLibrary === 'vant'
|
|
468
|
+
? [VantResolver()]
|
|
469
|
+
: [ElementPlusResolver()]
|
|
470
|
+
|
|
471
|
+
plugins.push(
|
|
472
|
+
Components({
|
|
473
|
+
dirs: Array.isArray(componentsOpts.dirs) ? componentsOpts.dirs : [componentsOpts.dirs],
|
|
474
|
+
extensions: componentsOpts.extensions,
|
|
475
|
+
dts: componentsOpts.dts,
|
|
476
|
+
resolvers: componentResolvers,
|
|
477
|
+
}),
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
// 6. UnoCSS
|
|
481
|
+
if (unoCSSOpts !== false) {
|
|
482
|
+
plugins.push(UnoCSS({ configFile: false, ...unoCSSOpts } as Parameters<typeof UnoCSS>[0]))
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// 7. Bootstrap(virtual:bootstrap)
|
|
486
|
+
plugins.push(bootstrapPlugin(bootstrapOpts.entryFile))
|
|
487
|
+
|
|
488
|
+
// 8. External(CDN 外部化)
|
|
489
|
+
plugins.push(...externalPlugin())
|
|
490
|
+
|
|
491
|
+
// 9. IndexHTML
|
|
492
|
+
plugins.push(await indexHTMLPlugin(entry, template))
|
|
493
|
+
|
|
494
|
+
// 10. Janus(可选)
|
|
495
|
+
const janusPlugin = loadJanus(janusOpts)
|
|
496
|
+
if (janusPlugin) plugins.push(janusPlugin)
|
|
497
|
+
|
|
498
|
+
// ===== 组装 defineConfig =====
|
|
499
|
+
|
|
500
|
+
return defineConfig(() => ({
|
|
501
|
+
server: {
|
|
502
|
+
host: devOpts.host ?? true,
|
|
503
|
+
port: devOpts.port,
|
|
504
|
+
proxy: proxy ? normalizeProxy(proxy) : undefined,
|
|
505
|
+
},
|
|
506
|
+
build: { outDir, emptyOutDir: true },
|
|
507
|
+
cacheDir: resolve(cwd, './node_modules/.vite'),
|
|
508
|
+
resolve: { alias: [{ find: '@', replacement: cwd }], tsconfigPaths: true },
|
|
509
|
+
experimental: { bundledDev: devOpts.bundledDev ?? DEFAULTS.bundledDev },
|
|
510
|
+
ssgOptions: ssgOpts === false
|
|
511
|
+
? undefined
|
|
512
|
+
: {
|
|
513
|
+
beastiesOptions: ssgOpts.beastiesOptions ?? { external: false },
|
|
514
|
+
dirStyle: ssgOpts.dirStyle ?? 'flat',
|
|
515
|
+
entry,
|
|
516
|
+
formatting: ssgOpts.formatting ?? 'none',
|
|
517
|
+
includedRoutes: ssgOpts.includedRoutes ?? ((paths: string[]) => paths.filter((p) => !p.includes('node_modules'))),
|
|
518
|
+
onPageRendered: ssgOpts.onPageRendered ?? ((_route: string, renderedHTML: string) => renderedHTML),
|
|
519
|
+
onFinished: ssgOpts.onFinished ?? (async () => { await remove(resolve(outDir, '.vite')) }),
|
|
520
|
+
},
|
|
521
|
+
plugins,
|
|
522
|
+
}))
|
|
523
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@minar-kotonoha/vite-plugin-miko",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./index.ts",
|
|
7
|
+
"./package.json": "./package.json"
|
|
8
|
+
},
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"vite": "catalog:"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@minar-kotonoha/linter": "workspace:^",
|
|
14
|
+
"@minar-kotonoha/vite-plugin-bootstrap": "workspace:^",
|
|
15
|
+
"@minar-kotonoha/vite-plugin-external": "workspace:^",
|
|
16
|
+
"@minar-kotonoha/vite-plugin-index-html": "workspace:^",
|
|
17
|
+
"@vant/auto-import-resolver": "^1.0.0",
|
|
18
|
+
"@vitejs/plugin-legacy": "^8.2.0",
|
|
19
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
20
|
+
"@vitejs/plugin-vue-jsx": "^5.1.6",
|
|
21
|
+
"fs-extra": "^11.3.6",
|
|
22
|
+
"unocss": "^66.7.0",
|
|
23
|
+
"unplugin-vue-components": "^32.1.0",
|
|
24
|
+
"vite-plugin-vue-layouts-next": "^2.1.0",
|
|
25
|
+
"vue-macros": "^3.1.4",
|
|
26
|
+
"vue-router": "^5.2.0"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"registry": "https://registry.npmjs.org/"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/tsconfig.json
ADDED
package/types.ts
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # @minar-kotonoha/vite-plugin-miko 类型定义
|
|
3
|
+
*
|
|
4
|
+
* `MikoUserConfig` 为 `miko.config.ts` 的完整配置类型。
|
|
5
|
+
* 所有字段均为可选,默认值在 JSDoc 中标注。
|
|
6
|
+
*
|
|
7
|
+
* 插件子类型直接引用底层插件的 Options 类型,保证类型始终准确。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ===== 直接引用底层插件类型(保证与插件版本同步) =====
|
|
11
|
+
|
|
12
|
+
import type { Options as VueOptions } from '@vitejs/plugin-vue'
|
|
13
|
+
import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx'
|
|
14
|
+
import type { Options as LegacyOptions } from '@vitejs/plugin-legacy'
|
|
15
|
+
import type { UserOptions as LayoutsUserOptions } from 'vite-plugin-vue-layouts-next'
|
|
16
|
+
import type { VitePluginConfig as UnoCSSVitePluginConfig } from '@unocss/vite'
|
|
17
|
+
|
|
18
|
+
// ===================================================================
|
|
19
|
+
// 重新导出底层插件类型(方便用户直接在 miko.config.ts 中使用)
|
|
20
|
+
// ===================================================================
|
|
21
|
+
|
|
22
|
+
export type { VueOptions, VueJsxOptions, LegacyOptions, LayoutsUserOptions, UnoCSSVitePluginConfig }
|
|
23
|
+
|
|
24
|
+
// ===== 基础配置 =====
|
|
25
|
+
|
|
26
|
+
/** 开发服务器代理规则 */
|
|
27
|
+
export interface ProxyConfig {
|
|
28
|
+
/** 要代理的路径模式,如 `['/api/**']` */
|
|
29
|
+
context: string[]
|
|
30
|
+
/** 代理目标地址 */
|
|
31
|
+
target: string
|
|
32
|
+
/** 是否修改请求头 origin */
|
|
33
|
+
changeOrigin?: boolean
|
|
34
|
+
/** 代理日志级别 */
|
|
35
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent'
|
|
36
|
+
/** 自定义代理事件 */
|
|
37
|
+
configure?: (proxy: unknown) => void
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ===== 库模式 =====
|
|
41
|
+
|
|
42
|
+
export interface LibConfig {
|
|
43
|
+
/** 库入口文件 */
|
|
44
|
+
entry?: string
|
|
45
|
+
/** 输出格式 */
|
|
46
|
+
formats?: ('es' | 'cjs' | 'umd')[]
|
|
47
|
+
/** 全局变量名(UMD 模式) */
|
|
48
|
+
name?: string
|
|
49
|
+
/** 输出文件名 */
|
|
50
|
+
fileName?: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ===== Vue Router =====
|
|
54
|
+
|
|
55
|
+
export interface VueRouterOptions {
|
|
56
|
+
/**
|
|
57
|
+
* 路由文件扩展名
|
|
58
|
+
* @default ['.vue', '.setup.tsx']
|
|
59
|
+
*/
|
|
60
|
+
extensions?: string[]
|
|
61
|
+
/**
|
|
62
|
+
* 页面文件目录(文件系统路由扫描根目录)
|
|
63
|
+
* @default '<cwd>/pages'
|
|
64
|
+
*/
|
|
65
|
+
routesFolder?: string
|
|
66
|
+
/**
|
|
67
|
+
* 路由类型声明输出路径
|
|
68
|
+
* @default '<cwd>/types/routes.d.ts'
|
|
69
|
+
*/
|
|
70
|
+
dts?: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ===== 组件自动导入 =====
|
|
74
|
+
|
|
75
|
+
export interface ComponentsOptions {
|
|
76
|
+
/**
|
|
77
|
+
* 组件文件目录
|
|
78
|
+
* @default ['<cwd>/components']
|
|
79
|
+
*/
|
|
80
|
+
dirs?: string | string[]
|
|
81
|
+
/**
|
|
82
|
+
* 组件文件扩展名
|
|
83
|
+
* @default ['vue', 'tsx', 'ts']
|
|
84
|
+
*/
|
|
85
|
+
extensions?: string[]
|
|
86
|
+
/**
|
|
87
|
+
* 类型声明输出路径,false 表示不生成
|
|
88
|
+
* @default '<cwd>/types/components.d.ts'
|
|
89
|
+
*/
|
|
90
|
+
dts?: string | boolean
|
|
91
|
+
/** 额外自定义 resolvers(会替换 uiLibrary 的默认 resolver) */
|
|
92
|
+
resolvers?: unknown[]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ===== SSG =====
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* vite-ssg 配置。
|
|
99
|
+
* 设为 `false` 禁用 SSG(降级为纯 SPA)。
|
|
100
|
+
*/
|
|
101
|
+
export interface SSGConfig {
|
|
102
|
+
/** beasties 配置(控制资源内联与压缩) */
|
|
103
|
+
beastiesOptions?: {
|
|
104
|
+
/** 是否外部化资源,默认 false(所有 CSS/JS 内联到 HTML) */
|
|
105
|
+
external?: boolean
|
|
106
|
+
/** 压缩配置 */
|
|
107
|
+
compress?: boolean | Record<string, unknown>
|
|
108
|
+
[key: string]: unknown
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 输出目录结构
|
|
112
|
+
* - `'flat'`:/about.html
|
|
113
|
+
* - `'nested'`:/about/index.html
|
|
114
|
+
* @default 'flat'
|
|
115
|
+
*/
|
|
116
|
+
dirStyle?: 'flat' | 'nested'
|
|
117
|
+
/**
|
|
118
|
+
* HTML 格式化
|
|
119
|
+
* @default 'none'
|
|
120
|
+
*/
|
|
121
|
+
formatting?: 'none' | 'prettier'
|
|
122
|
+
/** 需要被包含的路由过滤函数 */
|
|
123
|
+
includedRoutes?: (paths: string[]) => string[]
|
|
124
|
+
/** 页面渲染完成钩子(可在此注入脚本、修改 HTML) */
|
|
125
|
+
onPageRendered?: (route: string, renderedHTML: string) => string
|
|
126
|
+
/** SSG 构建完成钩子(可在此做清理工作) */
|
|
127
|
+
onFinished?: () => Promise<void>
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ===== 代码检查 =====
|
|
131
|
+
|
|
132
|
+
export interface LinterOptions {
|
|
133
|
+
/**
|
|
134
|
+
* 是否启用 oxlint
|
|
135
|
+
* @default true
|
|
136
|
+
*/
|
|
137
|
+
oxlint?: boolean
|
|
138
|
+
/**
|
|
139
|
+
* 是否启用 ESLint
|
|
140
|
+
* @default true
|
|
141
|
+
*/
|
|
142
|
+
eslint?: boolean
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ===== Bootstrap 启动器 =====
|
|
146
|
+
|
|
147
|
+
export interface BootstrapOptions {
|
|
148
|
+
/**
|
|
149
|
+
* 项目入口文件路径(相对于 cwd)
|
|
150
|
+
* @default 'index.ts'
|
|
151
|
+
*/
|
|
152
|
+
entryFile?: string
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ===== 外部化 / CDN =====
|
|
156
|
+
|
|
157
|
+
export interface ExternalOptions {
|
|
158
|
+
/**
|
|
159
|
+
* Framework CDN 地址,覆盖 .env 中的 VITE_FRAMEWORK_CDN
|
|
160
|
+
* @default 'https://unpkg.com/@minar-kotonoha/framework@<version>/dist/framework_v<version>.umd.js'
|
|
161
|
+
*/
|
|
162
|
+
frameworkCDN?: string
|
|
163
|
+
/** 额外需要外部化的包名 */
|
|
164
|
+
additionalExternals?: string[]
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ===== 开发 / 构建调优 =====
|
|
168
|
+
|
|
169
|
+
export interface DevOptions {
|
|
170
|
+
/**
|
|
171
|
+
* 是否启用 bundledDev(Rolldown 原生 dev 模式)
|
|
172
|
+
* @default true
|
|
173
|
+
*/
|
|
174
|
+
bundledDev?: boolean
|
|
175
|
+
/**
|
|
176
|
+
* 开发服务器主机名(Vite server.host)
|
|
177
|
+
* @default 'localhost'
|
|
178
|
+
*/
|
|
179
|
+
host?: string | boolean
|
|
180
|
+
/**
|
|
181
|
+
* 开发服务器端口(Vite server.port)
|
|
182
|
+
* @default 5173
|
|
183
|
+
*/
|
|
184
|
+
port?: number
|
|
185
|
+
/**
|
|
186
|
+
* 是否自动打开浏览器
|
|
187
|
+
* @default false
|
|
188
|
+
*/
|
|
189
|
+
open?: boolean | string
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ===== Janus 接口拦截器 =====
|
|
193
|
+
|
|
194
|
+
export interface JanusOptions {
|
|
195
|
+
/** Janus schema 目录 */
|
|
196
|
+
schemasDir?: string
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ===================================================================
|
|
200
|
+
// 主配置类型
|
|
201
|
+
// ===================================================================
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* miko 项目配置文件(`miko.config.ts`)的类型定义。
|
|
205
|
+
*
|
|
206
|
+
* **所有字段均为可选**,默认值已在每个字段的 JSDoc 中标注。
|
|
207
|
+
*
|
|
208
|
+
* ## 插件配置分类
|
|
209
|
+
*
|
|
210
|
+
* | 分类 | 字段 | 类型来源 |
|
|
211
|
+
* |------|------|----------|
|
|
212
|
+
* | Vue SFC 编译 | `vue` | `@vitejs/plugin-vue` Options |
|
|
213
|
+
* | JSX / TSX | `vueJsx` | `@vitejs/plugin-vue-jsx` Options |
|
|
214
|
+
* | 文件系统路由 | `vueRouter` | 自定义(vue-router/vite 参数) |
|
|
215
|
+
* | 布局系统 | `layouts` | `vite-plugin-vue-layouts-next` UserOptions |
|
|
216
|
+
* | 组件自动导入 | `components` | 自定义(unplugin-vue-components 参数) |
|
|
217
|
+
* | 原子 CSS | `unoCSS` | `@unocss/vite` VitePluginConfig(`false` 禁用) |
|
|
218
|
+
* | 浏览器兼容 | `legacy` | `@vitejs/plugin-legacy` Options(`false` 禁用) |
|
|
219
|
+
* | 静态生成 | `ssg` | 自定义(vite-ssg 参数)(`false` 禁用) |
|
|
220
|
+
* | 代码检查 | `linter` | 自定义(`false` 禁用) |
|
|
221
|
+
* | 入口启动 | `bootstrap` | 自定义 |
|
|
222
|
+
* | CDN 外部化 | `external` | 自定义 |
|
|
223
|
+
* | 接口拦截 | `janus` | 自定义(`false` 禁用) |
|
|
224
|
+
* | 开发调优 | `dev` | 自定义 |
|
|
225
|
+
*
|
|
226
|
+
* @example 最小配置
|
|
227
|
+
* ```ts
|
|
228
|
+
* // miko.config.ts
|
|
229
|
+
* import type { MikoUserConfig } from '@minar-kotonoha/vite-plugin-miko'
|
|
230
|
+
* export default { uiLibrary: 'vant' } satisfies MikoUserConfig
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* @example 完整配置
|
|
234
|
+
* ```ts
|
|
235
|
+
* import type { MikoUserConfig } from '@minar-kotonoha/vite-plugin-miko'
|
|
236
|
+
* export default {
|
|
237
|
+
* // 基础
|
|
238
|
+
* uiLibrary: 'element-plus',
|
|
239
|
+
* layout: 'default',
|
|
240
|
+
* pagesDir: 'src/pages',
|
|
241
|
+
*
|
|
242
|
+
* // 代理
|
|
243
|
+
* proxy: [{ context: ['/api/**'], target: 'https://api.example.com', changeOrigin: true }],
|
|
244
|
+
*
|
|
245
|
+
* // 插件透传(直接使用底层插件 Options)
|
|
246
|
+
* vue: { features: { optionsAPI: false } }, // @vitejs/plugin-vue Options
|
|
247
|
+
* vueJsx: { tsTransform: 'built-in' }, // @vitejs/plugin-vue-jsx Options
|
|
248
|
+
* layouts: { extensions: ['vue', 'tsx'] }, // vite-plugin-vue-layouts-next UserOptions
|
|
249
|
+
* legacy: { targets: ['chrome 80', 'ios 13'] }, // @vitejs/plugin-legacy Options
|
|
250
|
+
* unoCSS: { configFile: 'uno.config.ts' }, // @unocss/vite VitePluginConfig
|
|
251
|
+
* ssg: { dirStyle: 'nested' }, // false 禁用 SSG
|
|
252
|
+
* } satisfies MikoUserConfig
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
export interface MikoUserConfig {
|
|
256
|
+
// === 基础路径 ===
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* 模板目录路径。
|
|
260
|
+
* 包含 App.vue、main.ts、index.html、layouts/ 等 Vite 入口模板文件。
|
|
261
|
+
* @default 自动探测(优先项目根 `template/` → 回退包内 `template/`)
|
|
262
|
+
*/
|
|
263
|
+
template?: string
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* 应用入口文件路径(传给 vite-ssg 的 entry)。
|
|
267
|
+
* @default `<template>/main.ts`
|
|
268
|
+
*/
|
|
269
|
+
entry?: string
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* 构建输出目录。
|
|
273
|
+
* @default `'./dist'`
|
|
274
|
+
*/
|
|
275
|
+
outDir?: string
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* 页面目录(文件系统路由的扫描根目录)。
|
|
279
|
+
* @default `'./pages'`
|
|
280
|
+
*/
|
|
281
|
+
pagesDir?: string
|
|
282
|
+
|
|
283
|
+
// === UI 框架 ===
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* UI 组件库,控制自动导入 resolver 的选择。
|
|
287
|
+
* @default `'vant'`
|
|
288
|
+
*/
|
|
289
|
+
uiLibrary?: 'vant' | 'element-plus'
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* 默认布局名(`layouts.defaultLayout` 的快捷方式,向后兼容)。
|
|
293
|
+
* 当同时设置了 `layout` 和 `layouts.defaultLayout` 时,后者优先。
|
|
294
|
+
* @default `'flexible'`
|
|
295
|
+
*/
|
|
296
|
+
layout?: string
|
|
297
|
+
|
|
298
|
+
// === 开发服务器 ===
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 开发服务器代理规则。
|
|
302
|
+
* 数组格式(webpack-dev-server 风格),支持将多个路径映射到同一目标。
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* proxy: [
|
|
307
|
+
* { context: ['/api/**'], target: 'https://dev.example.com', changeOrigin: true },
|
|
308
|
+
* ]
|
|
309
|
+
* ```
|
|
310
|
+
* @default `[]`(无代理)
|
|
311
|
+
*/
|
|
312
|
+
proxy?: ProxyConfig[]
|
|
313
|
+
|
|
314
|
+
// === 库模式 ===
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 库模式配置(供 `miko build --lib` 使用)。
|
|
318
|
+
* @default `undefined`(应用模式)
|
|
319
|
+
*/
|
|
320
|
+
lib?: LibConfig
|
|
321
|
+
|
|
322
|
+
// === 开发调优 ===
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* 开发与构建行为微调。
|
|
326
|
+
* @default `{ bundledDev: true }`
|
|
327
|
+
*/
|
|
328
|
+
dev?: DevOptions
|
|
329
|
+
|
|
330
|
+
// ===================================================================
|
|
331
|
+
// 以下为各插件的独立配置分组
|
|
332
|
+
// 类型直接引自底层插件 Options,保证与 npm 包版本同步
|
|
333
|
+
// ===================================================================
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* `@vitejs/plugin-vue` 的完整 Options。
|
|
337
|
+
*
|
|
338
|
+
* 透传给 `vue()` 函数,支持 include/exclude/script/template/style/features/compiler 等。
|
|
339
|
+
*
|
|
340
|
+
* @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue
|
|
341
|
+
* @default `{}`
|
|
342
|
+
*/
|
|
343
|
+
vue?: VueOptions
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* `@vitejs/plugin-vue-jsx` 的完整 Options。
|
|
347
|
+
*
|
|
348
|
+
* 透传给 `vueJsx()` 函数,支持 include/exclude/babelPlugins/tsTransform 等。
|
|
349
|
+
*
|
|
350
|
+
* @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx
|
|
351
|
+
* @default `{}`
|
|
352
|
+
*/
|
|
353
|
+
vueJsx?: VueJsxOptions
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* vue-router 文件系统路由选项。
|
|
357
|
+
* @default `{ extensions: ['.vue', '.setup.tsx'], routesFolder: '<pagesDir>', dts: '<cwd>/types/routes.d.ts' }`
|
|
358
|
+
*/
|
|
359
|
+
vueRouter?: VueRouterOptions
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* `vite-plugin-vue-layouts-next` 的完整 UserOptions。
|
|
363
|
+
*
|
|
364
|
+
* 透传给 `Layouts()` 函数。
|
|
365
|
+
* 注意:`layoutsDirs`、`pagesDirs`、`defaultLayout` 均有 miko 默认值,
|
|
366
|
+
* 未设置时不会使用插件自身的默认值(`src/layouts` / `src/pages` / `default`)。
|
|
367
|
+
*
|
|
368
|
+
* @see https://github.com/JohnCampionJr/vite-plugin-vue-layouts-next
|
|
369
|
+
* @default `{ defaultLayout: 'flexible', layoutsDirs: ['<template>/layouts', '<cwd>/layouts'], pagesDirs: '<pagesDir>' }`
|
|
370
|
+
*/
|
|
371
|
+
layouts?: LayoutsUserOptions
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* unplugin-vue-components 选项。
|
|
375
|
+
* @default `{ dirs: ['<cwd>/components'], extensions: ['vue', 'tsx', 'ts'], dts: '<cwd>/types/components.d.ts' }`
|
|
376
|
+
*/
|
|
377
|
+
components?: ComponentsOptions
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* `@unocss/vite` 的完整 VitePluginConfig + UserConfig。
|
|
381
|
+
*
|
|
382
|
+
* 透传给 `UnoCSS()` 函数。设为 `false` 禁用 UnoCSS。
|
|
383
|
+
*
|
|
384
|
+
* 常用:`{ configFile: 'uno.config.ts' }` 加载自定义配置,
|
|
385
|
+
* 或 `{ configFile: false }`(默认)使用默认预设。
|
|
386
|
+
*
|
|
387
|
+
* @see https://unocss.dev/integrations/vite
|
|
388
|
+
* @default `{ configFile: false }`
|
|
389
|
+
*/
|
|
390
|
+
unoCSS?: UnoCSSVitePluginConfig | false
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* `@vitejs/plugin-legacy` 的完整 Options。
|
|
394
|
+
*
|
|
395
|
+
* 透传给 `legacy()` 函数。设为 `false` 禁用(不生成 `-legacy` 产物)。
|
|
396
|
+
*
|
|
397
|
+
* @see https://github.com/vitejs/vite/tree/main/packages/plugin-legacy
|
|
398
|
+
* @default `{ targets: ['chrome 49', 'ios 10'] }`
|
|
399
|
+
*/
|
|
400
|
+
legacy?: LegacyOptions | false
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* vite-ssg 选项。
|
|
404
|
+
* 设为 `false` 禁用 SSG(降级为纯 SPA)。
|
|
405
|
+
*
|
|
406
|
+
* @default `{ beastiesOptions: { external: false }, dirStyle: 'flat', formatting: 'none' }`
|
|
407
|
+
*/
|
|
408
|
+
ssg?: SSGConfig | false
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* 构建时代码检查选项。
|
|
412
|
+
* 设为 `false` 禁用所有 linter(oxlint + ESLint 均跳过)。
|
|
413
|
+
*
|
|
414
|
+
* @default `{ oxlint: true, eslint: true }`
|
|
415
|
+
*/
|
|
416
|
+
linter?: LinterOptions | false
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* virtual:bootstrap 入口启动器选项。
|
|
420
|
+
* @default `{ entryFile: 'index.ts' }`
|
|
421
|
+
*/
|
|
422
|
+
bootstrap?: BootstrapOptions
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* CDN 外部化选项。
|
|
426
|
+
* @default `{}`
|
|
427
|
+
*/
|
|
428
|
+
external?: ExternalOptions
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Janus 接口拦截器选项。
|
|
432
|
+
* 设为 `false` 禁用(即使安装了 `@janus/unplugin` 也不加载)。
|
|
433
|
+
*
|
|
434
|
+
* @default 自动发现(安装了 `@janus/unplugin` 则自动启用)
|
|
435
|
+
*/
|
|
436
|
+
janus?: JanusOptions | false
|
|
437
|
+
}
|