import type { App, PluginConfig } from '@vuepress/core' import { activeHeaderLinksPlugin } from '@vuepress/plugin-active-header-links' import { docsearchPlugin } from '@vuepress/plugin-docsearch' import { externalLinkIconPlugin } from '@vuepress/plugin-external-link-icon' import { gitPlugin } from '@vuepress/plugin-git' import { mediumZoomPlugin } from '@vuepress/plugin-medium-zoom' import { nprogressPlugin } from '@vuepress/plugin-nprogress' import { palettePlugin } from '@vuepress/plugin-palette' import { searchPlugin } from '@vuepress/plugin-search' import { themeDataPlugin } from '@vuepress/plugin-theme-data' import { autoFrontmatterPlugin } from '@vuepress-plume/plugin-auto-frontmatter' import { baiduTongjiPlugin } from '@vuepress-plume/plugin-baidu-tongji' import { blogDataPlugin } from '@vuepress-plume/plugin-blog-data' import { caniusePlugin } from '@vuepress-plume/plugin-caniuse' import { copyCodePlugin } from '@vuepress-plume/plugin-copy-code' import { iconifyPlugin } from '@vuepress-plume/plugin-iconify' import { notesDataPlugin } from '@vuepress-plume/plugin-notes-data' import { shikijiPlugin } from '@vuepress-plume/plugin-shikiji' import { commentPlugin } from 'vuepress-plugin-comment2' import { type MarkdownEnhanceOptions, mdEnhancePlugin } from 'vuepress-plugin-md-enhance' import { readingTimePlugin } from 'vuepress-plugin-reading-time2' import { seoPlugin } from 'vuepress-plugin-seo2' import { sitemapPlugin } from 'vuepress-plugin-sitemap2' import { contentUpdatePlugin } from '@vuepress-plume/plugin-content-update' import type { PlumeThemeLocaleOptions, PlumeThemePluginOptions, } from '../shared/index.js' import autoFrontmatter from './autoFrontmatter.js' import { resolveLocaleOptions } from './resolveLocaleOptions.js' import { pathJoin } from './utils.js' import { resolveNotesList } from './resolveNotesList.js' import { resolvedDocsearchOption, resolvedSearchOptions } from './searchPluginOptions.js' export function setupPlugins( app: App, options: PlumeThemePluginOptions, localeOptions: PlumeThemeLocaleOptions, ): PluginConfig { const isProd = !app.env.isDev const notesList = resolveNotesList(localeOptions) const notesDirList = notesList .map(notes => notes.dir && pathJoin(notes.dir, '**').replace(/^\//, '')) .filter(Boolean) const blog = resolveLocaleOptions(localeOptions, 'blog') const plugins: PluginConfig = [ palettePlugin({ preset: 'sass' }), themeDataPlugin({ themeData: localeOptions }), autoFrontmatterPlugin(autoFrontmatter(app, options, localeOptions)), blogDataPlugin({ include: blog?.include ?? ['**/*.md'], exclude: [ '**/{README,readme,index}.md', '.vuepress/', 'node_modules/', ...(blog?.exclude ?? []), ...notesDirList, ].filter(Boolean), sortBy: 'createTime', excerpt: true, pageFilter: (page: any) => page.frontmatter.article !== undefined ? !!page.frontmatter.article : true, extendBlogData: (page: any) => ({ categoryList: page.data.categoryList, tags: page.frontmatter.tags, sticky: page.frontmatter.sticky, createTime: page.data.frontmatter.createTime, lang: page.lang, }), }), notesDataPlugin(notesList), iconifyPlugin(), contentUpdatePlugin(), activeHeaderLinksPlugin({ headerLinkSelector: 'a.outline-link', headerAnchorSelector: '.header-anchor', delay: 200, offset: 20, }), ] if (options.readingTime !== false) plugins.push(readingTimePlugin(options.readingTime || {})) if (options.nprogress !== false) plugins.push(nprogressPlugin()) if (options.git !== false) { plugins.push(gitPlugin({ createdTime: false, updatedTime: resolveLocaleOptions(localeOptions, 'lastUpdated') !== false, contributors: resolveLocaleOptions(localeOptions, 'contributors') !== false, })) } if (options.mediumZoom !== false) { plugins.push(mediumZoomPlugin({ selector: '.plume-content > img, .plume-content :not(a) > img', zoomOptions: { background: 'var(--vp-c-bg)' }, delay: 300, })) } if (options.caniuse !== false) plugins.push(caniusePlugin(options.caniuse || { mode: 'embed' })) if (options.externalLinkIcon !== false) { plugins.push(externalLinkIconPlugin({ locales: Object.entries(localeOptions.locales || {}).reduce( (result: Record, [key, value]) => { result[key] = { openInNewWindow: value.openInNewWindow ?? localeOptions.openInNewWindow, } return result }, {}, ), })) } if (options.docsearch) { if (options.docsearch.appId && options.docsearch.apiKey) plugins.push(docsearchPlugin(resolvedDocsearchOption(app, options.docsearch))) else console.error('docsearch plugin: appId and apiKey are both required') } else if (options.search !== false) { plugins.push(searchPlugin(resolvedSearchOptions(app, options.search))) } if (options.shikiji !== false) { plugins.push(shikijiPlugin({ theme: { light: 'vitesse-light', dark: 'vitesse-dark' }, ...(options.shikiji ?? {}), })) } if (options.copyCode !== false) { plugins.push(copyCodePlugin({ selector: '.plume-content div[class*="language-"] pre', ...options.copyCode, })) } if (options.markdownEnhance !== false) { plugins.push(mdEnhancePlugin( Object.assign( { hint: true, // info note tip warning danger details codetabs: true, tabs: true, align: true, mark: true, tasklist: true, demo: true, attrs: true, sup: true, sub: true, alert: true, footnote: true, katex: true, } as MarkdownEnhanceOptions, options.markdownEnhance || {}, ), )) } if (options.comment) plugins.push(commentPlugin(options.comment)) if (options.baiduTongji !== false && options.baiduTongji?.key) plugins.push(baiduTongjiPlugin(options.baiduTongji)) const hostname = resolveLocaleOptions(localeOptions, 'hostname') if (options.sitemap !== false && hostname && isProd) plugins.push(sitemapPlugin({ hostname })) if (options.seo !== false && hostname && isProd) { plugins.push(seoPlugin({ hostname, author: resolveLocaleOptions(localeOptions, 'avatar')?.name, })) } return plugins }