# Plugins --- --- url: /ecosystem/plugins/ai/index.md --- # AI Plugins --- --- url: /ecosystem/plugins/ai/llms.md --- # plugin-llms Add [llms.txt](https://llmstxt.org/) to your site to provide LLM-friendly content. ## Usage ```bash npm i -D @vuepress/plugin-llms@next ``` ```ts title=".vuepress/config.ts" import { llmsPlugin } from '@vuepress/plugin-llms' export default { plugins: [ llmsPlugin({ // options }), ], } ``` ## Why llms.txt? Large language models increasingly rely on website information, but face a critical limitation: context windows are too small to handle most websites in their entirety. Converting complex HTML pages with navigation, ads, and JavaScript into LLM-friendly plain text is both difficult and imprecise. While websites serve both human readers and LLMs, the latter benefit from more concise, expert-level information gathered in a single, accessible location. This is particularly important for use cases like development environments, where LLMs need quick access to programming documentation and APIs. Add a `/llms.txt` Markdown file to the website to provide LLM-friendly content. This file includes brief background information, guidelines, and links to detailed Markdown files. ### Plugin Features The plugin retrieves all Markdown files from your document source directory and converts them into LLM-friendly plain text files. ```txt ๐Ÿ“‚ .vuepress/dist โ”œโ”€โ”€ ... โ”œโ”€โ”€ llms.txt โ”œโ”€โ”€ llms-full.txt โ”œโ”€โ”€ markdown-examples.html โ””โ”€โ”€ markdown-examples.md ``` Click the link below to view the `llms.txt` file of this documentation site: * llms.txt * llms-full.txt ::: tip The plugin only generates the `llms.txt` file, along with other LLM-friendly documentation files, during the production buildโ€”that is, when the `vuepress build` command is executedโ€”and outputs them to the `.vuepress/dist` directory. ::: ### `llms.txt` The `llms.txt` file contains the **title**, **description**, **details (optional)**, and **Table of Contents (TOC)** for the site. The default format is as follows: ```md title="llms.txt" # Title > Description Details (Optional) ## Table of Contents - [title](url): description - [title](url): description - โ€ฆ ``` * **Site Title**: Values are determined in the following order: 1. `llmsTxtTemplateGetter.title` 2. `heroText` in homepage frontmatter 3. Current locale's [title](https://v2.vuepress.vuejs.org/reference/config.html#locales) in VuePress config file 4. [title](https://v2.vuepress.vuejs.org/reference/config.html#title) in VuePress config file 5. Page title of locale homepage (locale `README.md`) * **Site Description**: Values are determined in the following order: 1. `llmsTxtTemplateGetter.description` 2. `tagline` in locale homepage frontmatter 3. Current locale's [description](https://v2.vuepress.vuejs.org/reference/config.html#locales) in VuePress config file 4. [description](https://v2.vuepress.vuejs.org/reference/config.html#description) in VuePress config file 5. `frontmatter.description` in locale homepage (locale `README.md`) * **Site Details (Optional)**: Values are determined in the following order: 1. `llmsTxtTemplateGetter.details` 2. `frontmatter.details` in locale homepage (`README.md`) * **Table of Contents (TOC)**: Formatted as `- [title](url): description`, where `description` is taken from `frontmatter.description`. If it does not exist, only `- [title](url)` is displayed. By default, the plugin only generates first-level TOC, and the default getter function is as follows: ```ts import { generateTOCLink } from '@vuepress/plugin-llms' const defaultTOCGetter = (pages, state) => pages.map((page) => generateTOCLink(page, state)).join('\n') ``` You can customize it to generate a multi-level TOC by setting a custom function with the [`llmsTxtTemplateGetter`](#llmstxttemplategetter) option. ### `llms-full.txt` `llms-full.txt` contains **links**, **descriptions**, and **Markdown-formatted content** for each page. Its format is as follows: ```txt title="llms-full.txt" --- url: url description: optional description --- page's Markdown-formatted content --- --- url: url description: optional description --- page's Markdown-formatted content โ€ฆ ``` The plugin directly merges the content of the Markdown files in the document source directory into `llms-full.txt` so that LLMs can read and analyze it. ### Page Contents The plugin generates accessible Markdown files for each page in the format `${url}.md`. For example, `/guide/quick-start.html` will produce a corresponding `/guide/quick-start.md` file. ## Options ### llmsTxt * Type: `boolean` * Default: `true` * Details: Whether to generate the `llms.txt` file, which contains a list of sections with corresponding links. ### llmsFullTxt * Type: `boolean` * Default: `true` * Details: Whether to generate the `llms-full.txt` file which contains all the documentation in one file. ### llmsPageTxt * Type: `boolean` * Default: `true` * Details: Whether to generate an LLM-friendly version of the documentation for each page on the website. ### stripHTML * Type: `boolean` * Default: `true` * Details: Whether to strip HTML tags from Markdown files. ### filter * Type: `(page: Page) => boolean` * Default: `() => true` * Details: Page filter function. When it returns `true`, the page will be included in `llms.txt`, otherwise it will be excluded. Pages that are disabled by `frontmatter.llmstxt` or not generated from Markdown files will be excluded anyway. ### domain * Type: `string` * Default: `''` * Details: The domain that will be prepended to URLs in `llms.txt` and other files. Domain attachment is not yet standardized (since it depends on whether the AI can resolve the relative paths that are currently there), but you can add it if needed. ```md title="llms.txt" - [title](/foo/bar.md) - [title](https://example.com/foo/bar.md) ``` ### locale * Types: `string | 'all'` * Default: `'/'` * Details: The locale of the site to generate. If not set, the plugin will use the default locale of the VuePress site. If you set it to `'all'`, the plugin will generate `llms.txt` for all locales. This option is useful when you have multiple locales and want to generate `llms.txt` for a specific locale, which should have the best documentation quality. Also, if you have many self-defined concepts that LLMs cannot understand or translate correctly, you should consider generating `llms.txt` for each locale to avoid confusion with different representations coming from LLM translation and the original documentation. ### llmsTxtTemplate * Types: `string` * Default: ```ts const DEFAULT_LLMSTXT_TEMPLATE = `\ # {title} {description} {details} ## Table of Contents {toc}` ``` * Details: A custom template for the `llms.txt` file, allowing for a personalized order of elements. By default, `{title}`, `{description}`, `{details}`, and `{toc}` are available. ### llmsTxtTemplateGetter * Type: `TemplateGetterOptions` ```ts /** * Link extension options for generated links */ export type LinkExtension = '.html' | '.md' /** * Page with additional LLM-friendly content */ export interface LLMPage extends Page { /** * The page's Markdown content * * @example '# Guide\n\nA guide' */ markdown: string /** * The page's excerpt * * @example 'Introduction to the guide' */ excerpt: string } /** * State object for LLM text generation */ export interface LLMState { /** * VuePress app instance */ app: App /** * Site base URL */ base: string /** * Optional domain to prepend to URLs */ domain?: string /** * Link extension for generated links */ linkExtension?: LinkExtension /** * The path of the current locale. */ currentLocale: string /** * Current site locale data */ siteLocale: SiteLocaleData /** * Whether to generate llms.txt files for all locales. */ allLocales: boolean } export type TemplateGetter = (pages: LLMPage[], state: LLMState) => string export interface TemplateGetterOptions { /** Any custom variable */ [key: string]: TemplateGetter | string | undefined } ``` * Default: `{}` * Details: Custom variables for the [`llmsTxtTemplate`](#llmstxttemplate). With this option you can add and override template variables. For example, setting a customized title for `llms.txt`: ```ts llmsPlugin({ llmsTxtTemplateGetter: { title: 'My title', }, }) ``` Or adding a custom variable `foo` to the template: ```ts llmsPlugin({ llmsTxtTemplate: '# {title}\n\n{foo}', llmsTxtTemplateGetter: { foo: 'My foo', }, }) ``` You can also add getter functions to the template: ```ts llmsPlugin({ llmsTxtTemplate: '# {title}\n\n## Pages\n\n{titles}', llmsTxtTemplateGetter: { titles: (pages, state) => pages.map((page) => `- ${page.title}`).join('\n'), }, }) ``` ## Frontmatter The following `frontmatter` will be used in the plugin. ### title {#frontmatter-title} * Types: `string` * Details: On the homepage (`README.md`), it serves as an alternative title for `llms.txt`. On other pages, it functions as the page title. ### description {#frontmatter-description} * Types: `string` * Details: On the homepage (`README.md`), as an alternative description for `llms.txt`. On other pages, as the page description. It is recommended to add concise and clear descriptions to the page, providing key information for LLMs to understand it. ### heroText {#frontmatter-herotext} * Types: `string` * Details: Being read from homepage (locale `README.md`) only, as title of `llms.txt`. ### tagline {#frontmatter-tagline} * Types: `string` * Details: Being read from homepage (locale `README.md`) only, as description of `llms.txt`. ### details {#frontmatter-details} * Types: `string` * Details: Being read from homepage (locale `README.md`) only, as details of `llms.txt`. ### llmstxt * Types: `boolean` * Default: `true` * Details: Whether the current page should be included in `llms.txt`. ## Others It is recommended to configure redirects so that AI can use addresses with `.md` and `.txt` extensions. For example, in `Netlify`, configure the following in `public/_redirects`: ```txt /llms.md /llms.txt 200! /llms-full.md /llms-full.txt 200! ``` Options syntax documentation: --- --- url: /ecosystem/plugins/analytics/index.md --- # Analytics Plugins --- --- url: /ecosystem/plugins/analytics/baidu-analytics.md --- # baidu-analytics Integrate [Baidu Analytics](https://tongji.baidu.com/) into VuePress. ::: tip Do not enable [SPA mode in Baidu Analytics](https://tongji.baidu.com/web/help/article?id=324\&type=0). The plugin will report page view events correctly. ::: ## Usage ```bash npm i -D @vuepress/plugin-baidu-analytics@next ``` ```ts title=".vuepress/config.ts" import { baiduAnalyticsPlugin } from '@vuepress/plugin-baidu-analytics' export default { plugins: [ baiduAnalyticsPlugin({ // options }), ], } ``` ### Reporting Events The plugin automatically reports page view events on page visits and route changes. A global `_hmt` array is available on the `window` object for [custom event reporting](https://tongji.baidu.com/holmes/Analytics/%E6%8A%80%E6%9C%AF%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97/JS%20API/JS%20API%20%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C). ## Options ### id * Type: `string` * Required: Yes * Details: Baidu Analytics tracking ID, which is the query parameter in the `hm.js` URL. --- --- url: /ecosystem/plugins/analytics/google-analytics.md --- # google-analytics Integrate [Google Analytics](https://analytics.google.com/) into VuePress. This plugin imports [gtag.js](https://developers.google.com/analytics/devguides/collection/gtagjs) to enable [Google Analytics 4](https://support.google.com/analytics/answer/10089681) tracking. ## Usage ```bash npm i -D @vuepress/plugin-google-analytics@next ``` ```ts title=".vuepress/config.ts" import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' export default { plugins: [ googleAnalyticsPlugin({ // options }), ], } ``` ### Reporting Events Google Analytics [automatically collects some events](https://support.google.com/analytics/answer/9234069), such as `page_view`, `first_visit`, etc. If you only need to collect basic site data, simply set the [Measurement ID](#id) correctly. After using this plugin, the global `gtag()` function is available on the `window` object for [custom event reporting](https://developers.google.com/analytics/devguides/collection/ga4/events). ## Options ### id * Type: `string` * Required: Yes * Details: Google Analytics 4 Measurement ID, which should start with `'G-'`. You can follow the instructions [here](https://support.google.com/analytics/answer/9539598) to find your Measurement ID. Note the difference between Google Analytics 4 Measurement ID ("G-" ID) and Universal Analytics Tracking ID ("UA-" ID). * Example: ```ts title=".vuepress/config.ts" export default { plugins: [ googleAnalyticsPlugin({ id: 'G-XXXXXXXXXX', }), ], } ``` ### debug * Type: `boolean` * Details: Set to `true` to enable sending events to DebugView. [See more information on DebugView](https://support.google.com/analytics/answer/7201382). * Example: ```ts title=".vuepress/config.ts" export default { plugins: [ googleAnalyticsPlugin({ id: 'G-XXXXXXXXXX', debug: true, }), ], } ``` --- --- url: /ecosystem/plugins/analytics/umami-analytics.md --- # umami-analytics Integrate [Umami Analytics](https://umami.is/) into VuePress. ## Usage ```bash npm i -D @vuepress/plugin-umami-analytics@next ``` ```ts title=".vuepress/config.ts" import { umamiAnalyticsPlugin } from '@vuepress/plugin-umami-analytics' export default { plugins: [ umamiAnalyticsPlugin({ // options }), ], } ``` You can use [Umami Cloud](https://cloud.umami.is/login) or [Self-host Umami](https://umami.is/docs/install). ### Reporting Events The plugin automatically reports page view events on page visits and route changes. A global `umami` object is available on the `window` object, and you can call `umami.track` for [custom tracking](https://umami.is/docs/tracker-functions). ## Options ### id * Type: `string` * Required: Yes * Details: The website ID from Umami Analytics ### link * Type: `string` * Default: `'https://us.umami.is/script.js'` * Details: URL to the Umami Analytics tracking script ### autoTrack * Type: `boolean` * Default: `true` * Details: By default, Umami tracks all pageviews and events automatically. Set to `false` to disable automatic tracking and use manual tracking functions. ### cache * Type: `boolean` * Details: Cache data to improve tracking script performance. Note: This will use session storage so you may need to inform your users. ### domains * Type: `string[]` * Details: Restrict tracking to specific domains only. ### hostUrl * Type: `string` * Default: `link` * Details: Custom endpoint for sending tracking data. --- --- url: /ecosystem/plugins/blog/index.md --- # Blog Plugins --- --- url: /ecosystem/plugins/blog/blog/index.md --- # blog Blog plugin for VuePress, providing article collection, categorization, type filtering, and excerpt generation. ## Usage ```bash npm i -D @vuepress/plugin-blog@next ``` ```ts title=".vuepress/config.ts" import { blogPlugin } from '@vuepress/plugin-blog' export default { plugins: [ blogPlugin({ // options }), ], } ``` --- --- url: /ecosystem/plugins/blog/blog/config.md --- # Config ## Plugin Options ### getInfo * Type: `(page: Page) => Record` * Reference: * [Guide โ†’ Article Collection](./guide.md#gathering-info) * Details: Function to extract article information from pages. Article info will be injected into route meta, making it available in client composables. ### filter * Type: `(page: Page) => boolean` * Default: `(page) => Boolean(page.filePathRelative) && !page.frontmatter.home` * Reference: * [Guide โ†’ Article Collection](./guide.md#collecting-articles) * Details: Function to filter pages for blog articles. By default, all pages generated from Markdown files except homepage are included. ### category * Type: `BlogCategoryOptions[]` * Reference: * [Guide โ†’ Categories and Types](./guide.md#customizing-categories-and-types) * Details: Category configurations. See [Category Config](#blog-category-config). ### type * Type: `BlogTypeOptions[]` * Reference: * [Guide โ†’ Categories and Types](./guide.md#customizing-categories-and-types) * Details: Type configurations. See [Type Config](#blog-type-config). ### slugify * Type: `(name: string) => string` * Default: `(name) => name.replace(/ _/g, '-').replace(/[:?*|\\/<>]/g, "").toLowerCase()` * Details: Function to convert strings to URL-friendly slugs for route registration. ### excerpt * Type: `boolean` * Default: `true` * Reference: [Guide โ†’ Excerpt Generation](./guide.md#generating-excerpt) * Details: Whether to generate excerpt for pages. ### excerptSeparator * Type: `string` * Default: `` * Reference: * [Guide โ†’ Excerpt Generation](./guide.md#generating-excerpt) * Details: Separator for manual excerpt in content. ### excerptLength * Type: `number` * Default: `300` * Reference: * [Guide โ†’ Excerpt Generation](./guide.md#generating-excerpt) * Details: Target length for auto-generated excerpts. ::: tip Excerpt length will be the minimal possible length reaching this value. Set to `0` to disable auto excerpt generation. ::: ### excerptFilter * Type: `(page: Page) => boolean` * Default: Same as `filter` option * Reference: * [Guide โ†’ Excerpt Generation](./guide.md#generating-excerpt) * Details: Function to filter pages for excerpt generation. ::: tip Use this to skip pages that don't need excerpt generation. For example, if users set `excerpt` or `description` in frontmatter, you may want to use them directly. ::: ### isCustomElement * Type: `(tagName: string) => boolean` * Default: `() => false` * Reference: * [Guide โ†’ Generating Excerpt](./guide.md#generating-excerpt) * Details: Tags which is considered as custom elements. This is used to determine whether a tag is a custom element since all unknown tags are removed in excerpt. ### metaScope * Type: `string` * Default: `"_blog"` * Details: Key used when injecting info to route meta. ::: tip Setting to an empty key will inject to route meta directly instead of a field. ::: ### hotReload * Type: `boolean` * Default: Whether using `--debug` flag * Details: Whether enable hotReload in devServer. ::: tip To theme developers It's disabled by default because it does have performance impact in sites with a lot of categories and types. And it can slow down hotReload speed when editing Markdown. If users are adding or organizing your categories or tags, you may tell them to enable this, for the rest it's better to keep it disabled. Also, you can try to detect number of pages in users project and decide whether to enable it. ::: ## Blog Category Config Blog category config should be an array, while each item is controlling a "category" rule. ```ts interface BlogCategoryOptions { /** * Unique category name */ key: string /** * Function getting category from page */ getter: (page: Page) => string[] /** * A custom function to sort the pages */ sorter?: (pageA: Page, pageB: Page) => number /** * Path pattern of page to be registered * * @description `:key` will be replaced by the "slugify" result of the original key * * @default `/:key/` */ path?: string | false /** * Page layout name * * @default 'Layout' */ layout?: string /** * Frontmatter */ frontmatter?: (localePath: string) => Record /** * Item page path pattern or custom function to be registered * * @description When filling in a string, `:key` and `:name` will be replaced by the "slugify" result of the original key and name * * @default `/:key/:name/` */ itemPath?: string | false | ((name: string) => string) /** * Item page layout name * * @default 'Layout' */ itemLayout?: string /** * Items Frontmatter */ itemFrontmatter?: (name: string, localePath: string) => Record } ``` ## Blog Type Config Blog type config should be an array, while each item is controlling a "type" rule. ```ts interface BlogTypeOptions { /** * Unique type name */ key: string /** * A filter function to determine whether a page should be the type */ filter: (page: Page) => boolean /** * A custom function to sort the pages */ sorter?: (pageA: Page, pageB: Page) => number /** * Page path to be registered * * @default '/:key/' */ path?: string /** * Layout name * * @default 'Layout' */ layout?: string /** * Frontmatter */ frontmatter?: (localePath: string) => Record } ``` ## Composition API You can import the following API from `@vuepress/plugin-blog/client`. * Blog category ```ts const useBlogCategory: < T extends Record = Record, >( key?: string, ) => ComputedRef> ``` Argument `key` should be the category unique key. If no key is passed, the plugin will try to use the key in current path. * Blog category ```ts const useBlogType: < T extends Record = Record, >( key?: string, ) => ComputedRef> ``` Argument `key` should be the type unique key. If no key is passed, the plugin will try to use the key in current path. Returning values are: ```ts interface Article = Record> { /** Article path */ path: string /** Article info */ info: T } interface BlogCategoryData< T extends Record = Record, > { /** Category path */ path: string /** * Only available when current route matches an item path */ currentItems?: Article[] /** Category map */ map: { /** Unique key under current category */ [key: string]: { /** Category path of the key */ path: string /** Category items of the key */ items: Article[] } } } interface BlogTypeData< T extends Record = Record, > { /** Type path */ path: string /** Items under current type */ items: Article[] } ``` --- --- url: /ecosystem/plugins/blog/blog/guide.md --- # Guide Adds blog functionality to VuePress themes with article collection, categorization, and excerpt generation. ## Article Collection The plugin filters pages using the `filter` option to determine which pages should be treated as articles. ::: tip By default, all pages generated from Markdown files except the homepage are considered articles. ::: ## Gathering Info Set the `getInfo` option with a function that extracts article information from pages. The plugin injects collected information into the `routeMeta` field, making it available through Composition API. ::: details Demo ```ts title="theme entrance" import { blogPlugin } from '@vuepress/plugin-blog' export default { name: 'vuepress-theme-xxx', plugins: [ blogPlugin({ filter: ({ filePathRelative, frontmatter }) => { // drop those pages which is NOT generated from file if (!filePathRelative) return false // drop those pages in `archives` directory if (filePathRelative.startsWith('archives/')) return false // drop those pages which do not use default layout if (frontmatter.home || frontmatter.layout) return false return true }, getInfo: ({ frontmatter, title, git = {}, data = {} }) => { // get page info const info: Record = { title, author: frontmatter.author || '', categories: frontmatter.categories || [], date: frontmatter.date || git.createdTime || null, tags: frontmatter.tags || [], excerpt: data.excerpt || '', } return info }, }), // other plugins ... ], } ``` ::: ## Customizing Categories and Types Basically, you would want 2 types of collections in your blog: * Category: "Category" means grouping articles with their labels. For example, each article may have "categories" and "tags". * Type: "Type" means identifying articles with conditions. For example, you may want to describe some of your articles as diary. After understanding the description of these 2 types, you can set the `category` and `type` options, each accepts an array, and each element represents a configuration. Let's start with 2 examples here. Imagine you are setting tags for each article with the `tag` field in page frontmatter. You want a tag mapping page in `/tag/` with `TagMap` layout, and group each tag list with tagName in `/tag/tagName` with `TagList` layout, you probably need a configuration like this: ```ts title="theme entrance" import { blogPlugin } from '@vuepress/plugin-blog' export default { name: 'vuepress-theme-xxx', plugins: [ blogPlugin({ // other options ... category: [ { key: 'tag', getter: ({ frontmatter }) => frontmatter.tag || [], path: '/tag/', layout: 'TagMap', frontmatter: () => ({ title: 'Tag page' }), itemPath: '/tag/:name/', itemLayout: 'TagList', itemFrontmatter: (name) => ({ title: `Tag ${name}` }), }, ], }), // other plugins ... ], } ``` Also, you may want to star some of your articles and display them to visitors. When you are setting `star: true` in frontmatter to mark them, you probably need a configuration like this to display them in the `/star/` path with `StarList` layout: ```ts title="theme entrance" import { blogPlugin } from '@vuepress/plugin-blog' export default { name: 'vuepress-theme-xxx', plugins: [ blogPlugin({ // other options ... type: [ { key: 'star', filter: ({ frontmatter }) => frontmatter.star, path: '/star/', layout: 'StarList', frontmatter: () => ({ title: 'Star page' }), }, ], }), // other plugins ... ], } ``` See, setting these 2 types is easy. For full options, please see [Category Config](./config.md#blog-category-config) and [Type Config](./config.md#blog-type-config). ## Using Composition API in Client-side When generating each page, the plugin will set the following information under `frontmatter.blog`: ```ts interface BlogFrontmatterOptions { /** Current type of the page */ type: 'category' | 'type' /** Unique key under current category or tag */ key: string /** * Current category name * * @description Only available in category item page */ name?: string } ``` So you can invoke `useBlogCategory()` and `useBlogType()` directly, and the result will be the category or type bound to the current route. Also, you can pass the `key` you want as an argument, then you will get information bound to that key. So with the node side settings above, you can get information about "tag" and "star" in the client side: `TagMap` layout: ```vue ``` `TagList` layout: ```vue ``` `StarList` layout: ```vue ``` For return types, please see [Composition API Return Types](./config.md#composition-api). ## I18n Support This plugin adds native i18n support, so your settings will be automatically applied to each language. For example, if the user has the following locales config, and you are setting the "star" example above: ```ts title=".vuepress/config.ts" export default { locales: { '/': { lang: 'en-US', }, '/zh/': { lang: 'zh-CN', }, }, } ``` Then `/zh/star/` and `/star/` will both be available, and only articles under the correct locale will appear. ## Generating Excerpt This plugin provides a built-in excerpt generator, which can be enabled by setting the `excerpt` option to `true`. ::: tip Excerpt introduction An excerpt is an HTML fragment that is used to display a short description of an article in the blog list, so the excerpt has the following restrictions: * It doesn't support any unknown tags (including all Vue components) and Vue syntax, so these contents will be removed when generating. If you have custom components (non-Vue components), set the `isCustomElement` option. * Since the excerpt is an HTML fragment, you will not be able to import any images via relative paths or aliases, they will be removed directly. If you want to keep images, please use absolute paths based on `.vuepress/public` or full URLs to ensure they can be accessed in other places. ::: The excerpt generator will try to find a valid excerpt separator from markdown contents, if it finds one, it will use content before the separator. The separator is default ``, and you can customize it by setting the `excerptSeparator` option. If it cannot find a valid separator, it will parse content from the beginning of the markdown file, and stop till its length reaches a preset value. The value is default `300`, and you can customize it by setting the `excerptLength` option. To choose which page should generate excerpt, you can use the `excerptFilter` option. ::: tip Example Normally you may want to use `frontmatter.description` if users set them, so you can let the filter function return `false` if `frontmatter.description` is not empty. ::: --- --- url: /ecosystem/plugins/blog/comment/index.md --- # comment Comment plugin for VuePress supporting multiple providers. ## Usage ```bash npm i -D @vuepress/plugin-comment@next ``` ```ts title=".vuepress/config.ts" import { commentPlugin } from '@vuepress/plugin-comment' export default { plugins: [ commentPlugin({ provider: 'Waline', // Artalk | Giscus | Waline | Twikoo // provider-specific options }), ], } ``` ## Supported Providers * [Artalk](./artalk/) * [Giscus](./giscus/) * [Twikoo](./twikoo/) * [Waline](./waline/) ## Guide See [Guide](./guide.md) for detailed configuration. --- --- url: /ecosystem/plugins/blog/comment/artalk/index.md --- # Artalk Artalk is a clean self-hosted commenting system that you can easily deploy on your server and integrate into your front-end pages. Deploy the Artalk comment box on your blog or any other page to add rich social functionality. ## Install ```bash npm i -D artalk ``` ## Deploy Artalk Server See the [Artalk documentation](https://artalk.js.org/guide/deploy.html). ## Configuration Please set `provider: "Artalk"` and pass your server link to `server` in the plugin options. For other configuration items, see [Artalk Config](./config.md). ::: tip The plugin retains the `el` option and inserts Artalk itself on the page. At the same time, the plugin will automatically set the `pageTitle`, `pageKey` and `site` options for you according to the VuePress information. ::: ## Dark Mode To let Artalk apply the correct theme, you need to pass a boolean value to `` through `darkmode` prop, representing whether the dark mode is currently enabled. --- --- url: /ecosystem/plugins/blog/comment/artalk/config.md --- # Artalk Options ## Config See [Artalk Configuration](https://artalk.js.org/guide/frontend/config.html) for details. * The `el`, `pageTitle`, `pageKey`, and `site` options are reserved for the plugin and will be automatically inferred from VuePress config. * The two function options `imgUploader` and `avatarURLBuilder` can only be set on the client side. ## Plugin Config You can directly configure serializable options in the plugin options: ```ts title=".vuepress/config.ts" import { commentPlugin } from '@vuepress/plugin-comment' export default { plugins: [ commentPlugin({ provider: 'Artalk', // other options // ... }), ], } ``` ## Client Config You can use the `defineArtalkConfig` function to customize Artalk: ```ts title=".vuepress/client.ts" import { defineArtalkConfig } from '@vuepress/plugin-comment/client' import { defineClientConfig } from 'vuepress/client' defineArtalkConfig({ // Artalk config }) ``` --- --- url: /ecosystem/plugins/blog/comment/giscus/index.md --- # Giscus Giscus is a commenting system based on GitHub Discussion that is easy to start. ## Preparation 1. Create a public repository and open discussion panel as a place to store comments. 2. Install the [Giscus App](https://github.com/apps/giscus) to have permission to access the corresponding repository. 3. After completing the above steps, please go to the [Giscus page](https://giscus.app) to get your settings. You just need to fill in the repository and Discussion categories, then scroll to the "Enable giscus" section at the bottom of the page and obtain four attributes: `data-repo`, `data-repo-id`, `data-category` and `data-category-id`. ## Config Please set `provider: "Giscus"` and pass `data-repo`, `data-repo-id`, `data-category` and `data-category-id` as plugin options as `repo`, `repoId`, `category` `categoryId`. For other options, see [Giscus Config](./config.md). ## Theme By default, the theme of Giscus is `light` or `dark` (based on darkmode status). ::: tip Dark Mode To let Giscus apply the correct theme, you need to pass a boolean value to `` via `darkmode` property, indicating whether darkmode is currently enabled. ::: If you want to customize theme in lightmode and darkmode, you can set `lightTheme` and `darkTheme` option with a built-in theme keyword or a custom CSS link starting with `https://`. --- --- url: /ecosystem/plugins/blog/comment/giscus/config.md --- # Giscus Options ## Config ### repo * Type: `string` * Required: Yes * Details: The name of repository to store discussions ### repoId * Type: `string` * Required: Yes * Details: The ID of repository to store discussions. Generate through [Giscus Page](https://giscus.app/) ### category * Type: `string` * Required: Yes * Details: The name of the discussion category ### categoryId * Type: `string` * Required: Yes * Details: The ID of the discussion category. Generate through [Giscus Page](https://giscus.app/) ### mapping * Type: `string` * Default: `"pathname"` * Details: Page - Discussion mapping. For details see [Giscus Page](https://giscus.app/) ### strict * Type: `boolean` * Default: `true` * Details: Whether to enable strict mapping ### lazyLoading * Type: `boolean` * Default: `true` * Details: Whether to enable lazy loading ### reactionsEnabled * Type: `boolean` * Default: `true` * Details: Whether to enable reactions ### inputPosition * Type: `"top" | "bottom"` * Default: `"top"` * Details: Input position ### lightTheme * Type: `GiscusTheme` ```ts type GiscusTheme = | 'dark_dimmed' | 'dark_high_contrast' | 'dark_protanopia' | 'dark' | 'light_high_contrast' | 'light_protanopia' | 'light' | 'preferred_color_scheme' | 'transparent_dark' | `https://${string}` ``` * Default: `"light"` * Details: Giscus theme used in light mode Should be a built-in theme keyword or a CSS link starting with `https://`. ### darkTheme * Type: `GiscusTheme` ```ts type GiscusTheme = | 'dark_dimmed' | 'dark_high_contrast' | 'dark_protanopia' | 'dark' | 'light_high_contrast' | 'light_protanopia' | 'light' | 'preferred_color_scheme' | 'transparent_dark' | `https://${string}` ``` * Default: `"dark"` * Details: Giscus theme used in dark mode Should be a built-in theme keyword or a CSS link starting with `https://`. ## Plugin Config You can directly configure serializable options in the plugin options: ```ts title=".vuepress/config.ts" import { commentPlugin } from '@vuepress/plugin-comment' export default { plugins: [ commentPlugin({ provider: 'Giscus', // other options // ... }), ], } ``` ## Client Config You can use the `defineGiscusConfig` function to customize Giscus: ```ts title=".vuepress/client.ts" import { defineGiscusConfig } from '@vuepress/plugin-comment/client' import { defineClientConfig } from 'vuepress/client' defineGiscusConfig({ // Giscus config }) ``` --- --- url: /ecosystem/plugins/blog/comment/guide.md --- # Guide ## Configuration Configure the plugin with its options and client config file. ### Using Plugin Options ```ts title=".vuepress/config.ts" import { commentPlugin } from '@vuepress/plugin-comment' export default { plugins: [ commentPlugin({ provider: 'Artalk', // Artalk | Giscus | Waline | Twikoo // provider-specific options }), ], } ``` ### Using Client Config ```ts title=".vuepress/client.ts" import { defineArtalkConfig, // defineGiscusConfig, // defineTwikooConfig, // defineWalineConfig, } from '@vuepress/plugin-comment/client' import { defineClientConfig } from 'vuepress/client' defineArtalkConfig({ // options }) ``` ### Configuration Limitations * **Plugin Options Only**: `provider`, locales, and resource-related options must be set in plugin options for tree-shaking optimization. * **Client Config Only**: Function-based options must be set in client config as they cannot be serialized. ## Using Comments The plugin registers a global `` component. **For Users**: Use aliases and layout slots to insert the component. Recommended placement is after ``. **For Theme Developers**: Insert the component in your theme layout. ### Comment Control Control comments via plugin options or page frontmatter: * **Global**: Set `comment: false` in plugin options to disable globally * **Per Page**: Set `comment: true/false` in frontmatter to enable/disable locally * **Custom ID**: Set `commentID` in frontmatter to customize comment storage identifier ## Available Providers Choose from [Giscus](giscus/README.md), [Waline](waline/README.md), [Artalk](artalk/README.md), or [Twikoo](twikoo/README.md). ::: tip Recommendations * **Developers**: Giscus (GitHub-based) * **General Users**: Waline (full-featured) ::: ## Common Options ### provider * Type: `"Artalk" | "Giscus" | "Twikoo" | "Waline" | "None"` * Default: `"None"` * Details: Comment service provider. ### comment * Type: `boolean` * Default: `true` * Details: Whether to enable comment feature by default. --- --- url: /ecosystem/plugins/blog/comment/twikoo/index.md --- # Twikoo A concise, safe and free static site commenting system, based on [Tencent Cloud Development](https://curl.qcloud.com/KnnJtUom). ## Install ```bash npm i -D twikoo ``` ## Getting started 1. Apply for [MongoDB](https://www.mongodb.com/cloud/atlas/register) account 2. Create a free MongoDB database, the recommended region is `AWS / N. Virginia (us-east-1)` 3. Click CONNECT on the Clusters page, follow the steps to allow connections from all IP addresses ([Why?](https://vercel.com/support/articles/how-to-allowlist-deployment-ip-address)), create Database user, and record the database connection string, please change the `` in the connection string to the database password 4. Sign up for a [Vercel](https://vercel.com/signup) account 5. Click the button below to deploy Twikoo to Vercel in one click [![Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/imaegoo/twikoo/tree/dev/src/vercel-min) 6. Go to Settings - Environment Variables, add the environment variable `MONGODB_URI`, the value is the database connection string in step 3 7. Go to Overview, click the link under Domains, if the environment configuration is correct, you can see the prompt "Twikoo cloud function is running normally" 8. Vercel Domains (with `https://` prefix, e.g. `https://xxx.vercel.app`) is your environment ID ## Configuration Please set `provider: "Twikoo"` and pass your server address to `envId` in the plugin options. For other configuration items, see [Twikoo Config](./config.md). --- --- url: /ecosystem/plugins/blog/comment/twikoo/config.md --- # Twikoo Options ## Config ### envId * Type: `string` * Required: Yes * Details: Vercel address or Tencent CloudBase environment ID. ## Plugin Config You can directly configure serializable options in the plugin options: ```ts title=".vuepress/config.ts" import { commentPlugin } from '@vuepress/plugin-comment' export default { plugins: [ commentPlugin({ provider: 'Twikoo', // other options // ... }), ], } ``` ## Client Config You can use the `defineTwikooConfig` function to customize Twikoo: ```ts title=".vuepress/client.ts" import { defineTwikooConfig } from '@vuepress/plugin-comment/client' import { defineClientConfig } from 'vuepress/client' defineTwikooConfig({ // Twikoo config }) ``` --- --- url: /ecosystem/plugins/blog/comment/waline/index.md --- # Waline A safe comment system with backend. ## Install ```bash npm i -D @waline/client ``` ## LeanCloud Settings (Database) 1. [Sign in](https://console.leancloud.app/login) or [sign up](https://console.leancloud.app/register) to LeanCloud and enter the [Console](https://console.leancloud.app/apps). 2. Click the [Create app](https://console.leancloud.app/apps) button to create a new app and enter a name you like: ![Create App](./assets/leancloud-app-1.jpg) 3. Enter the app, then select `Settings` > `App Keys` in the left bottom corner. You will see `APP ID`, `APP Key` and `Master Key` of your app. We will use them later. ![ID and Key](./assets/leancloud-app-2.jpg) ## Deploy to Vercel (Server) [![Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwalinejs%2Fwaline%2Ftree%2Fmain%2Fexample) 1. Click the button above to redirect to Vercel and deploy with the Waline template. ::: tip If you haven't logged in, we recommend you sign in with GitHub. ::: 2. Input your Vercel project name then click `Create`. ![skip team](/images/comment/vercel-2.png) 3. A repository named as your input will be created and initialized automatically based on the Waline example template by Vercel. ![deploy](/images/comment/vercel-3.png) After a minute or two, Vercel should finish the deployment. Click `Go to Dashboard` to redirect to your application dashboard. ![deploy](/images/comment/vercel-4.png) 4. Click `Settings` menu on the top, and `Environment Variables` button on the side to go to environment variables setting page. Then set `LEAN_ID`, `LEAN_KEY` and `LEAN_MASTER_KEY`. The variables' values should be the ones you got in the previous step. `APP ID` is the value of `LEAN_ID`, and `APP Key` to `LEAN_KEY`, `Master Key` to `LEAN_MASTER_KEY`. ![set environment variables](/images/comment/vercel-5.png) 5. To let your environment variables setting take effect, you need to redeploy your application. Click `Deployments` menu on the top and find the latest deployment at the top of list, click `Redeploy` button in the right dropdown menu. ![redeploy](/images/comment/vercel-6.png) 6. If everything is ok, Vercel will redirect to `Overview` page to start redeployment. Wait a moment and the `STATUS` will change to `Ready`. Now you can click `Visit` to visit the site. This link is your server address. ![redeploy success](/images/comment/vercel-7.png) ## Assign Domain (Optional) 1. Click `Settings` - `Domains` to go to domain setting page. 2. Input domain you want to assign and click `Add` button. ![Add domain](/images/comment/vercel-8.png) 3. Add a new `CNAME` record in your domain service server. | Type | Name | Value | | ----- | ------- | -------------------- | | CNAME | example | cname.vercel-dns.com | 4. You can use your own domain to visit the Waline comment system after it goes into effect. :tada: * serverURL: example.your-domain.com * admin panel: example.your-domain.com/ui ![success](/images/comment/vercel-9.png) ## Client ### Using plugin Set `provider: "Waline"` in the plugin options, and set `serverURL` as the link obtained in the previous step. Then, place the `` component at a suitable location in your site (usually at the bottom of the page), you will be able to see the comment box. ::: tip You can also pass in other options supported by Waline (except `el`). For details, see [Waline Config](config.md) ::: ## Comment Management (Management) 1. After the deployment is complete, please visit `/ui/register` to register. The first person to register will be set as an administrator. 2. After you log in as administrator, you can see the comment management interface. You can edit, mark or delete comments here. 3. Users can also register their account through comment box, and they will be redirected to their profile page after logging in. --- --- url: /ecosystem/plugins/blog/comment/waline/config.md --- # Waline Config ## Config ### serverURL * Type: `string` * Required: Yes * Details: Waline server address URL ### emoji * Type: `(string | WalineEmojiInfo)[] | false` ```ts type WalineEmojiPresets = `http://${string}` | `https://${string}` interface WalineEmojiInfo { /** * Emoji name show on tab */ name: string /** * Current folder link */ folder?: string /** * Common prefix of Emoji icons */ prefix?: string /** * Type of Emoji icons, will be regarded as file extension */ type?: string /** * Emoji icon show on tab */ icon: string /** * Emoji image list */ items: string[] } ``` * Default: `['//unpkg.com/@waline/emojis@1.1.0/weibo']` * Reference: * [Guide โ†’ Emoji](https://waline.js.org/en/guide/features/emoji.html) * Details: Emoji settings ### dark * Type: `string | boolean` * Default: `false` * Reference: * [Custom Style](https://waline.js.org/en/guide/features/style.html) * Details: Dark mode support. Setting a boolean will set the dark mode according to its value. Set it to `'auto'` will display darkmode due to device settings. Filling in a CSS selector will enable darkmode only when the selector match waline ancestor nodes. ### commentSorting * Type: `WalineCommentSorting` * Default: `'latest'` * Details: Comment list sorting method. Should be one of `'latest'`, `'oldest'`, or `'hottest'`. ### meta * Type: `string[]` * Default: `['nick', 'mail', 'link']` * Details: Reviewer attributes. Should be one of `'nick'`, `'mail'`, `'link'`. ### requiredMeta * Type: `string[]` * Default: `[]` * Details: Set required fields. Available values: * `[]` * `['nick']` * `['nick', 'mail']` ### login * Type: `string` * Default: `'enable'` * Details: Login mode status. Available values: * `'enable'`: Enable login (default) * `'disable'`: Login is disabled, users should fill in information to comment * `'force'`: Forced login, users must login to comment ### wordLimit * Type: `number | [number, number]` * Default: `0` * Details: Comment word limit. When a single number is filled in, it's the maximum number of comment words. No limit when set to `0`. ### pageSize * Type: `number` * Default: `10` * Details: Number of comments per page. ### imageUploader * Type: `WalineImageUploader | false` ```ts type WalineImageUploader = (image: File) => Promise ``` * Reference: * [Cookbook โ†’ Upload Image](https://waline.js.org/en/cookbook/customize/upload-image.html) * Details: Custom image upload method. The default behavior is to embed images Base 64 encoded, you can set this to `false` to disable image uploading. The function should receive an image object and return a Promise that provides the image address. ### highlighter * Type: `WalineHighlighter | false` ```ts type WalineHighlighter = (code: string, lang: string) => string ``` * Reference: * [Cookbook โ†’ Customize Highlighter](https://waline.js.org/en/cookbook/customize/highlighter.html) * Details: **Code highlighting** uses `hanabi` by default. The function passes in original content of code block and language of the code block. You should return a string directly. You can pass in a code highlighter of your own, or set to `false` to disable code highlighting. ### texRenderer * Type: `WalineTexRenderer | false` ```ts type WalineTexRenderer = (blockMode: boolean, tex: string) => string ``` * Reference: * [Cookbook โ†’ Customize TeX Renderer](https://waline.js.org/en/cookbook/customize/tex-renderer.html) * [MathJax](https://www.mathjax.org/) * [KaTeX](https://katex.org/) * Details: Customize TeX rendering. The default behavior is to prompt that the preview mode does not support TeX. The function provides two parameters: the first parameter indicates whether it should be rendered in block level, and the second parameter is the string of the TeX content. Return an HTML string as render result. You can import TeX renderer to provide preview feature. We recommend you use KaTeX or MathJax, or set to `false` to disable parsing TeX. ### search * Type: `WalineSearchOptions | false` ```ts interface WalineSearchImageData extends Record { /** * Image link */ src: string /** * Image title * * @description Used for alt attribute of image */ title?: string /** * Image preview link * * @description For better loading performance, we will use this thumbnail first in the list * * @default src */ preview?: string } type WalineSearchResult = WalineSearchImageData[] interface WalineSearchOptions { /** * Search action */ search: (word: string) => Promise /** * Default result when opening list * * @default () => search('') */ default?: () => Promise /** * Fetch more action * * @description It will be triggered when the list scrolls to the bottom. If your search service supports paging, you should set this to achieve infinite scrolling * * @default (word) => search(word) */ more?: (word: string, currentCount: number) => Promise } ``` * Details: Customize search features. You can disable search function by setting it to `false`. ### recaptchaV3Key * Type: `string` * Details: reCAPTCHA V3 is a captcha service provided by Google. You can add reCAPTCHA V3 site key with `recaptchaV3Key` to enable it. You should also set environment variable `RECAPTCHA_V3_SECRET` for server. ### reaction * Type: `boolean | string[]` * Default: `false` * Details: Add emoji interaction function to the article. Set it to `true` to provide the default emoji, you can also customize the emoji image by setting the emoji URL array, and supports a maximum of 8 emojis. ### metaIcon * Type: `boolean` * Default: `true` * Details: Whether to import meta icon. ### locales * Type: `WalineLocales` ```ts interface WalineLocales { [localePath: string]: Partial } ``` * Reference: * [Waline Locales](https://waline.js.org/en/cookbook/customize/locale.html) * Details: Waline locales. ## Plugin Config You can directly configure serializable options in the plugin options: ```ts title=".vuepress/config.ts" import { commentPlugin } from '@vuepress/plugin-comment' export default { plugins: [ commentPlugin({ provider: 'Waline', // other options // ... }), ], } ``` ## Client Config You can use the `defineWalineConfig` function to customize Waline: ```ts title=".vuepress/client.ts" import { defineWalineConfig } from '@vuepress/plugin-comment/client' import { defineClientConfig } from 'vuepress/client' defineWalineConfig({ // Waline config }) ``` --- --- url: /ecosystem/plugins/blog/feed/index.md --- # feed ## Usage ```bash npm i -D @vuepress/plugin-feed@next ``` ```ts title=".vuepress/config.ts" import { feedPlugin } from '@vuepress/plugin-feed' export default { plugins: [ feedPlugin({ // options }), ], } ``` --- --- url: /ecosystem/plugins/blog/feed/channel.md --- # Channel Config The channel plugin option is used to config the feed channel. ## channel.title * Type: `string` * Default: `SiteConfig.title` Channel title ## channel.link * Type: `string` * Default: Deployment link (generated by `options.hostname` and `context.base`) Channel address ## channel.description * Type: `string` * Default: `SiteConfig.description` Channel description ## channel.language * Type: `string` * Default: * `siteConfig.locales['/'].lang` * If the above is not provided, fall back to `"en-US"` The language of the channel ## channel.copyright * Type: `string` * Default: * Try to read the `author.name` in channel options, and fall back to `Copyright by $author` * Recommended to set manually: **Yes** Channel copyright information ## channel.pubDate * Type: `string` (must be a valid Date ISOString) * Default: time when the plugin is called each time * Recommended to set manually: **Yes** Publish date of the Channel ## channel.lastUpdated * Type: `string` (must be a valid Date ISOString) * Default: time when the plugin is called each time Last update time of channel content ## channel.ttl * Type: `number` * Recommended to set manually: **Yes** The effective time of the content. It's the time to keep the cache after request without making new requests. ## channel.image * Type: `string` * Recommended to set manually: **Yes** A picture presenting the channel. A square picture with a size not smaller than 512ร—512 is recommended. ## channel.icon * Type: `string` * Recommended to set manually: **Yes** An icon representing a channel, a square picture, with not less than 128ร—128 in size. Transparent background color is recommended. ## channel.author * Type: `FeedAuthor` * Recommended to set manually: **Yes** The author of the channel. ::: details FeedAuthor format ```ts interface FeedAuthor { /** Author name */ name: string /** Author's email */ email?: string /** Author's site */ url?: string /** * Author's avatar address * * Square, preferably not less than 128ร—128 with transparent background */ avatar?: string } ``` ## channel.hub * Type: `string` Link to Websub. Websub requires a server backend, which is inconsistent with VuePress, so ignore it if there is no special need. ::: tip WebSub For details, see [Websub](https://w3c.github.io/websub/#subscription-migration). ::: --- --- url: /ecosystem/plugins/blog/feed/config.md --- # Plugin Config ## hostname * Type: `string` * Required: Yes The domain name of the deployment site. ## atom * Type: `boolean` * Default: `false` Whether to output Atom syntax files. ## json * Type: `boolean` * Default: `false` Whether to output JSON syntax files. ## rss * Type: `boolean` * Default: `false` Whether to output RSS syntax files. ## image * Type: `string` A large image/icon of the feed, probably used as banner. ## icon * Type: `string` A small icon of the feed, probably used as favicon. ## count * Type: `number` * Default: `100` Set the maximum number of items in the feed. After all pages are sorted, the first `count` items will be intercepted. If your site has a lot of articles, you may consider this option to reduce feed file size. ## preservedElements * Type: `(RegExp | string)[] | (tagName: string) => boolean` Custom element or component which should be preserved in feed. ::: tip By default, all unknown tags will be removed. ::: ## filter * Type: `(page: Page)=> boolean` * Default: ```js ;({ frontmatter, filePathRelative }) => Boolean(frontmatter.feed ?? (filePathRelative && !frontmatter.home)) ``` A custom filter function, used to filter feed items. ## sorter * Type: `(pageA: Page, pageB: Page)=> number` * Default: ```ts // dateSorter is from @vuepress/helper ;(pageA: Page, pageB: Page): number => dateSorter( pageA.data.git?.createdTime ? new Date(pageA.data.git?.createdTime) : pageA.frontmatter.date, pageB.data.git?.createdTime ? new Date(pageB.data.git?.createdTime) : pageB.frontmatter.date, ) ``` Custom sorter function for feed items. The default sorting behavior is by file adding time coming from git (needs `@vuepress/plugin-git`). ::: tip You should enable `@vuepress/plugin-git` to get the newest created pages as feed items. Otherwise, the feed items will be sorted by the default order of pages in VuePress. ::: ## channel `channel` option is used to config *Feed Channels*. For available options, please see [Config โ†’ Channel](channel.md) ## devServer * Type: `boolean` * Default: `false` Whether enabled in devServer. ::: tip For performance reasons, we do not provide hot reload. Reboot your devServer to sync your changes. ::: ## devHostname * Type: `string` * Default: `"http://localhost:${port}"` Hostname to use in devServer ## atomOutputFilename * Type: `string` * Default: `"atom.xml"` Atom syntax output filename, relative to dest folder. ## atomXslTemplate * Type: `string` * Default: Content of `@vuepress/plugin-feed/templates/atom.xsl` Atom xsl template file content. ## atomXslFilename * Type: `string` * Default: `"atom.xsl"` Atom xsl filename, relative to dest folder. ## jsonOutputFilename * Type: `string` * Default: `"feed.json"` JSON syntax output filename, relative to dest folder. ## rssOutputFilename * Type: `string` * Default: `"rss.xml"` RSS syntax output filename, relative to dest folder. ## rssXslTemplate * Type: `string` * Default: Content of `@vuepress/plugin-feed/templates/rss.xsl` RSS xsl template file content. ## rssXslFilename * Type: `string` * Default: `"rss.xsl"` RSS syntax xsl filename, relative to dest folder. ## getter Feed generation controller, see [Feed Getter](./getter.md). ::: tip The plugin has a built-in getter, only set this if you want full control of feed generation. ::: ## locales * Type: `Record` You can use it to specific options for each locale. Any options above are supported except `hostname`. --- --- url: /ecosystem/plugins/blog/feed/frontmatter.md --- # Frontmatter Config You can control each feed item generation by setting page frontmatter. ## Additions and Removals By default, all articles are added to the feed stream. Set `feed: false` in frontmatter to remove a page from feed. ## Frontmatter Information ### title * Type: `string` Automatically generated by VuePress, defaults to the h1 content of the page ### description * Type: `string` Description of the page ### date * Type: `Date` Date when the page was published ### article * Type: `boolean` Whether the page is an article > If this is set to `false`, the page will not be included in the final feed. ### copyright * Type: `string` Page copyright information ### cover / image / banner * Type: `string` Image used as page cover , should be full link or absolute link. ## Frontmatter Options ### feed.title * Type: `string` The title of the feed item ### feed.description * Type: `string` Description of the feed item ### feed.content * Type: `string` The content of the feed item ### feed.author * Type: `FeedAuthor[] | FeedAuthor` The author of the feed item ::: details FeedAuthor format ```ts interface FeedAuthor { /** * Author name */ name?: string /** * Author email */ email?: string /** * Author site * * @description json format only */ url?: string /** * Author avatar * * @description json format only */ avatar?: string } ``` ::: ### feed.contributor * Type: `FeedContributor[] | FeedContributor` Contributors to feed item ::: details FeedContributor format ```ts interface FeedContributor { /** * Author name */ name?: string /** * Author email */ email?: string /** * Author site * * @description json format only */ url?: string /** * Author avatar * * @description json format only */ avatar?: string } ``` ::: ### feed.guid * Type: `string` The identifier of feed item, used to identify the feed item. ::: tip You should ensure every feed has a unique guid. ::: --- --- url: /ecosystem/plugins/blog/feed/getter.md --- # Feed Getter You can take full control of feed items generation by setting `getter` in the plugin options. ## getter.title * Type: `(page: Page, app: App) => string` Item title getter ## getter.link * Type: `(page: Page, app: App) => string` Item link getter ## getter.description * Type: `(page: Page, app: App) => string | undefined` Item description getter ::: tip Due to Atom supporting HTML in summary, you can return HTML content here if possible, but the content must start with the mark `html:`. ::: ## getter.content * Type: `(page: Page, app: App) => string` Item content getter ## getter.author * Type: `(page: Page, app: App) => FeedAuthor[]` Item author getter. ::: tip The getter should return an empty array when author information is missing. ::: ::: details FeedAuthor format ```ts interface FeedAuthor { /** * Author name */ name?: string /** * Author email */ email?: string /** * Author site * * @description json format only */ url?: string /** * Author avatar * * @description json format only */ avatar?: string } ``` ::: ## getter.category * Type: `(page: Page, app: App) => FeedCategory[] | undefined` Item category getter. ::: details FeedCategory format ```ts interface FeedCategory { /** * Category Name */ name: string /** * A string that identifies a categorization taxonomy * * @description rss format only */ domain?: string /** * the categorization scheme via a URI * * @description atom format only */ scheme?: string } ``` ::: ## getter.enclosure * Type: `(page: Page, app: App) => FeedEnclosure | undefined` Item enclosure getter. ::: details FeedEnclosure format ```ts interface FeedEnclosure { /** * Enclosure link */ url: string /** * what its type is * * @description should be a standard MIME Type, rss format only */ type: string /** * Size in bytes * * @description rss format only */ length?: number } ``` ::: ## getter.publishDate * Type: `(page: Page, app: App) => Date | undefined` Item release date getter ## getter.lastUpdateDate * Type: `(page: Page, app: App) => Date` Item last update date getter ## getter.image * Type: `(page: Page, app: App) => string` Item image getter ::: tip Ensure it's returning a full URL ::: ## getter.contributor * Type: `(page: Page, app: App) => FeedContributor[]` Item contributor getter ::: tip The getter should return an empty array when contributor information is missing. ::: ::: details FeedContributor format ```ts interface FeedContributor { /** * Author name */ name?: string /** * Author email */ email?: string /** * Author site * * @description json format only */ url?: string /** * Author avatar * * @description json format only */ avatar?: string } ``` ::: ## getter.copyright * Type: `(page: Page, app: App) => string | undefined` Item copyright getter --- --- url: /ecosystem/plugins/blog/feed/guide.md --- # Guide ## Usage The plugin can generate feed files in the following three formats for you: * Atom 1.0 * JSON 1.1 * RSS 2.0 Please set `atom`, `json` or `rss` to `true` in the plugin options according to the formats you want to generate. To correctly generate feed links, you need to set `hostname` in the plugin options. ## Readable Preview When you open the feed file in a browser, we magically convert atom and rss feed xml to human readable html via xsl template. Check [atom](/atom.xml) and [rss](/rss.xml) feed of this site as an example! If you want to preview your feed in devServer, set `devServer: true` in plugin options. You may also need to set `devHostname` if you are not using the default `http://localhost:{port}`. ## Channel settings You can customize the feed channel information by setting the `channel` option. We recommend the following settings: * Convert the date of creating the feed to ISOString and write it into `channel.pubDate` * The update period of the content set in `channel.ttl` (unit: minutes) * Set copyright information via `channel.copyright` * Set the channel author via `channel.author`. For detailed options and their default values, see [Channel Config](./channel.md) ## Feed Generation By default, all articles are added to the feed stream. You can set `feed` and other options in page frontmatter to control contents of feed item. See [Frontmatter Config](./frontmatter.md) for how they are converted. You can take full control of feed items generation by configuring the `getter` in the plugin options. For detailed options and their default values, see [Configuration โ†’ Feed Getter](./getter.md). ### I18n Config The plugin generates separate feeds for each language. You can provide different settings for different languages via `locales` in the plugin options. --- --- url: /ecosystem/plugins/development/index.md --- # Development Plugins --- --- url: /ecosystem/plugins/development/active-header-links.md --- # active-header-links This plugin will listen to page scroll event. When the page scrolls to a certain *header anchor*, this plugin will change the route hash to that *header anchor* if there is a corresponding *header link*. This plugin is mainly used to develop themes, and has been integrated into the default theme. You won't need to use it directly in most cases. ## Usage ```bash npm i -D @vuepress/plugin-active-header-links@next ``` ```ts title=".vuepress/config.ts" import { activeHeaderLinksPlugin } from '@vuepress/plugin-active-header-links' export default { plugins: [ activeHeaderLinksPlugin({ // options }), ], } ``` ## Options ### headerLinkSelector * Type: `string` * Default: `'a.vp-sidebar-item'` * Details: Selector of *header link*. If a *header anchor* does not have a corresponding *header link*, this plugin won't change the route hash to that anchor when scrolling to it. ### headerAnchorSelector * Type: `string` * Default: `'.header-anchor'` * Details: Selector of *header anchor*. You don't need to specify this option unless you have changed the `permalinkClass` option of [markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor#readme) via [markdown.anchor](https://vuejs.press/reference/config.html#markdown-anchor). * Also see: * [Guide > Markdown > Syntax Extensions > Header Anchors](https://vuejs.press/guide/markdown.html#header-anchors) ### delay * Type: `number` * Default: `200` * Details: The delay of the debounced scroll event listener. ### offset * Type: `number` * Default: `5` * Details: Even if you click the link of the *header anchor* directly, the `scrollTop` might not be exactly equal to `offsetTop` of the *header anchor*, so we add an offset to avoid the error. --- --- url: /ecosystem/plugins/development/git.md --- # git This plugin will collect git information of your pages, including the created and updated time, the contributors, the changelog, etc. The [lastUpdated](../../themes/default/config.md#lastupdated) and [contributors](../../themes/default/config.md#contributors) of default theme is powered by this plugin. This plugin is mainly used to develop themes. You won't need to use it directly in most cases. ## Usage ```bash npm i -D @vuepress/plugin-git@next ``` ```ts title=".vuepress/config.ts" import { gitPlugin } from '@vuepress/plugin-git' export default { plugins: [ gitPlugin({ // options }), ], } ``` ## Git Repository This plugin requires your project to be inside a [Git Repository](https://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository), so that it can collect information from the commit history. You should ensure all commits are available when building your site. For example, CI workflows usually clone your repository with [--depth 1](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt) to avoid fetching all commits, so you should disable the behavior to make this plugin work properly in CI. ::: warning This plugin will significantly slow down the speed of data preparation, especially when you have a lot of pages. You can consider disabling this plugin in `dev` mode to get better development experience. ::: ## Options ### createdTime * Type: `boolean` * Default: `true` * Details: Whether to collect page created time or not. ### updatedTime * Type: `boolean` * Default: `true` * Details: Whether to collect page updated time or not. ### contributors * Type: `boolean | ContributorsOptions` ```ts interface ContributorInfo { /** * Contributor's username on the git hosting service */ username: string /** * Contributor name displayed on the page, default is `username` */ name?: string /** * The alias of the contributor, * Since contributors may have different usernames saved in their local git configuration * compared to their usernames on the hosting service, In this case, aliases can be used to * map to the actual usernames. */ alias?: string[] | string /** * The primary email of the contributor */ email?: string /** * The alternative emails of the contributor on the Git hosting service, * or emails they have used in the past. */ emailAlias?: string[] | string /** * The avatar url of the contributor. * * If the git hosting service is `github`, it can be ignored and left blank, * as the plugin will automatically fill it in. */ avatar?: string /** * The url of the contributor * * If the git hosting service is `github`, it can be ignored and left blank, * as the plugin will automatically fill it in. */ url?: string } interface ContributorsOptions { /** * Contributor information */ info?: ContributorInfo[] /** * Whether to add avatar in contributor information * @default false */ avatar?: boolean /** * Avatar url pattern * - `:username` - Contributor's username * * @example 'https://github.com/:username' */ avatarPattern?: string /** * Functions to transform contributors, e.g. remove duplicates ones and sort them. * The input is the contributors collected by this plugin, and the output should be the transformed contributors. */ transform?: (contributors: GitContributorInfo[]) => GitContributorInfo[] } ``` * Default: `true` * Details: Whether to collect page contributors or not. ### changelog * Type: `boolean | ChangelogOptions` ```ts interface ChangelogOptions { /** * Maximum number of changelog */ maxCount?: number /** * The url of the git repository, e.g: https://github.com/vuepress/ecosystem */ repoUrl?: string /** * Commit url pattern * * - `:repo` - The url of the git repository * - `:hash` - Hash of the commit record * * @default ':repo/commit/:hash' */ commitUrlPattern?: string /** * Issue url pattern * * - `:repo` - The url of the git repository * - `:issue` - Id of the issue * * @default ':repo/issues/:issue' */ issueUrlPattern?: string /** * Tag url pattern * * - `:repo` - The url of the git repository * - `:tag` - Name of the tag * * @default ':repo/releases/tag/:tag' */ tagUrlPattern?: string } ``` * Default: `false` * Details: Whether to collect page changelog or not. ### filter * Type: `(page: Page) => boolean` * Details: Page filter, if it returns `true`, the page will collect git information. ### locales * Type: `Record` ```ts export interface GitLocaleData { /** * Contributors title */ contributors: string /** * Changelog title */ changelog: string /** * Word to represent a commit "on" a time */ timeOn: string /** * Changelog button */ viewChangelog: string /** * Latest updated */ latestUpdateAt: string } ``` * Details: Locales configuration, used in the [Git Component](#component). ## Frontmatter ### gitInclude * Type: `string[]` * Details: An array of relative paths to be included when calculating page data. * Example: ```md --- gitInclude: - relative/path/to/file1 - relative/path/to/file2 --- ``` ### contributors * Type: `boolean | string[]` * Details: Whether to collect contributor information for the current page, this value will override the [contributors](#contributors) configuration item. * `true` - Collect contributor information * `false` - Do not collect contributor information * `string[]` - List of additional contributors, sometimes there are additional contributors on the page, and this configuration item can be used to specify the list of additional contributors to obtain contributor information ### changelog * Type: `boolean` * Details: Whether to collect the change history for the current page, this value will override the [changelog](#changelog) configuration item. ## Composables You can import the following composables from `@vuepress/plugin-git/client`. ### useChangelog Get the changelog of the current page. ```ts export interface CoAuthorInfo { /** * Co-author name */ name: string /** * Co-author email */ email: string } export interface GitChangelogItem extends GitChangelogInfo { /** * Commit hash */ hash: string /** * Unix timestamp in milliseconds */ time: number /** * Commit message */ message: string /** * The url of the commit */ commitUrl?: string /** * release tag */ tag?: string /** * The url of the release tag */ tagUrl?: string /** * Commit author name */ author: string /** * Commit author email */ email: string /** * The co-authors of the commit */ coAuthors?: CoAuthorInfo[] /** * Date text of the commit */ date: string } export const useChangelog: ( enabled?: MaybeRefOrGetter, ) => ComputedRef ``` ### useContributors Get the contributors of the current page. ```ts export interface GitContributorInfo { /** * Contributor display name */ name: string /** * Contributor email */ email: string /** * Contributor username on the git hosting service */ username: string /** * Number of commits */ commits: number /** * Contributor avatar */ avatar?: string /** * The url of the contributor */ url?: string } export const useContributors: ( enabled?: MaybeRefOrGetter, ) => ComputedRef ``` ### useLastUpdated Get the last updated time of the current page. ```ts export interface LastUpdated { /** * The date object of the last updated time */ date: Date /** * The ISO string of the last updated time */ iso: string /** * The formatted text of the last updated time */ text: string /** * The locale of the last updated time */ locale: string } export const useLastUpdated: ( enabled?: MaybeRefOrGetter, ) => ComputedRef ``` ## Page Data This plugin will add a `git` field to page data. After using this plugin, you can get the collected git information in page data: ```ts import type { GitPluginPageData } from '@vuepress/plugin-git' import { usePage } from 'vuepress/client' export default { setup(): void { const page = usePage() console.log(page.value.git) }, } ``` ### git.createdTime * Type: `number` * Details: Unix timestamp in milliseconds of the first commit of the page. This attribute would take the minimum of the first commit timestamps of the current page and the files listed in [gitInclude](#gitinclude). ### git.updatedTime * Type: `number` * Details: Unix timestamp in milliseconds of the last commit of the page. This attribute would take the maximum of the last commit timestamps of the current page and the files listed in [gitInclude](#gitinclude). ### git.contributors * Type: `GitContributorInfo[]` ```ts interface GitContributorInfo { // display name name: string email: string // username on the git hosting service username: string commits: number avatar?: string url?: string } ``` * Details: The contributors information of the page. This attribute would also include contributors to the files listed in [gitInclude](#gitinclude). ### git.changelog * Type: `GitChangelogInfo[]` ```ts interface CoAuthorInfo { /** * Co-author name */ name: string /** * Co-author email */ email: string } interface GitChangelogInfo { /** * Commit hash */ hash: string /** * Unix timestamp in milliseconds */ time: number /** * Commit message */ message: string /** * The url of the commit */ commitUrl?: string /** * release tag */ tag?: string /** * The url of the release tag */ tagUrl?: string /** * Commit author name */ author: string /** * Commit author email */ email: string /** * The co-authors of the commit */ coAuthors?: CoAuthorInfo[] } ``` * Details: The changelog of the page. This attribute would also include contributors to the files listed in [gitInclude](#gitinclude). ## Git Component{#component} The plugin provides global components related to Git information, which can be used in themes. ### GitContributors List the contributor information for the current page. ```vue{4} ``` **Effect Preview:** ### GitChangelog List the changelog of the current page. ```vue{4} ``` **Effect Preview:** --- --- url: /ecosystem/plugins/development/palette.md --- # palette Provide palette support for your theme. This plugin is primarily designed for theme development and has been integrated into the default theme. You typically won't need to use it directly in most cases. For theme authors, this plugin provides users with the ability to customize styles. ## Usage ```bash npm i -D @vuepress/plugin-palette@next ``` ```ts title=".vuepress/config.ts" import { palettePlugin } from '@vuepress/plugin-palette' export default { plugins: [ palettePlugin({ // options }), ], } ``` ## Palette and Style This plugin provides a `@vuepress/plugin-palette/palette` (palette file) and a `@vuepress/plugin-palette/style` (style file) for import in your theme styles. The palette file is used to define style variables, so it's typically imported at the beginning of your theme styles. For example, users can define [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties), [SASS variables](https://sass-lang.com/documentation/variables), [LESS variables](http://lesscss.org/features/#variables-feature), or [Stylus variables](https://stylus-lang.com/docs/variables.html) in the palette, and then you can use those variables in your theme styles. The style file is used to override default styles or add extra styles, so it's typically imported at the end of your theme styles. ## Usage Use this plugin in your theme, assuming you're using SASS: ```ts import { palettePlugin } from '@vuepress/plugin-palette' export default { // ... plugins: [ palettePlugin({ preset: 'sass' }), // ... ], } ``` ### Usage of Palette Import the plugin's palette file wherever your theme needs to use the corresponding variables, such as in the `Layout.vue` file: ```vue ``` Then users can customize variables in `.vuepress/styles/palette.scss`: ```scss $color: green; ``` ### Usage of Style Import the plugin's style file after your theme's styles, for example, in the `clientConfigFile`: ```ts // import your theme's style file import 'path/to/your/theme/style' // import the plugin's style file import '@vuepress/plugin-palette/style' ``` Then users can add extra styles in `.vuepress/styles/index.scss` and override your theme's default styles: ```scss h1 { font-size: 2.5rem; } ``` ## Options ### preset * Type: `'css' | 'less' | 'sass' | 'stylus'` * Default: `'css'` * Details: Set preset for other options. If you don't need advanced customization of the plugin, it's recommended to set only this option and omit others. ### userPaletteFile * Type: `string` * Default: * css: `'.vuepress/styles/palette.css'` * less: `'.vuepress/styles/palette.less'` * sass: `'.vuepress/styles/palette.scss'` * stylus: `'.vuepress/styles/palette.styl'` * Details: File path of the user palette file, relative to source directory. The default value depends on the [preset](#preset) option. This file is where users define style variables, and it's recommended to keep the default file path as a convention. ### tempPaletteFile * Type: `string` * Default: * css: `'styles/palette.css'` * less: `'styles/palette.less'` * sass: `'styles/palette.scss'` * stylus: `'styles/palette.styl'` * Details: File path of the generated palette temp file, relative to temp directory. The default value depends on the [preset](#preset) option. You should import the palette file via `'@vuepress/plugin-palette/palette'` alias, so you don't need to change this option in most cases. ### userStyleFile * Type: `string` * Default: * css: `'.vuepress/styles/index.css'` * less: `'.vuepress/styles/index.less'` * sass: `'.vuepress/styles/index.scss'` * stylus: `'.vuepress/styles/index.styl'` * Details: File path of the user style file, relative to source directory. The default value depends on the [preset](#preset) option. This file is where users override default styles or add extra styles, and it's recommended to keep the default file path as a convention. ### tempStyleFile * Type: `string` * Default: * css: `'styles/index.css'` * less: `'styles/index.less'` * sass: `'styles/index.scss'` * stylus: `'styles/index.styl'` * Details: File path of the generated style temp file, relative to temp directory. The default value depends on the [preset](#preset) option. You should import the style file via `'@vuepress/plugin-palette/style'` alias, so you don't need to change this option in most cases. ### importCode * Type: `(filePath: string) => string` * Default: * css: `` (filePath) => `@import '${filePath}';\n` `` * less: `` (filePath) => `@import '${filePath}';\n` `` * sass: `` (filePath) => `@forward 'file:///${filePath}';\n` `` * stylus: `` (filePath) => `@require '${filePath}';\n` `` * Details: Function to generate import code. The default value depends on the [preset](#preset) option. This option is used for generating [tempPaletteFile](#temppalettefile) and [tempStyleFile](#tempstylefile), and you don't need to change this option in most cases. --- --- url: /ecosystem/plugins/development/reading-time.md --- # reading-time This plugin generates word count and estimated reading time for each page. ## Usage ```bash npm i -D @vuepress/plugin-reading-time@next ``` ```ts title=".vuepress/config.ts" import { readingTimePlugin } from '@vuepress/plugin-reading-time' export default { plugins: [ readingTimePlugin({ // options }), ], } ``` The plugin injects reading time information into the `readingTime` field of page data: * `readingTime.minutes`: estimated reading time in minutes (`number`) * `readingTime.words`: word count (`number`) ### Getting Data on Node Side For any page, you can get estimated reading time and word count from `page.data.readingTime`: ```ts page.data.readingTime // { minutes: 3.2, words: 934 } ``` You can access it for further processing in the `extendsPage` lifecycle and other lifecycles: ```js export default { // ... extendsPage: (page) => { page.data.readingTime // { minutes: 3.2, words: 934 } }, onInitialized: (app) => { app.pages.forEach((page) => { page.data.readingTime // { minutes: 3.2, words: 934 } }) }, } ``` ### Getting Data on Client Side You can import `useReadingTimeData` and `useReadingTimeLocale` from `@vuepress/plugin-reading-time/client` to get the reading time data and locale data of the current page: ```vue ``` ## Options ### wordPerMinute * Type: `number` * Default: `300` * Details: Reading speed in words per minute. ### locales * Type: `ReadingTimePluginLocaleConfig` ```ts interface ReadingTimePluginLocaleData { /** * Word template, `$word` will be automatically replaced by actual words */ word: string /** * Text for less than one minute */ less1Minute: string /** * Time template, `$time` will be automatically replaced by actual time */ time: string } interface ReadingTimePluginLocaleConfig { [localePath: string]: Partial } ``` * Details: Locale config for reading time text and word count text. ::: details Built-in Supported Languages * **Simplified Chinese** (zh-CN) * **Traditional Chinese** (zh-TW) * **English (United States)** (en-US) * **German** (de-DE) * **Russian** (ru-RU) * **Ukrainian** (uk-UA) * **Vietnamese** (vi-VN) * **Portuguese (Brazil)** (pt-BR) * **Polish** (pl-PL) * **French** (fr-FR) * **Spanish** (es-ES) * **Slovak** (sk-SK) * **Japanese** (ja-JP) * **Turkish** (tr-TR) * **Korean** (ko-KR) * **Finnish** (fi-FI) * **Indonesian** (id-ID) * **Dutch** (nl-NL) ::: ## Client API You can import and use these APIs from `@vuepress/plugin-reading-time/client`: ::: tip These APIs won't throw errors even if you disable the plugin. ::: ### useReadingTimeData ```ts interface ReadingTime { /** Expected reading time in minutes */ minutes: number /** Words count of content */ words: number } const useReadingTimeData: () => ComputedRef ``` Returns `null` when the plugin is disabled. ### useReadingTimeLocale ```ts interface ReadingTimeLocale { /** Expected reading time text in locale */ time: string /** Word count text in locale */ words: string } const useReadingTimeLocale: () => ComputedRef ``` ## Advanced Usage This plugin targets plugin and theme developers, so we provide a "Use API": ```js title="your plugin or theme entry" import { useReadingTimePlugin } from '@vuepress/plugin-reading-time' export default (options) => (app) => { useReadingTimePlugin(app, { // your options }) return { name: 'vuepress-plugin-xxx', // or vuepress-theme-xxx } } ``` ::: tip Why you should use the "Use API" 1. When you register a plugin multiple times, VuePress gives you a warning that only the first one takes effect. The `useReadingTimePlugin` automatically detects if the plugin is registered and avoids registering multiple times. 2. If you access reading time data in the `extendsPage` lifecycle, then `@vuepress/plugin-reading-time` must be called before your theme or plugin, otherwise you will get `undefined` for `page.data.readingTime`. The `useReadingTimePlugin` ensures that `@vuepress/plugin-reading-time` is called before your theme or plugin. ::: We also provide a `removeReadingTimePlugin` API to remove the plugin. You can use this to ensure your call takes effect or clear the plugin: ```js title="your plugin or theme entry" import { useReadingTimePlugin } from '@vuepress/plugin-reading-time' export default (options) => (app) => { // this removes any existing reading time plugin at this time removeReadingTimePlugin(app) // so this will take effect even if there is a reading time plugin registered before useReadingTimePlugin(app, { // your options }) return { name: 'vuepress-plugin-xxx', // or vuepress-theme-xxx } } ``` --- --- url: /ecosystem/plugins/development/rtl.md --- # RTL This plugin sets text direction to RTL on configured locales. ## Usage ```bash npm i -D @vuepress/plugin-rtl@next ``` ```ts title=".vuepress/config.ts" import { rtlPlugin } from '@vuepress/plugin-rtl' export default { plugins: [ rtlPlugin({ // options locales: ['/ar/'], }), ], } ``` ## Demo ## Options ### locales * Type: `string[]` * Default: `['/']` * Details: RTL locale paths to enable RTL layout. ### selector * Type: `SelectorOptions` ```ts interface SelectorOptions { [cssSelector: string]: { [attr: string]: string } } ``` * Default: `{ 'html': { dir: 'rtl' } }` * Details: Selector configuration to enable RTL layout. The default settings mean that the `dir` attribute of the `html` element will be set to `rtl` in RTL locales. --- --- url: /ecosystem/plugins/development/sass-palette/index.md --- # sass-palette This plugin is mainly facing plugin and theme developers, it is more powerful than [`@vuepress/plugin-palette`](../palette.md). ::: tip You should manually install these deps in your project: * When using Vite bundler: `sass-embedded` * When using Webpack bundler: `sass-embedded` and `sass-loader` ::: ## Usage You must invoke `useSassPalettePlugin` function during plugin initialization to use this plugin. ```bash npm i -D @vuepress/plugin-sass-palette@next ``` ```js title="Your plugin or theme entry" import { useSassPalettePlugin } from '@vuepress/plugin-sass-palette' export const yourPlugin = (options) => (app) => { useSassPalettePlugin(app, { // plugin options }) return { // your plugin api } } ``` --- --- url: /ecosystem/plugins/development/sass-palette/config.md --- # Config ## Options ### id * Type: `string` * Required: Yes Identifier for palette, used to avoid duplicate registration. ### config * Type: `string` * Default: `` `.vuepress/styles/${id}-config.scss` `` User config file path, relative to source dir. ::: tip This is the file where users set style variables. The default filename starts with ID above. ::: ### defaultConfig * Type: `string` * Default: `"@vuepress/plugin-sass-palette/styles/default/config.scss"` Default config file path, should be absolute path. ::: tip This is the file you should use to provide default values with `!default`. ::: ### palette * Type: `string` * Default: `` `.vuepress/styles/${id}-palette.scss` `` User palette file path, relative to source dir. ::: tip This is the file where users control injected CSS variables. All the variables will be converted to kebab-case and injected. The default filename starts with ID above. ::: ### defaultPalette * Type: `string` Default palette file path, should be absolute path. ::: tip This is the file you should use to provide default CSS variables with `!default`. All the variables will be converted to kebab-case and injected. ::: ### generator * Type: `string` Custom generator used to generate derivative values with palette config. For example: You may want to provide a `$theme-color-light` based on `$theme-color`. ### style * Type: `string` User style file path, relative to source dir. ## Alias Available aliases are: * config: `@sass-palette/${id}-config` (based on `id`) * palette: `@sass-palette/${id}-palette` (based on `id`) * style: `@sass-palette/${id}-style` (only available when `style` option is set) * helper: `@sass-palette/helper` --- --- url: /ecosystem/plugins/development/sass-palette/guide.md --- # Guide Comparing to [`@vuepress/plugin-palette`](../palette.md), this plugin allows you to: * Derive related styles based on user configuration * Provide style customization similar to themes in plugins * Group applications across multiple plugins or themes via id option Before using the plugin, you need to understand the id option, as well as three styling concepts: configuration, palette and generator. ## ID Option To get started, you should understand that this plugin is designed to work across plugins and themes (unlike the official one only for themes). We are providing `id` option to do that, and using this plugin (by calling `useSassPalette`) with same ID won't have any side effects. Also, all the aliases and module names have an ID prefix. This will allow you to: * Share the same style system across your plugins (or themes) using the same ID without any side effects. All aliases and module names have an ID prefix, which means you can use a set of style variables within your plugins (or theme) to unify your styles without being affected by other plugins (or themes). Users can configure all color variables, breakpoints, and other style configurations in the same file and have them automatically applied to themes and plugins with the same ID. ::: tip Example `vuepress-theme-hope` and other related plugins use the same ID `hope` to call the plugin, so the styles configured by the user in the theme will automatically take effect in all plugins. ::: * With different ID, plugins and theme won't affect others. We recommend you to set the `id` variable with your plugin name. With the default settings, users will set your plugin style under `.vuepress/styles` directory with Sass files starting with your ID prefix. And you can access the variables you need with `${id}-config` and `${id}-palette`. ::: tip Example `vuepress-theme-hope` is using ID `"hope"`, and just imagine a `vuepress-plugin-abc` is using `"abc"`. They can get their own variables with module name `hope-config` `hope-palette` and `abc-config` `abc-palette`. ::: * Calling the plugin with the same ID has no side effects. ::: tip example `vuepress-theme-hope` and other related plugins use the same ID `hope` to call the plugin. ::: ## Config Config file is used for Sass variable only. It holds Sass variables which can be used via `${id}-config` in other files later. You can specify a file (probably in `.vuepress/styles/` directory) as user config file. So you can get the module containing every variable later in Sass files. Also, you are able to provide a default config files where you can place fallback values for variables with `!default`. ::: details An example Imagine you are invoking the plugin with the following options in `vuepress-plugin-abc`: ```js useSassPalette(app, { id: 'abc', defaultConfig: 'vuepress-plugin-abc/styles/config.scss', }) ``` User config file: ```scss title=".vuepress/styles/abc-palette.scss" $navbar-height: 3.5rem; ``` Default config file: ```scss title="vuepress-plugin-abc/styles/palette.scss" $navbar-height: 2rem !default; $sidebar-width: 18rem !default; ``` You can get the following variables in the plugin Sass files: ```scss // @endregex ::: ::: preview Network @startuml nwdiag { group nightly { color = "#FFAAAA"; description = "<\&clock> Restarted nightly <\&clock>"; web02; db01; } network dmz { address = "210.x.x.x/24" ``` user [description = "<&person*4.5>\n user1"]; web01 [address = "210.x.x.1, 210.x.x.20", description = "<&cog*4>\nweb01"] web02 [address = "210.x.x.2", description = "<&cog*4>\nweb02"]; ``` } network internal { address = "172.x.x.x/24"; ``` web01 [address = "172.x.x.1"]; web02 [address = "172.x.x.2"]; db01 [address = "172.x.x.100", description = "<&spreadsheet*4>\n db01"]; db02 [address = "172.x.x.101", description = "<&spreadsheet*4>\n db02"]; ptr [address = "172.x.x.110", description = "<&print*4>\n ptr01"]; ``` } } @enduml ::: ::: preview Salt @startsalt {+ {/ General | Fullscreen | Behavior | Saving } { { Open image in: | ^Smart Mode^ } \[X] Smooth images when zoomed \[X] Confirm image deletion \[ ] Show hidden images } \[Close] } @endsalt ::: ::: preview Archimate @startuml skinparam rectangle<> { roundCorner 25 } sprite $bProcess jar:archimate/business-process sprite $aService jar:archimate/application-service sprite $aComponent jar:archimate/application-component rectangle "Handle claim" as HC <<$bProcess>><> #Business rectangle "Capture Information" as CI <<$bProcess>><> #Business rectangle "Notify\nAdditional Stakeholders" as NAS <<$bProcess>><> #Business rectangle "Validate" as V <<$bProcess>><> #Business rectangle "Investigate" as I <<$bProcess>><> #Business rectangle "Pay" as P <<$bProcess>><> #Business HC \*-down- CI HC \*-down- NAS HC \*-down- V HC \*-down- I HC \*-down- P CI -right->> NAS NAS -right->> V V -right->> I I -right->> P rectangle "Scanning" as scanning <<$aService>><> #Application rectangle "Customer admnistration" as customerAdministration <<$aService>><> #Application rectangle "Claims admnistration" as claimsAdministration <<$aService>><> #Application rectangle Printing <<$aService>><> #Application rectangle Payment <<$aService>><> #Application scanning -up-> CI customerAdministration -up-> CI claimsAdministration -up-> NAS claimsAdministration -up-> V claimsAdministration -up-> I Payment -up-> P Printing -up-> V Printing -up-> P rectangle "Document\nManagement\nSystem" as DMS <<$aComponent>> #Application rectangle "General\nCRM\nSystem" as CRM <<$aComponent>> #Application rectangle "Home & Away\nPolicy\nAdministration" as HAPA <<$aComponent>> #Application rectangle "Home & Away\nFinancial\nAdministration" as HFPA <<$aComponent>> #Application DMS .up.|> scanning DMS .up.|> Printing CRM .up.|> customerAdministration HAPA .up.|> claimsAdministration HFPA .up.|> Payment legend left Example from the "Archisurance case study" (OpenGroup). See === # <$bProcess> :business process # <$aService> : application service <$aComponent> : application component endlegend @enduml ::: ::: preview Gantt @startgantt Project starts the 2020-12-01 \[Task1] requires 10 days sunday are closed note bottom memo1 ... memo2 ... explanations1 ... explanations2 ... end note \[Task2] requires 20 days \[Task2] starts 10 days after \[Task1]'s end \-- Separator title -- \[M1] happens on 5 days after \[Task1]'s end \-- end -- @endgantt ::: ::: preview Mindmap @startmindmap caption figure 1 title My super title * <\&flag>Debian \*\* <\&globe>Ubuntu \*\*\* Linux Mint \*\*\* Kubuntu \*\*\* Lubuntu \*\*\* KDE Neon \*\* <\&graph>LMDE \*\* <\&pulse>SolydXK \*\* <\&people>SteamOS \*\* <\&star>Raspbian with a very long name \*\*\* Raspmbc => OSMC \*\*\* Raspyfi => Volumio header My super header endheader center footer My super footer legend right Short legend endlegend @endmindmap ::: ::: preview WBS @startwbs * New Job ++ Decide on Job Requirements +++ Identity gaps +++ Review JDs ++++ Sign-Up for courses ++++ Volunteer ++++ Reading ++- Checklist +++- Responsibilities +++- Location ++ CV Upload Done +++ CV Updated ++++ Spelling & Grammar ++++ Check dates \---- Skills +++ Recruitment sites chosen @endwbs ::: ::: preview JSON @startjson \#highlight "lastName" \#highlight "address" / "city" \#highlight "phoneNumbers" / "0" / "number" { "firstName": "John", "lastName": "Smith", "isAlive": true, "age": 28, "address": { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" }, "phoneNumbers": \[ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" } ], "children": \[], "spouse": null } @endjson ::: ::: preview YAML @startyaml doe: "a deer, a female deer" ray: "a drop of golden sun" pi: 3.14159 xmas: true french-hens: 3 calling-birds: \- huey \- dewey \- louie \- fred xmas-fifth-day: calling-birds: four french-hens: 3 golden-rings: 5 partridges: count: 1 location: "a pear tree" turtle-doves: two @endyaml ::: --- --- url: /ecosystem/plugins/markdown/markdown-container.md --- # markdown-container Register markdown custom containers in your VuePress site. This plugin simplifies the use of [markdown-it-container](https://github.com/markdown-it/markdown-it-container), but also retains its original capabilities. ## Usage ```bash npm i -D @vuepress/plugin-markdown-container@next ``` ```ts title=".vuepress/config.ts" import { markdownContainerPlugin } from '@vuepress/plugin-markdown-container' export default { plugins: [ markdownContainerPlugin({ // options }), ], } ``` ## Container Syntax ```md ::: [info] [content] ::: ``` * The `type` is required and should be specified via [type](#type) option. * The `info` is optional, and the default value can be specified via `defaultInfo` in [locales](#locales) option. * The `content` can be any valid markdown content. ::: tip This plugin can be used multiple times to support different types of containers. ::: ## Options ### type * Type: `string` * Required: Yes * Details: The type of the container. It will be used as the `name` param of [markdown-it-container](https://github.com/markdown-it/markdown-it-container#api). ### locales * Type: `Record` * Default: `{}` * Details: The default `info` of the container in different locales. If this option is not specified, the default `info` will fallback to the uppercase of the [type](#type) option. * Example: ```ts title=".vuepress/config.ts" export default { plugins: [ markdownContainerPlugin({ type: 'tip', locales: { '/': { defaultInfo: 'TIP', }, '/zh/': { defaultInfo: 'ๆ็คบ', }, }, }), ], } ``` * Reference: * [Guide > I18n](https://vuejs.press/guide/i18n.html) ### before * Type: `(info: string) => string` * Default: ```ts ;(info: string): string => `
${info ? `

${info}

` : ''}\n` ``` * Details: A function to render the starting tag of the container. The first param is the `info` part of [container syntax](#container-syntax). This option will not take effect if you don't specify the [after](#after) option. ### after * Type: `(info: string) => string` * Default: ```ts ;(): string => '
\n' ``` * Details: A function to render the ending tag of the container. The first param is the `info` part of [container syntax](#container-syntax). This option will not take effect if you don't specify the [before](#before) option. ### render * Type: ```ts type MarkdownItContainerRenderFunction = ( tokens: Token[], index: number, options: unknown, env: MarkdownEnv, self: Renderer, ) => string ``` * Details: The `render` option of [markdown-it-container](https://github.com/markdown-it/markdown-it-container#api). This plugin uses a default `render` function. If you specify this option, the default `render` function will be replaced, and the [locales](#locales), [before](#before) and [after](#after) options will be ignored. ### validate * Type: `(params: string) => boolean` * Details: The `validate` option of [markdown-it-container](https://github.com/markdown-it/markdown-it-container#api). ### marker * Type: `string` * Default: `':'` * Details: The `marker` option of [markdown-it-container](https://github.com/markdown-it/markdown-it-container#api). --- --- url: /ecosystem/plugins/markdown/markdown-ext.md --- # markdown-ext Add basic GFM support to VuePress with useful features. ## Usage ```bash npm i -D @vuepress/plugin-markdown-ext@next ``` ```ts title=".vuepress/config.ts" import { markdownExtPlugin } from '@vuepress/plugin-markdown-ext' export default { plugins: [ markdownExtPlugin({ // options }), ], } ``` ## Syntax ### Footnote * Use `[^Anchor text]` in Markdown to define a footnote * Use `[^Anchor text]: ...` to describe footnote content * If there are multiple paragraphs in footnote, the paragraph show be double indented ::: preview Footnote 1 link\[^first]. Footnote 2 link\[^second]. Inline footnote^\[Text of inline footnote] definition. Duplicated footnote reference\[^second]. \[^first]: Footnote **can have markup** ``` and multiple paragraphs. ``` \[^second]: Footnote text. ::: ### Task list * Use `- [ ] some text` to render an unchecked task item. * Use `- [x] some text` to render a checked task item. (Capital `X` is also supported) ::: preview * \[ ] Plan A * \[x] Plan B ::: ### Component You can use component fence block to add a component into your markdown content. Both YAML and JSON format props data are supported: * YAML : ````md ```component ComponentName # component data here ``` ```` * JSON: ````md ```component ComponentName { // component data here } ``` ```` ::: preview ```component Badge text: Mr.Hope type: tip ``` ```component Badge { "text": "Mr.Hope", "type": "tip" } ``` ::: ### v-pre You can use any mustache syntax as raw text in `v-pre` container: :::: preview ::: v-pre ::: :::: ## Options ### gfm * Type: `boolean` * Details: Whether tweaks the behavior and features to be more similar to GitHub Flavored Markdown. `markdown-it` already supports tables and strike through by default. If this option is `true`, the following new features will be enabled: * Auto link (named `linkify` in `markdown-it`) * Hard breaks * Footnote * Task list Note: Not all behavior is exactly the same as GitHub Flavored Markdown. ### footnote * Type: `boolean` * Details: Whether to enable footnote format support. * Enabled in GFM: Yes ### tasklist * Type: `MarkdownItTaskListOptions | boolean` ```ts interface MarkdownItTaskListOptions { /** * Whether disable checkbox * * @default true */ disabled?: boolean /** * Whether use `