From 7b6e2c260001af12a0face735079185db5ef9743 Mon Sep 17 00:00:00 2001 From: qiang Date: Thu, 22 Aug 2024 14:33:13 +0800 Subject: [PATCH] docs: rendering example demos on the server side (#17472) * docs: rendering example demos on the server side * fix: render error * chore: update dependencies * chore: return all teleports --- docs/.vitepress/config/index.mts | 19 ++ docs/.vitepress/config/plugins.ts | 51 +--- docs/.vitepress/plugins/demo.ts | 55 +++++ docs/.vitepress/plugins/markdown-transform.ts | 24 +- docs/.vitepress/theme/index.ts | 7 +- .../components/common/vp-theme-toggler.vue | 3 + .../vitepress/components/demo/vp-example.vue | 28 --- .../components/demo/vp-source-code.vue | 6 +- .../doc-content/vp-table-of-content.vue | 42 ++-- .../vitepress/components/vp-demo.vue | 224 +++++++++--------- docs/components.d.ts | 1 - docs/examples/border/radius.vue | 18 +- docs/examples/statistic/countdown.vue | 4 +- pnpm-lock.yaml | 43 +--- typings/components.d.ts | 1 + 15 files changed, 256 insertions(+), 270 deletions(-) create mode 100644 docs/.vitepress/plugins/demo.ts delete mode 100644 docs/.vitepress/vitepress/components/demo/vp-example.vue diff --git a/docs/.vitepress/config/index.mts b/docs/.vitepress/config/index.mts index 6200874d27..e38e45e1ef 100644 --- a/docs/.vitepress/config/index.mts +++ b/docs/.vitepress/config/index.mts @@ -85,5 +85,24 @@ const config: UserConfig = { }, }, }, + + postRender(context) { + // Inject the teleport markup + if (context.teleports) { + const body = Object.entries(context.teleports).reduce( + (all, [key, value]) => { + if (key.startsWith('#el-popper-container-')) { + return `${all}
${value}
` + } + return all + }, + context.teleports.body || '' + ) + + context.teleports = { ...context.teleports, body } + } + + return context + }, } export default config diff --git a/docs/.vitepress/config/plugins.ts b/docs/.vitepress/config/plugins.ts index 00272394e9..10ab965152 100644 --- a/docs/.vitepress/config/plugins.ts +++ b/docs/.vitepress/config/plugins.ts @@ -1,66 +1,19 @@ -import path from 'path' -import fs from 'fs' import mdContainer from 'markdown-it-container' -import { docRoot } from '@element-plus/build-utils' import externalLinkIcon from '../plugins/external-link-icon' import tableWrapper from '../plugins/table-wrapper' import tooltip from '../plugins/tooltip' import tag from '../plugins/tag' import headers from '../plugins/headers' +import createDemoContainer from '../plugins/demo' import { ApiTableContainer } from '../plugins/api-table' -import type Token from 'markdown-it/lib/token' -import type Renderer from 'markdown-it/lib/renderer' import type MarkdownIt from 'markdown-it' -interface ContainerOpts { - marker?: string | undefined - validate?(params: string): boolean - render?( - tokens: Token[], - index: number, - options: any, - env: any, - self: Renderer - ): string -} - export const mdPlugin = (md: MarkdownIt) => { md.use(headers) md.use(externalLinkIcon) md.use(tableWrapper) md.use(tooltip) md.use(tag) - md.use(mdContainer, 'demo', { - validate(params) { - return !!params.trim().match(/^demo\s*(.*)$/) - }, - - render(tokens, idx) { - const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/) - if (tokens[idx].nesting === 1 /* means the tag is opening */) { - const description = m && m.length > 1 ? m[1] : '' - const sourceFileToken = tokens[idx + 2] - let source = '' - const sourceFile = sourceFileToken.children?.[0].content ?? '' - - if (sourceFileToken.type === 'inline') { - source = fs.readFileSync( - path.resolve(docRoot, 'examples', `${sourceFile}.vue`), - 'utf-8' - ) - } - if (!source) throw new Error(`Incorrect source file: ${sourceFile}`) - - return `` - } else { - return '' - } - }, - } as ContainerOpts) - + md.use(mdContainer, 'demo', createDemoContainer(md)) md.use(ApiTableContainer) } diff --git a/docs/.vitepress/plugins/demo.ts b/docs/.vitepress/plugins/demo.ts new file mode 100644 index 0000000000..d465f6bfec --- /dev/null +++ b/docs/.vitepress/plugins/demo.ts @@ -0,0 +1,55 @@ +import path from 'path' +import fs from 'fs' +import { docRoot } from '@element-plus/build-utils' +import type MarkdownIt from 'markdown-it' +import type Token from 'markdown-it/lib/token' +import type Renderer from 'markdown-it/lib/renderer' + +interface ContainerOpts { + marker?: string | undefined + validate?(params: string): boolean + render?( + tokens: Token[], + index: number, + options: any, + env: any, + self: Renderer + ): string +} + +function createDemoContainer(md: MarkdownIt): ContainerOpts { + return { + validate(params) { + return !!params.trim().match(/^demo\s*(.*)$/) + }, + + render(tokens, idx) { + const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/) + if (tokens[idx].nesting === 1 /* means the tag is opening */) { + const description = m && m.length > 1 ? m[1] : '' + const sourceFileToken = tokens[idx + 2] + let source = '' + const sourceFile = sourceFileToken.children?.[0].content ?? '' + + if (sourceFileToken.type === 'inline') { + source = fs.readFileSync( + path.resolve(docRoot, 'examples', `${sourceFile}.vue`), + 'utf-8' + ) + } + if (!source) throw new Error(`Incorrect source file: ${sourceFile}`) + + return ` + ` + } else { + return '\n' + } + }, + } +} + +export default createDemoContainer diff --git a/docs/.vitepress/plugins/markdown-transform.ts b/docs/.vitepress/plugins/markdown-transform.ts index cfe5777890..70e152f16a 100644 --- a/docs/.vitepress/plugins/markdown-transform.ts +++ b/docs/.vitepress/plugins/markdown-transform.ts @@ -1,5 +1,6 @@ import fs from 'fs' import path from 'path' +import { camelize } from '@vue/shared' import glob from 'fast-glob' import { docRoot, docsDirName, projRoot } from '@element-plus/build-utils' import { REPO_BRANCH, REPO_PATH } from '@element-plus/build-constants' @@ -35,9 +36,7 @@ export function MarkdownTransform(): Plugin { const append: Append = { headers: [], footers: [], - scriptSetups: [ - `const demos = import.meta.glob('../../examples/${componentId}/*.vue', { eager: true })`, - ], + scriptSetups: getExampleImports(componentId), } code = transformVpScriptSetup(code, append) @@ -144,3 +143,22 @@ ${linksText}` return code } + +const getExampleImports = (componentId: string) => { + const examplePath = path.resolve(docRoot, 'examples', componentId) + if (!fs.existsSync(examplePath)) return [] + const files = fs.readdirSync(examplePath) + const imports: string[] = [] + + for (const item of files) { + if (!/\.vue$/.test(item)) continue + const file = item.replace(/\.vue$/, '') + const name = camelize(`Ep-${componentId}-${file}`) + + imports.push( + `import ${name} from '../../examples/${componentId}/${file}.vue'` + ) + } + + return imports +} diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 79c4344e59..d411ada6f8 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,4 +1,7 @@ -import ElementPlus from 'element-plus' +import ElementPlus, { + ID_INJECTION_KEY, + ZINDEX_INJECTION_KEY, +} from 'element-plus' import VPApp, { NotFound, globals } from '../vitepress' import { define } from '../utils/types' @@ -11,6 +14,8 @@ export default define({ Layout: VPApp, enhanceApp: ({ app }) => { app.use(ElementPlus) + app.provide(ID_INJECTION_KEY, { prefix: 1024, current: 0 }) + app.provide(ZINDEX_INJECTION_KEY, { current: 0 }) globals.forEach(([name, Comp]) => { app.component(name, Comp) diff --git a/docs/.vitepress/vitepress/components/common/vp-theme-toggler.vue b/docs/.vitepress/vitepress/components/common/vp-theme-toggler.vue index a50e896bd7..2148b0d41e 100644 --- a/docs/.vitepress/vitepress/components/common/vp-theme-toggler.vue +++ b/docs/.vitepress/vitepress/components/common/vp-theme-toggler.vue @@ -5,6 +5,8 @@ import DarkIcon from '../icons/dark.vue' import LightIcon from '../icons/light.vue' import type { SwitchInstance } from 'element-plus' +defineOptions({ inheritAttrs: false }) + const darkMode = ref(isDark.value) const switchRef = ref() @@ -67,6 +69,7 @@ const beforeChange = () => { -defineProps({ - file: { - type: String, - required: true, - }, - demo: { - type: Object, - required: true, - }, -}) - - - - - diff --git a/docs/.vitepress/vitepress/components/demo/vp-source-code.vue b/docs/.vitepress/vitepress/components/demo/vp-source-code.vue index 16b8ddf647..6f3cb3dae9 100644 --- a/docs/.vitepress/vitepress/components/demo/vp-source-code.vue +++ b/docs/.vitepress/vitepress/components/demo/vp-source-code.vue @@ -2,6 +2,10 @@ import { computed } from 'vue' const props = defineProps({ + visible: { + type: Boolean, + required: true, + }, source: { type: String, required: true, @@ -14,7 +18,7 @@ const decoded = computed(() => { diff --git a/docs/.vitepress/vitepress/components/doc-content/vp-table-of-content.vue b/docs/.vitepress/vitepress/components/doc-content/vp-table-of-content.vue index dd78dedabe..83275bf2f4 100644 --- a/docs/.vitepress/vitepress/components/doc-content/vp-table-of-content.vue +++ b/docs/.vitepress/vitepress/components/doc-content/vp-table-of-content.vue @@ -19,28 +19,26 @@ const sponsor = computed(() => sponsorLocale[lang.value])