@movk/nuxt-docs 1.15.0 → 1.16.1
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 +27 -9
- package/app/components/OgImage/OgImageDocs.takumi.vue +5 -5
- package/modules/ai-chat/runtime/components/AiChatPanel.vue +5 -2
- package/modules/config.ts +7 -23
- package/modules/module.ts +103 -0
- package/{app/components/content/prose/ProsePre.global.vue → modules/runtime/components/prose/Pre.vue} +5 -7
- package/modules/runtime/public/noto-sans-sc-400-normal.woff2 +0 -0
- package/modules/runtime/public/noto-sans-sc-500-normal.woff2 +0 -0
- package/modules/runtime/public/noto-sans-sc-latin-400-normal.woff +0 -0
- package/modules/runtime/public/noto-sans-sc-latin-500-normal.woff2 +0 -0
- package/nuxt.config.ts +6 -4
- package/package.json +8 -8
- package/server/mcp/tools/get-example.ts +1 -1
- package/server/mcp/tools/get-page.ts +1 -1
- package/server/mcp/tools/list-examples.ts +1 -1
- package/server/mcp/tools/list-getting-started-guides.ts +1 -1
- package/server/mcp/tools/list-pages.ts +2 -2
- package/utils/component-meta.ts +1 -5
- package/modules/mermaid.ts +0 -93
- /package/{app/components/content → modules/runtime/components/prose}/Mermaid.vue +0 -0
package/README.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
[](https://docs.mhaibaraai.cn/)
|
|
1
2
|
[](https://docs.mhaibaraai.cn/)
|
|
2
3
|
|
|
3
4
|
> 基于 Nuxt 4 的现代文档主题,集成组件自动化文档、AI 聊天助手、MCP Server 和完整的开发者体验优化
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
### 🤖 AI 增强体验
|
|
22
23
|
|
|
23
24
|
<div style="padding: 40px 0; display: flex; justify-content: center;">
|
|
24
|
-
|
|
25
|
+
<img src="https://docs.mhaibaraai.cn/ai/AiChat.png" alt="AiChat" width="400">
|
|
25
26
|
</div>
|
|
26
27
|
|
|
27
28
|
- **AI 聊天助手** - 内置智能文档助手,基于 Vercel AI SDK 支持多种 LLM 模型
|
|
@@ -189,7 +190,10 @@ pnpm add mermaid dompurify
|
|
|
189
190
|
```ts [nuxt.config.ts]
|
|
190
191
|
export default defineNuxtConfig({
|
|
191
192
|
extends: ['@movk/nuxt-docs'],
|
|
192
|
-
|
|
193
|
+
|
|
194
|
+
movkNuxtDocs: {
|
|
195
|
+
mermaid: true
|
|
196
|
+
}
|
|
193
197
|
})
|
|
194
198
|
```
|
|
195
199
|
|
|
@@ -198,11 +202,11 @@ export default defineNuxtConfig({
|
|
|
198
202
|
````md [md]
|
|
199
203
|
```mermaid
|
|
200
204
|
graph TD
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
A[开始] --> B{是否有效?}
|
|
206
|
+
B -->|是| C[处理数据]
|
|
207
|
+
B -->|否| D[显示错误]
|
|
208
|
+
C --> E[完成]
|
|
209
|
+
D --> E
|
|
206
210
|
```
|
|
207
211
|
````
|
|
208
212
|
|
|
@@ -215,9 +219,9 @@ graph TD
|
|
|
215
219
|
|
|
216
220
|
**支持的图表类型:**
|
|
217
221
|
- **流程图**(`flowchart`/`graph`):用于展示流程和决策
|
|
218
|
-
|
|
222
|
+

|
|
219
223
|
- **时序图**(`sequenceDiagram`):用于展示交互时序
|
|
220
|
-
|
|
224
|
+

|
|
221
225
|
- **类图**(`classDiagram`):用于展示类关系
|
|
222
226
|
- **状态图**(`stateDiagram`):用于展示状态转换
|
|
223
227
|
- **甘特图**(`gantt`):用于展示项目时间线
|
|
@@ -225,6 +229,20 @@ graph TD
|
|
|
225
229
|
- **Git 图**(`gitGraph`):用于展示分支历史
|
|
226
230
|
- 以及更多 [Mermaid 支持的图表类型](https://mermaid.js.org/intro())
|
|
227
231
|
|
|
232
|
+
### 无障碍支持(A11y)
|
|
233
|
+
|
|
234
|
+
Movk Nuxt Docs 默认启用 `@nuxt/a11y`。如需关闭,可在 `movkNuxtDocs` 中设置:
|
|
235
|
+
|
|
236
|
+
```ts [nuxt.config.ts]
|
|
237
|
+
export default defineNuxtConfig({
|
|
238
|
+
extends: ['@movk/nuxt-docs'],
|
|
239
|
+
|
|
240
|
+
movkNuxtDocs: {
|
|
241
|
+
a11y: false
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
```
|
|
245
|
+
|
|
228
246
|
## 🛠️ 开发
|
|
229
247
|
|
|
230
248
|
### 本地开发
|
|
@@ -11,10 +11,7 @@ withDefaults(defineProps<{
|
|
|
11
11
|
</script>
|
|
12
12
|
|
|
13
13
|
<template>
|
|
14
|
-
<div
|
|
15
|
-
style="font-family: 'Public Sans', 'Noto Sans SC', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;"
|
|
16
|
-
class="w-full h-full flex flex-col justify-center items-center relative p-10 lg:p-15 bg-white text-neutral-900 dark:bg-neutral-900 dark:text-neutral-50"
|
|
17
|
-
>
|
|
14
|
+
<div style="font-family: 'Noto Sans SC', sans-serif;" class="w-full h-full flex flex-col justify-center items-center relative p-10 lg:p-15 bg-white text-neutral-900 dark:bg-neutral-900 dark:text-neutral-50">
|
|
18
15
|
<div
|
|
19
16
|
class="absolute top-0 left-0 right-0 bottom-0"
|
|
20
17
|
:style="{
|
|
@@ -82,7 +79,10 @@ withDefaults(defineProps<{
|
|
|
82
79
|
</h1>
|
|
83
80
|
</div>
|
|
84
81
|
|
|
85
|
-
<p
|
|
82
|
+
<p
|
|
83
|
+
v-if="description"
|
|
84
|
+
class="text-slate-500 text-[24px] lg:text-[32px] opacity-70 max-w-162.5 lg:max-w-225 leading-normal"
|
|
85
|
+
>
|
|
86
86
|
{{ description }}
|
|
87
87
|
</p>
|
|
88
88
|
</div>
|
|
@@ -98,8 +98,11 @@ function getToolIcon(part: ToolPart): string {
|
|
|
98
98
|
const { toolIcon } = useToolCall(part.state, toolName, part.input || {} as any)
|
|
99
99
|
|
|
100
100
|
const iconMap: Record<string, string> = {
|
|
101
|
-
'get-page': 'i-lucide-
|
|
102
|
-
'get-example': 'i-lucide-
|
|
101
|
+
'get-page': 'i-lucide-book-open',
|
|
102
|
+
'get-example': 'i-lucide-codepen',
|
|
103
|
+
'list-examples': 'i-lucide-codesandbox',
|
|
104
|
+
'list-getting-started-guides': 'i-lucide-square-play',
|
|
105
|
+
'list-pages': 'i-lucide-book-minus',
|
|
103
106
|
...toolIcon
|
|
104
107
|
}
|
|
105
108
|
|
package/modules/config.ts
CHANGED
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs'
|
|
2
1
|
import { createResolver, defineNuxtModule } from '@nuxt/kit'
|
|
3
2
|
import { defu } from 'defu'
|
|
4
|
-
import { join } from 'pathe'
|
|
5
3
|
import { getGitBranch, getGitEnv, getLocalGitInfo } from '../utils/git'
|
|
6
4
|
import { getPackageJsonMetadata, inferSiteURL } from '../utils/meta'
|
|
7
5
|
import { createComponentMetaExcludeFilters } from '../utils/component-meta'
|
|
8
6
|
|
|
9
|
-
function getMdcConfigSources(nuxt: any): string[] {
|
|
10
|
-
return nuxt.options._layers.flatMap((layer: any) => {
|
|
11
|
-
const tsConfigPath = join(layer.config.srcDir, 'mdc.config.ts')
|
|
12
|
-
if (existsSync(tsConfigPath)) {
|
|
13
|
-
return [tsConfigPath]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const jsConfigPath = join(layer.config.srcDir, 'mdc.config.js')
|
|
17
|
-
if (existsSync(jsConfigPath)) {
|
|
18
|
-
return [jsConfigPath]
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return []
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
|
|
25
7
|
export default defineNuxtModule({
|
|
26
8
|
meta: {
|
|
27
9
|
name: 'config'
|
|
@@ -91,10 +73,12 @@ export default defineNuxtModule({
|
|
|
91
73
|
]
|
|
92
74
|
})
|
|
93
75
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
76
|
+
nuxt.hook('nitro:config', (nitroConfig) => {
|
|
77
|
+
nitroConfig.publicAssets ||= []
|
|
78
|
+
nitroConfig.publicAssets.push({
|
|
79
|
+
dir: resolve('./runtime/public'),
|
|
80
|
+
maxAge: 60 * 60 * 24 * 30
|
|
81
|
+
})
|
|
82
|
+
})
|
|
99
83
|
}
|
|
100
84
|
})
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { addComponentsDir, createResolver, defineNuxtModule, logger } from '@nuxt/kit'
|
|
2
|
+
import type { ModuleDependencies } from 'nuxt/schema'
|
|
3
|
+
|
|
4
|
+
export interface ModuleOptions {
|
|
5
|
+
/**
|
|
6
|
+
* 是否启用 @nuxt/a11y 无障碍支持
|
|
7
|
+
* @defaultValue true
|
|
8
|
+
* @see https://a11y.nuxtjs.org/
|
|
9
|
+
*/
|
|
10
|
+
a11y?: boolean
|
|
11
|
+
/**
|
|
12
|
+
* 是否启用 Mermaid 图表支持
|
|
13
|
+
* - 启用前需安装依赖: `pnpm add mermaid dompurify`
|
|
14
|
+
* @defaultValue false
|
|
15
|
+
*/
|
|
16
|
+
mermaid?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const log = logger.withTag('movk-nuxt-docs')
|
|
20
|
+
|
|
21
|
+
export default defineNuxtModule<ModuleOptions>({
|
|
22
|
+
meta: {
|
|
23
|
+
name: 'movk-nuxt-docs',
|
|
24
|
+
configKey: 'movkNuxtDocs'
|
|
25
|
+
},
|
|
26
|
+
defaults: {
|
|
27
|
+
a11y: true,
|
|
28
|
+
mermaid: false
|
|
29
|
+
},
|
|
30
|
+
moduleDependencies(nuxt): ModuleDependencies {
|
|
31
|
+
const userOptions = nuxt.options.movkNuxtDocs || {}
|
|
32
|
+
return {
|
|
33
|
+
...userOptions.a11y !== false && {
|
|
34
|
+
'@nuxt/a11y': {
|
|
35
|
+
version: '^1.0.0-alpha.1'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
setup(options, nuxt) {
|
|
41
|
+
const { resolve } = createResolver(import.meta.url)
|
|
42
|
+
|
|
43
|
+
if (options.mermaid) {
|
|
44
|
+
let mermaidAvailable = true
|
|
45
|
+
try {
|
|
46
|
+
import.meta.resolve('mermaid')
|
|
47
|
+
} catch {
|
|
48
|
+
log.warn('mermaid package not found. install it with: pnpm add mermaid dompurify')
|
|
49
|
+
mermaidAvailable = false
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (mermaidAvailable) {
|
|
53
|
+
addComponentsDir({
|
|
54
|
+
path: resolve('./runtime/components/prose'),
|
|
55
|
+
pathPrefix: false,
|
|
56
|
+
prefix: 'Prose',
|
|
57
|
+
global: true
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// 添加 mermaid 语言高亮
|
|
61
|
+
const contentOptions = nuxt.options.content as Record<string, any> | false
|
|
62
|
+
if (contentOptions) {
|
|
63
|
+
const build = contentOptions.build ??= {}
|
|
64
|
+
const markdown = build.markdown ??= {}
|
|
65
|
+
const highlight = markdown.highlight ??= {}
|
|
66
|
+
const langs = highlight.langs ??= [] as string[]
|
|
67
|
+
if (!langs.includes('mermaid')) {
|
|
68
|
+
langs.push('mermaid')
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 为 mermaid ESM 兼容性配置 optimizeDeps
|
|
73
|
+
nuxt.hooks.hook('vite:extendConfig', (config) => {
|
|
74
|
+
const cfg = config as { optimizeDeps?: { include?: string[] } }
|
|
75
|
+
cfg.optimizeDeps ??= {}
|
|
76
|
+
cfg.optimizeDeps.include ??= []
|
|
77
|
+
cfg.optimizeDeps.include.push(
|
|
78
|
+
'@movk/nuxt-docs > mermaid',
|
|
79
|
+
'@movk/nuxt-docs > mermaid > dayjs',
|
|
80
|
+
'@movk/nuxt-docs > mermaid > @braintree/sanitize-url',
|
|
81
|
+
'@movk/nuxt-docs > mermaid > d3',
|
|
82
|
+
'@movk/nuxt-docs > mermaid > dompurify'
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// 注入 mermaid 代码图标配置到 appConfig
|
|
87
|
+
const appConfig = nuxt.options.appConfig as Record<string, any>
|
|
88
|
+
appConfig.ui ??= {}
|
|
89
|
+
appConfig.ui.prose ??= {}
|
|
90
|
+
appConfig.ui.prose.codeIcon ??= {}
|
|
91
|
+
appConfig.ui.prose.codeIcon.mmd ??= 'i-vscode-icons-file-type-mermaid'
|
|
92
|
+
|
|
93
|
+
log.info('mermaid diagram support enabled')
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
declare module 'nuxt/schema' {
|
|
100
|
+
interface NuxtConfig {
|
|
101
|
+
movkNuxtDocs?: ModuleOptions
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { ProsePreProps } from '@nuxt/ui'
|
|
3
|
-
// @ts-ignore
|
|
3
|
+
// @ts-ignore - #build alias only available at Nuxt build time
|
|
4
4
|
import NuxtUIProsePre from '@nuxt/ui/components/prose/Pre.vue'
|
|
5
5
|
|
|
6
6
|
const props = defineProps<ProsePreProps>()
|
|
7
7
|
|
|
8
|
-
const isMermaid = computed(() => props.language === 'mermaid')
|
|
9
|
-
|
|
10
|
-
// 动态解析 Mermaid 组件(仅在 mermaid 模块启用时可用)
|
|
11
8
|
const MermaidComponent = computed(() => {
|
|
12
|
-
if (
|
|
13
|
-
const resolved = resolveComponent('
|
|
9
|
+
if (props.language !== 'mermaid') return null
|
|
10
|
+
const resolved = resolveComponent('ProseMermaid')
|
|
14
11
|
return typeof resolved === 'string' ? null : resolved
|
|
15
12
|
})
|
|
16
13
|
</script>
|
|
@@ -18,11 +15,12 @@ const MermaidComponent = computed(() => {
|
|
|
18
15
|
<template>
|
|
19
16
|
<component
|
|
20
17
|
:is="MermaidComponent"
|
|
21
|
-
v-if="
|
|
18
|
+
v-if="MermaidComponent"
|
|
22
19
|
:code="props.code || ''"
|
|
23
20
|
:filename="props.filename"
|
|
24
21
|
:icon="props.icon"
|
|
25
22
|
/>
|
|
23
|
+
|
|
26
24
|
<NuxtUIProsePre v-else v-bind="props">
|
|
27
25
|
<slot />
|
|
28
26
|
</NuxtUIProsePre>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/nuxt.config.ts
CHANGED
|
@@ -20,7 +20,6 @@ export default defineNuxtConfig({
|
|
|
20
20
|
'@nuxt/fonts',
|
|
21
21
|
'@nuxt/content',
|
|
22
22
|
'@nuxt/image',
|
|
23
|
-
'@nuxt/a11y',
|
|
24
23
|
'@nuxtjs/robots',
|
|
25
24
|
'@nuxtjs/mcp-toolkit',
|
|
26
25
|
'@vueuse/nuxt',
|
|
@@ -172,10 +171,9 @@ export default defineNuxtConfig({
|
|
|
172
171
|
},
|
|
173
172
|
|
|
174
173
|
fonts: {
|
|
175
|
-
provider: 'bunny',
|
|
176
174
|
families: [
|
|
177
|
-
{ name: 'Public Sans', global: true
|
|
178
|
-
{ name: 'Noto Sans SC', global: true }
|
|
175
|
+
{ name: 'Public Sans', global: true },
|
|
176
|
+
{ name: 'Noto Sans SC', global: true, provider: 'local' }
|
|
179
177
|
]
|
|
180
178
|
},
|
|
181
179
|
|
|
@@ -196,5 +194,9 @@ export default defineNuxtConfig({
|
|
|
196
194
|
// Must be defined before @nuxt/content setup,
|
|
197
195
|
// otherwise Content LLMS module will overwrite it in modules:done.
|
|
198
196
|
contentRawMarkdown: false
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
ogImage: {
|
|
200
|
+
zeroRuntime: true
|
|
199
201
|
}
|
|
200
202
|
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@movk/nuxt-docs",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.16.1",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Modern Nuxt 4 documentation theme with auto-generated component docs, AI chat assistant, MCP server, and complete developer experience optimization.",
|
|
7
7
|
"author": "YiXuan <mhaibaraai@gmail.com>",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"README.md"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@ai-sdk/gateway": "^3.0.
|
|
42
|
+
"@ai-sdk/gateway": "^3.0.83",
|
|
43
43
|
"@ai-sdk/mcp": "^1.0.30",
|
|
44
|
-
"@ai-sdk/vue": "^3.0.
|
|
45
|
-
"@iconify-json/lucide": "^1.2.
|
|
44
|
+
"@ai-sdk/vue": "^3.0.141",
|
|
45
|
+
"@iconify-json/lucide": "^1.2.100",
|
|
46
46
|
"@iconify-json/simple-icons": "^1.2.75",
|
|
47
47
|
"@iconify-json/vscode-icons": "^1.2.45",
|
|
48
48
|
"@movk/core": "^1.2.2",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"@nuxt/kit": "^4.4.2",
|
|
53
53
|
"@nuxt/ui": "^4.6.0",
|
|
54
54
|
"@nuxtjs/mcp-toolkit": "^0.12.0",
|
|
55
|
-
"@nuxtjs/mdc": "^0.
|
|
56
|
-
"@nuxtjs/robots": "^
|
|
55
|
+
"@nuxtjs/mdc": "^0.21.0",
|
|
56
|
+
"@nuxtjs/robots": "^6.0.6",
|
|
57
57
|
"@octokit/rest": "^22.0.1",
|
|
58
58
|
"@shikijs/core": "^4.0.2",
|
|
59
59
|
"@shikijs/engine-javascript": "^4.0.2",
|
|
@@ -63,14 +63,14 @@
|
|
|
63
63
|
"@takumi-rs/wasm": "^0.73.1",
|
|
64
64
|
"@vueuse/core": "^14.2.1",
|
|
65
65
|
"@vueuse/nuxt": "^14.2.1",
|
|
66
|
-
"ai": "^6.0.
|
|
66
|
+
"ai": "^6.0.141",
|
|
67
67
|
"defu": "^6.1.4",
|
|
68
68
|
"exsolve": "^1.0.8",
|
|
69
69
|
"git-url-parse": "^16.1.0",
|
|
70
70
|
"motion-v": "^2.2.0",
|
|
71
71
|
"nuxt-component-meta": "^0.17.2",
|
|
72
72
|
"nuxt-llms": "^0.2.0",
|
|
73
|
-
"nuxt-og-image": "^6.
|
|
73
|
+
"nuxt-og-image": "^6.3.0",
|
|
74
74
|
"ohash": "^2.0.11",
|
|
75
75
|
"pathe": "^2.0.3",
|
|
76
76
|
"pkg-types": "^2.3.0",
|
|
@@ -13,7 +13,7 @@ export default defineMcpTool({
|
|
|
13
13
|
content: [{ type: 'text' as const, text: result.code }]
|
|
14
14
|
}
|
|
15
15
|
} catch {
|
|
16
|
-
|
|
16
|
+
throw createError({ statusCode: 404, message: `示例 '${exampleName}' 未找到。使用 list_examples 工具查看所有可用示例。` })
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
})
|
|
@@ -8,10 +8,10 @@ export default defineMcpTool({
|
|
|
8
8
|
|
|
9
9
|
const pages = await queryCollection(event, 'docs').all()
|
|
10
10
|
|
|
11
|
-
return
|
|
11
|
+
return pages.map(doc => ({
|
|
12
12
|
title: doc.title,
|
|
13
13
|
description: doc.description,
|
|
14
14
|
path: doc.path
|
|
15
|
-
}))
|
|
15
|
+
}))
|
|
16
16
|
}
|
|
17
17
|
})
|
package/utils/component-meta.ts
CHANGED
|
@@ -52,11 +52,7 @@ export function createComponentMetaExcludeFilters(
|
|
|
52
52
|
resolve('../app/components/content/ComponentProps.vue'),
|
|
53
53
|
resolve('../app/components/content/ComponentSlots.vue'),
|
|
54
54
|
resolve('../app/components/content/PageLastCommit.vue'),
|
|
55
|
-
resolve('
|
|
56
|
-
resolve('./ai-chat/runtime/components/AiChatToolCall.vue'),
|
|
57
|
-
resolve('./ai-chat/runtime/components/AiChatReasoning.vue'),
|
|
58
|
-
resolve('./ai-chat/runtime/components/AiChatSlideoverFaq.vue'),
|
|
59
|
-
resolve('./ai-chat/runtime/components/AiChatPreStream.vue')
|
|
55
|
+
resolve('./runtime/components/prose/Mermaid.vue')
|
|
60
56
|
]
|
|
61
57
|
|
|
62
58
|
const userComponentPaths = [
|
package/modules/mermaid.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { createResolver, defineNuxtModule, logger } from '@nuxt/kit'
|
|
2
|
-
|
|
3
|
-
export interface MermaidModuleOptions {
|
|
4
|
-
/**
|
|
5
|
-
* 是否启用 Mermaid 图表支持
|
|
6
|
-
*
|
|
7
|
-
* 启用前需安装依赖: `pnpm add mermaid dompurify`
|
|
8
|
-
* @default false
|
|
9
|
-
*/
|
|
10
|
-
enabled?: boolean
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const log = logger.withTag('movk-nuxt-docs')
|
|
14
|
-
|
|
15
|
-
export default defineNuxtModule<MermaidModuleOptions>({
|
|
16
|
-
meta: {
|
|
17
|
-
name: 'mermaid',
|
|
18
|
-
configKey: 'mermaid'
|
|
19
|
-
},
|
|
20
|
-
defaults: {
|
|
21
|
-
enabled: false
|
|
22
|
-
},
|
|
23
|
-
setup(options, nuxt) {
|
|
24
|
-
const { resolve } = createResolver(import.meta.url)
|
|
25
|
-
const mermaidFilePath = resolve('../app/components/content/Mermaid.vue')
|
|
26
|
-
|
|
27
|
-
// Layer 自动扫描会注册 Mermaid.vue,通过 components:extend 统一管理:
|
|
28
|
-
// - 禁用时:从列表移除,resolveComponent('Mermaid') 返回字符串,ProsePre fallback 到普通代码块
|
|
29
|
-
// - 启用时:将 mode 改为 'client',避免 SSR 阶段执行
|
|
30
|
-
nuxt.hooks.hook('components:extend', (components) => {
|
|
31
|
-
const idx = components.findIndex(c => c.filePath === mermaidFilePath)
|
|
32
|
-
if (idx === -1) return
|
|
33
|
-
|
|
34
|
-
if (!options.enabled) {
|
|
35
|
-
components.splice(idx, 1)
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
components[idx]!.mode = 'client'
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
if (!options.enabled) return
|
|
43
|
-
|
|
44
|
-
// 验证 mermaid 依赖是否已安装
|
|
45
|
-
try {
|
|
46
|
-
import.meta.resolve('mermaid')
|
|
47
|
-
} catch {
|
|
48
|
-
log.warn('[mermaid] `mermaid` package not found. Install it with: pnpm add mermaid dompurify')
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 添加 mermaid 语言高亮
|
|
53
|
-
const contentOptions = nuxt.options.content as Record<string, any> | false
|
|
54
|
-
if (contentOptions) {
|
|
55
|
-
const build = contentOptions.build ??= {}
|
|
56
|
-
const markdown = build.markdown ??= {}
|
|
57
|
-
const highlight = markdown.highlight ??= {}
|
|
58
|
-
const langs = highlight.langs ??= [] as string[]
|
|
59
|
-
if (!langs.includes('mermaid')) {
|
|
60
|
-
langs.push('mermaid')
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// 为 mermaid ESM 兼容性配置 optimizeDeps
|
|
65
|
-
nuxt.hooks.hook('vite:extendConfig', (config) => {
|
|
66
|
-
const cfg = config as { optimizeDeps?: { include?: string[] } }
|
|
67
|
-
cfg.optimizeDeps ??= {}
|
|
68
|
-
cfg.optimizeDeps.include ??= []
|
|
69
|
-
cfg.optimizeDeps.include.push(
|
|
70
|
-
'@movk/nuxt-docs > mermaid',
|
|
71
|
-
'@movk/nuxt-docs > mermaid > dayjs',
|
|
72
|
-
'@movk/nuxt-docs > mermaid > @braintree/sanitize-url',
|
|
73
|
-
'@movk/nuxt-docs > mermaid > d3',
|
|
74
|
-
'@movk/nuxt-docs > mermaid > dompurify'
|
|
75
|
-
)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
// 注入 mermaid 代码图标配置到 appConfig
|
|
79
|
-
const appConfig = nuxt.options.appConfig as Record<string, any>
|
|
80
|
-
appConfig.ui ??= {}
|
|
81
|
-
appConfig.ui.prose ??= {}
|
|
82
|
-
appConfig.ui.prose.codeIcon ??= {}
|
|
83
|
-
appConfig.ui.prose.codeIcon.mmd ??= 'i-vscode-icons-file-type-mermaid'
|
|
84
|
-
|
|
85
|
-
log.info('[mermaid] Mermaid diagram support enabled')
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
declare module 'nuxt/schema' {
|
|
90
|
-
interface NuxtConfig {
|
|
91
|
-
mermaid?: MermaidModuleOptions
|
|
92
|
-
}
|
|
93
|
-
}
|
|
File without changes
|