404
Page not found
Looks like we've got some broken links.
diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 5d126348..00000000 --- a/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -# editorconfig.org -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 9f77618a..00000000 --- a/.gitattributes +++ /dev/null @@ -1,12 +0,0 @@ -* text eol=lf -*.txt text eol=crlf - -*.png binary -*.jpg binary -*.jpeg binary -*.ico binary -*.tff binary -*.woff binary -*.woff2 binary - -docs/.vuepress/** -linguist-documentation diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 400fc670..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Bug Report -description: Create a report to help us improve -title: '[Bug report] ' -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: textarea - id: bug-description - attributes: - label: Description - description: A clear and concise description of what the bug is. If applicable, add screenshots to help explain your problem. If you intend to submit a PR for this issue, tell us in the description. Thanks! - placeholder: Bug description - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 3aee83f9..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Question & Discussion - url: https://github.com/vuepress/docs/discussions - about: Please ask and answer questions here. diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml deleted file mode 100644 index 25e5232d..00000000 --- a/.github/workflows/check-docs.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: check-docs - -on: - push: - branches: - - main - pull_request: - branches: - - main - workflow_dispatch: - -jobs: - check-docs: - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - - windows-latest - - macos-latest - node: - - 20 - - 22 - bundler: - - vite - - webpack - - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - - - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node }} - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Lint - run: pnpm lint - - - name: Build docs with ${{ matrix.bundler }} - run: pnpm docs:build - env: - DOCS_BUNDLER: ${{ matrix.bundler }} - - check-docs-result: - if: ${{ always() }} - name: check-docs result - runs-on: ubuntu-latest - needs: - - check-docs - steps: - - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} - run: exit 1 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 341b385d..00000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: docs - -on: - push: - branches: - - main - workflow_dispatch: - -jobs: - docs: - runs-on: ubuntu-latest - - env: - DOCS_GA_ID: G-CTB8FQ7VMW - NODE_VERSION: '22' - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build documentation site - run: pnpm docs:build - - - name: Deploy to GitHub Pages - uses: crazy-max/ghaction-github-pages@v4 - with: - repo: vuepress/vuepress.github.io - target_branch: main - build_dir: docs/.vuepress/dist - env: - GH_PAT: ${{ secrets.GH_PAGES_TOKEN }} diff --git a/.github/workflows/issue-commented.yml b/.github/workflows/issue-commented.yml deleted file mode 100644 index 1f09e871..00000000 --- a/.github/workflows/issue-commented.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: issue-commented - -on: - issue_comment: - types: - - created - -jobs: - issue-commented: - name: remove stale on commented - if: contains(github.event.issue.labels.*.name, 'stale') - runs-on: ubuntu-latest - steps: - - uses: actions-cool/issues-helper@v3 - with: - actions: 'remove-labels' - token: ${{ secrets.GITHUB_TOKEN }} - labels: 'stale' diff --git a/.github/workflows/issue-daily.yml b/.github/workflows/issue-daily.yml deleted file mode 100644 index 4b51b033..00000000 --- a/.github/workflows/issue-daily.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: issue-daily - -on: - schedule: - - cron: '0 0 * * *' - -jobs: - issue-label-stale: - name: label stale issues - runs-on: ubuntu-latest - steps: - - uses: actions-cool/issues-helper@v3 - with: - actions: 'check-inactive' - token: ${{ secrets.GITHUB_TOKEN }} - inactive-day: 15 - inactive-label: 'stale' - exclude-labels: 'bug, documentation, enhancement, feature, help wanted, need reproduction, need review, stale' - body: | - This issue is marked as `stale` because it has not had recent activity. Issues marked with `stale` will be closed if they have no activity within 7 days. - - issue-close-stale: - name: close stale issues - runs-on: ubuntu-latest - steps: - - uses: actions-cool/issues-helper@v3 - with: - actions: 'close-issues' - token: ${{ secrets.GITHUB_TOKEN }} - labels: 'stale' - inactive-day: 7 - - issue-close-need-reproduction: - name: close need-reproduction issues - runs-on: ubuntu-latest - steps: - - uses: actions-cool/issues-helper@v3 - with: - actions: 'close-issues' - token: ${{ secrets.GITHUB_TOKEN }} - labels: 'need reproduction' - inactive-day: 7 diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml deleted file mode 100644 index 227d6760..00000000 --- a/.github/workflows/issue-labeled.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: issue-labeled - -on: - issues: - types: [labeled] - -jobs: - issue-invalid: - name: close invalid issue - if: github.event.label.name == 'invalid' - runs-on: ubuntu-latest - steps: - - uses: actions-cool/issues-helper@v3 - with: - actions: 'close-issue, create-comment' - token: ${{ secrets.GITHUB_TOKEN }} - body: | - Hello @${{ github.event.issue.user.login }}. This issue is marked as `invalid` and closed. Please follow the issue template. - - issue-need-reproduction: - name: need reproduction - if: github.event.label.name == 'need reproduction' - runs-on: ubuntu-latest - steps: - - uses: actions-cool/issues-helper@v3 - with: - actions: 'create-comment' - token: ${{ secrets.GITHUB_TOKEN }} - body: | - Hello @${{ github.event.issue.user.login }}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository or [vuepress.vuejs.org/new](https://vuepress.vuejs.org/new). Issues marked with `need reproduction` will be closed if they have no activity within 7 days. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 91ed4fba..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: release - -on: - push: - tags: - - 'v*' - workflow_dispatch: - -jobs: - release: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Push to release branch - run: git push origin HEAD:release diff --git a/.gitignore b/.gitignore deleted file mode 100644 index e3fdda76..00000000 --- a/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# VuePress files -docs/.vuepress/.temp/ -docs/.vuepress/.cache/ -docs/.vuepress/dist/ - -# Node modules -node_modules/ - -# MacOS Desktop Services Store -.DS_Store - -# Log files -*.log diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index cfe75101..00000000 --- a/.husky/commit-msg +++ /dev/null @@ -1 +0,0 @@ -pnpm commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 74821141..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1 +0,0 @@ -pnpm nano-staged diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 88deb460..00000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -message="build: version %s" diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index bd5535a6..00000000 --- a/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -pnpm-lock.yaml diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index adc12201..00000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "recommendations": [ - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "vue.volar" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 611c9559..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, - "editor.insertSpaces": true, - "editor.tabSize": 2, - "files.encoding": "utf8", - "files.eol": "\n", - "files.trimFinalNewlines": true, - "files.trimTrailingWhitespace": true, - "[markdown]": { - "files.trimTrailingWhitespace": false - }, - "typescript.tsdk": "node_modules/typescript/lib", - "eslint.validate": [ - "javascript", - "javascriptreact", - "typescript", - "typescriptreact", - "vue" - ], - "cSpell.words": [ - "bumpp", - "composables", - "devtool", - "docsearch", - "envinfo", - "esbuild", - "frontmatter", - "globby", - "gtag", - "mdit", - "nprogress", - "prefetch", - "preload", - "prismjs", - "shiki", - "shikiji", - "slugify", - "unmount", - "vuejs", - "vuepress", - "vueuse", - "zoomable" - ] -} diff --git a/404.html b/404.html new file mode 100644 index 00000000..6a541f36 --- /dev/null +++ b/404.html @@ -0,0 +1,40 @@ + + +
+ + + + +The above figure shows a brief overview of the VuePress architecture:
As a developer, you must be aware of that VuePress has two main parts: Node App and Client App, which is important when developing plugins and themes:
The above figure shows the core process of VuePress Node App and the hooks of Plugin API:
Sometimes you might want to add some extra pages without creating a markdown file in the source directory.
With the help of Plugin API and Node API, we can do that with ease.
As a theme author, you may not require users to create a /README.md
file as the homepage, but you want to provide a default one:
import { createPage } from "@vuepress/core";
+
+export default {
+ // all pages have been loaded after initialization
+ async onInitialized(app) {
+ // if the homepage does not exist
+ if (app.pages.every((page) => page.path !== "/")) {
+ // create a homepage
+ const homepage = await createPage(app, {
+ path: "/",
+ // set frontmatter
+ frontmatter: {
+ layout: "Layout",
+ },
+ // set markdown content
+ content: `\
+# Welcome to ${app.options.title}
+
+This is the default homepage
+`,
+ });
+ // add it to `app.pages`
+ app.pages.push(homepage);
+ }
+ },
+};
+
So here comes the Cookbook.
Each recipe will focus on one specific aspect, providing more detailed examples to show you the usages and possibilities of VuePress.
Sometimes users might want make some minor changes to a theme, but they don't want to fork and modify the entire project.
With the help of Theme API, you can make your theme extendable, allowing users to make their own modifications easily.
You must have known that how to extend default theme. Here we'll introduce how to make your own theme extendable like default theme.
This approach requires you to determine which parts of your theme could be extended. It is more suitable for those common customizations like page footer or header.
You just need to provide slots in your layouts, and tell users how to make use of them:
<template>
+ <div class="my-theme-layout">
+ <slot name="page-header" />
+ <Content />
+ <slot name="page-footer" />
+ </div>
+</template>
+
This approach requires you to consider which components of your theme should be replaceable, and you also need to split components into a suitable granularity.
First, set alias
for replaceable components of you theme:
import type { Theme } from "@vuepress/core";
+import { getDirname } from "@vuepress/utils";
+
+const __dirname = getDirname(import.meta.url);
+
+export const fooTheme = (options): Theme => {
+ return {
+ name: "vuepress-theme-foo",
+ alias: {
+ // set alias for replaceable components
+ "@theme/Navbar.vue": path.resolve(__dirname, "components/Navbar.vue"),
+ "@theme/Sidebar.vue": path.resolve(__dirname, "components/Sidebar.vue"),
+ },
+ };
+};
+
Next, use those components via aliases in your theme:
<script setup lang="ts">
+import Navbar from "@theme/Navbar.vue";
+import Sidebar from "@theme/Sidebar.vue";
+</script>
+
+<template>
+ <div class="my-theme-layout">
+ <Navbar />
+ <Sidebar />
+ <Content />
+ </div>
+</template>
+
Then, users can replace specific components by overriding the alias
when extending or using your theme.
Each Markdown file is first compiled into HTML, and then converted to a Vue SFC. In other words, you can write a Markdown file like a Vue SFC:
<script>
and <style>
are treated as Vue SFC blocks as they are. In other words, they are hoisted from the <template>
block to the top-level of SFC.<script>
and <style>
will be compiled into HTML, and be treated as Vue SFC <template>
block.Note
As Vue SFC can contain only one <script>
element, you should avoid using more than one <script>
in VuePress markdown.
Here comes an example:
Input
_Hello, {{ msg }}_
+
+<RedDiv>
+
+_Current count is: {{ count }}_
+
+</RedDiv>
+
+<button @click="count++">Click Me!</button>
+
+<script setup>
+import { h, ref } from "vue";
+
+const RedDiv = (_, ctx) =>
+ h(
+ "div",
+ {
+ class: "red-div",
+ },
+ ctx.slots.default()
+ );
+const msg = "Vue in Markdown";
+const count = ref(0);
+</script>
+
+<style>
+.red-div {
+ color: red;
+}
+</style>
+
Output
Hello, Vue in Markdown
Current count is: 0
As we know, VuePress plugin entries and theme entries are processed in Node side, but sometimes you might need to pass data to client side. For example, you want to generate different data when users use different options.
define
HookPlugin API provides a define hook to define global constants for client code. You can make use of it to pass data to client.
First, define some constants in define
hook:
export default (options) => ({
+ define: {
+ __FOO__: options.foo || "str",
+ __OBJ__: {
+ bar: options.bar || 123,
+ },
+ },
+});
+
Then use them in client code directly:
const foo = __FOO__;
+const obj = __OBJ__;
+
If you are using TypeScript in client code, you may need to declare the types of the global constants manually:
declare const __FOO__: string;
+declare const __OBJ__: { bar: number };
+
If you need to achieve some more complex features, you can write temp files and load them dynamically in client code.
First, write a temp file foo.js
, which will be generated in the temp directory:
export default (options) => ({
+ async onPrepared(app) {
+ // write temp file
+ await app.writeTemp(
+ "foo.js",
+ `export const foo = ${JSON.stringify(options.foo)}`
+ );
+ },
+});
+
Then, load the temp file via @temp
alias in client code:
import { foo } from "@temp/foo";
+
If you are using TypeScript in client code, you may need to declare the type of the temp module manually:
declare module "@temp/foo" {
+ export const foo: string;
+}
+
You can make use of the client config file directly in your project, or specify the file path in your plugin or theme via clientConfigFile hook:
import { getDirname, path } from "@vuepress/utils";
+
+const __dirname = getDirname(import.meta.url);
+
+const pluginOrTheme = {
+ clientConfigFile: path.resolve(__dirname, "./path/to/clientConfig.ts"),
+};
+
Inside the client config file, @vuepress/client
package provides a helper function defineClientConfig to help you define the client config:
import { defineClientConfig } from "@vuepress/client";
+
+export default defineClientConfig({
+ enhance({ app, router, siteData }) {},
+ setup() {},
+ layouts: {},
+ rootComponents: [],
+});
+
The enhance
function could be either synchronous or asynchronous. It accepts a context param with following properties:
app
is the Vue application instance that created by createApp.router
is the Vue Router instance that created by createRouter.siteData
is a ref of an object that generated from user config, including base, lang, title, description, head and locales.The enhance
function will be invoked after the client app is created. It's possible to implement any enhancements to the Vue application.
You can register global Vue components via the app.component method:
import { defineClientConfig } from "@vuepress/client";
+import MyComponent from "./MyComponent.vue";
+
+export default defineClientConfig({
+ enhance({ app }) {
+ app.component("MyComponent", MyComponent);
+ },
+});
+
VuePress will generate a SSR application to pre-render pages during build. Generally speaking, if a code snippet is using Browser / DOM APIs before client app is mounted, we call it non-SSR-friendly.
We already provides a ClientOnly component to wrap non-SSR-friendly content.
In the enhance
function, you can make use of the _
flag for that purpose.
import { defineClientConfig } from "@vuepress/client";
+
+export default defineClientConfig({
+ async enhance() {
+ if (!__VUEPRESS_SSR__) {
+ const nonSsrFriendlyModule = await import("non-ssr-friendly-module");
+ // ...
+ }
+ },
+});
+
You can make use of the Router Methods that provided by vue-router. For example, add navigation guard:
import { defineClientConfig } from "@vuepress/client";
+
+export default defineClientConfig({
+ enhance({ router }) {
+ router.beforeEach((to) => {
+ console.log("before navigation");
+ });
+
+ router.afterEach((to) => {
+ console.log("after navigation");
+ });
+ },
+});
+
Note
It's not recommended to use addRoute
method to add dynamic routes here, because those routes will NOT be pre-rendered in build mode.
But you can still do that if you understand the drawback.
The setup
function would be invoked inside the setup hook of the client vue app.
You can take the setup
function as part of the setup hook of the root component. Thus, all composition APIs are available here.
import { defineClientConfig } from "@vuepress/client";
+import { provide, ref } from "vue";
+import { useRoute, useRouter } from "vue-router";
+
+export default defineClientConfig({
+ setup() {
+ // get the current route location
+ const route = useRoute();
+ // get the vue-router instance
+ const router = useRouter();
+ // provide a value that can be injected by layouts, pages and other components
+ const count = ref(0);
+ provide("count", count);
+ },
+});
+
In the setup
function, the _
flag is also available.
Another way to use non-ssr-friendly features is to put them inside the onMounted hook:
import { defineClientConfig } from "@vuepress/client";
+import { onMounted } from "vue";
+
+export default defineClientConfig({
+ setup() {
+ onMounted(() => {
+ // use DOM API after mounted
+ document.querySelector("#app");
+ });
+ },
+});
+
The layouts
options is to set layout components. After layout components are registered here, users can use it via layout frontmatter.
import { defineClientConfig } from "@vuepress/client";
+import MyLayout from "./layouts/MyLayout.vue";
+
+export default defineClientConfig({
+ layouts: {
+ MyLayout,
+ },
+});
+
The rootComponents
is a components array to be placed directly into the root node of the client vue app.
Typical usage of this option is to put some global UI components, like global popup or so:
import { defineClientConfig } from "@vuepress/client";
+import GlobalPopup from "./components/GlobalPopup.vue";
+
+export default defineClientConfig({
+ rootComponents: [GlobalPopup],
+});
+
Tips
Before reading this guide, you'd better learn the VuePress architecture first.
A plugin should be a plain JavaScript object that satisfies the Plugin API, which is called a Plugin Object:
const fooPlugin = {
+ name: "vuepress-plugin-foo",
+ // ...
+};
+
A plugin could also be a function that receives the app instance as the param and returns a Plugin Object, which is called a Plugin Function:
const barPlugin = (app) => {
+ return {
+ name: "vuepress-plugin-bar",
+ // ...
+ };
+};
+
A plugin usually needs to allow user options, so we typically provide users with a function to receive options, and returns a Plugin Object or a Plugin Function. Then your plugin should be converted like this:
const fooPlugin = (options) => {
+ return {
+ name: "vuepress-plugin-foo",
+ // ...
+ };
+};
+
+const barPlugin = (options) => {
+ return (app) => {
+ return {
+ name: "vuepress-plugin-bar",
+ // ...
+ };
+ };
+};
+
After creating a plugin, you should follow some conventions in the package.json file before publishing it to NPM:
{
+ "name": "vuepress-plugin-foo",
+ "keywords": ["vuepress-plugin"]
+}
+
name
to follow the naming convention, i.e. vuepress-plugin-xxx
or @org/vuepress-plugin-xxx
, which should be consistent with the name field of the Plugin Object.keywords
to include vuepress-plugin
, so that users can search your plugin on NPM.Tips
Before reading this guide, you'd better learn the guide of Writing a Plugin first.
A VuePress theme is a special plugin, which should satisfy the Theme API. Like plugins, a theme should also be a Theme Object or a Theme Function, and could be wrapped with a function to receive options:
import { getDirname, path } from "@vuepress/utils";
+
+const __dirname = getDirname(import.meta.url);
+
+const fooTheme = (options) => {
+ // returns a theme object
+ return {
+ name: "vuepress-theme-foo",
+
+ // path to the client config of your theme
+ clientConfigFile: path.resolve(__dirname, "client.js"),
+
+ // set custom dev / build template
+ // if the template is not specified, the default template from `@vuepress/client` will be used
+ templateBuild: path.resolve(__dirname, "templates/build.html"),
+ templateDev: path.resolve(__dirname, "templates/dev.html"),
+
+ // use plugins
+ plugins: [
+ // ...
+ ],
+
+ // other plugin APIs are also available
+ };
+};
+
+const barTheme = (options) => {
+ // returns a theme function
+ return (app) => {
+ return {
+ name: "vuepress-theme-bar",
+ // ...
+ };
+ };
+};
+
Then, create theme's client config file client.js
:
import { defineClientConfig } from "@vuepress/client";
+import Layout from "./layouts/Layout.vue";
+import NotFound from "./layouts/NotFound.vue";
+
+export default defineClientConfig({
+ layouts: {
+ Layout,
+ NotFound,
+ },
+});
+
The layouts
field declares the layouts provided by your theme. A theme must provide at least two layouts: Layout
and NotFound
. The former is to provide default layout for common pages, while the latter is to provide layout for 404-not-found page.
The Layout
layout should contain the Content component to display the markdown content:
<template>
+ <div>
+ <Content />
+ </div>
+</template>
+
The NotFound
layout will be used for the 404.html
page:
<template>
+ <div>404 Not Found</div>
+</template>
+
You can provide more layouts, and users can change layout via layout frontmatter.
Also, there are some conventions for theme in package.json:
{
+ "name": "vuepress-theme-foo",
+ "keywords": ["vuepress-theme"]
+}
+
name
to follow the naming convention: vuepress-theme-xxx
or @org/vuepress-theme-xxx
, which should be consistent with the name field of the Theme Object.keywords
to include vuepress-theme
, so that users can search your theme on NPM.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.
npm i -D @vuepress/plugin-active-header-links@next
+
import { activeHeaderLinksPlugin } from "@vuepress/plugin-active-header-links";
+
+export default {
+ plugins: [
+ activeHeaderLinksPlugin({
+ // options
+ }),
+ ],
+};
+
Type: string
Default: 'a.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.
Type: number
Default: 200
Details:
The delay of the debounced scroll event listener.
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.
该插件会监听页面滚动事件。当页面滚动至某个 标题锚点 后,如果存在对应的 标题链接 ,那么该插件会将路由 Hash 更改为该 标题锚点 。
该插件主要用于开发主题,并且已经集成到默认主题中。大部分情况下你不需要直接使用它。
npm i -D @vuepress/plugin-active-header-links@next
+
import { activeHeaderLinksPlugin } from "@vuepress/plugin-active-header-links";
+
+export default {
+ plugins: [
+ activeHeaderLinksPlugin({
+ // 配置项
+ }),
+ ],
+};
+
类型: string
默认值: 'a.sidebar-item'
详情:
标题链接 的选择器。
如果一个 标题锚点 没有对应的 标题链接 ,那么即使滚动到这个 标题锚点 ,该插件也不会更改路由 Hash 。
类型: number
默认值: 200
详情:
滚动事件监听器的 Debounce 延迟。
类型: number
默认值: 5
详情:
即便直接点击 标题锚点 的链接, scrollTop
也可能不会完全等于 标题锚点 的 offsetTop
,所以我们添加一个 Offset 偏移量来避免这个误差。
As a theme author, you may not require users to create a /README.md
file as the homepage, but you want to provide a default one:
import { createPage } from "@vuepress/core";
+
+export default {
+ // all pages have been loaded after initialization
+ async onInitialized(app) {
+ // if the homepage does not exist
+ if (app.pages.every((page) => page.path !== "/")) {
+ // create a homepage
+ const homepage = await createPage(app, {
+ path: "/",
+ // set frontmatter
+ frontmatter: {
+ layout: "Layout",
+ },
+ // set markdown content
+ content: \`\\
+# Welcome to \${app.options.title}
+
+This is the default homepage
+\`,
+ });
+ // add it to \`app.pages\`
+ app.pages.push(homepage);
+ }
+ },
+};
+
作为一个主题作者,你可能不想要求用户必须创建一个 /README.md
文件来作为主页,但是你希望提供一个默认的主页:
import { createPage } from "@vuepress/core";
+
+export default {
+ // 初始化之后,所有的页面已经加载完毕
+ async onInitialized(app) {
+ // 如果主页不存在
+ if (app.pages.every((page) => page.path !== "/")) {
+ // 创建一个主页
+ const homepage = await createPage(app, {
+ path: "/",
+ // 设置 frontmatter
+ frontmatter: {
+ layout: "Layout",
+ },
+ // 设置 markdown 内容
+ content: \`\\
+# 欢迎来到 \${app.options.title}
+
+这是默认主页
+\`,
+ });
+ // 把它添加到 \`app.pages\`
+ app.pages.push(homepage);
+ }
+ },
+};
+
上图展示了 VuePress 的简要架构:
作为开发者,你必须要意识到 VuePress 分为两个主要部分: Node App 和 Client App ,这一点对于开发插件和主题来说都十分重要。
The above figure shows a brief overview of the VuePress architecture:
As a developer, you must be aware of that VuePress has two main parts: Node App and Client App, which is important when developing plugins and themes:
You can reference any assets using relative URLs in your Markdown content:

+
This is generally the suggested way to import images, as users usually place images near the Markdown file that references them.
You can put some static assets inside public directory, and they will be copied to the root of the generated directory.
`,7),m=a("code",null,".vuepress/public",-1),k=o(`It would be useful in some cases:
Take our documentation source files as an example, we are putting the logo of VuePress inside the public directory:
└─ docs
+ ├─ .vuepress
+ | └─ public
+ | └─ images
+ | └─ hero.png # <- Logo file
+ └─ guide
+ └─ assets.md # <- Here we are
+
We can reference our logo in current page like this:
Input

+
Output
In most cases, you don't need to worry about the reference path of those public files, as VuePress will automatically handle base
for you:
<!-- you don't need to prepend `/bar/` to `/images/hero.png` manually -->\n\n\n
<template>
+ <img :src="withBase(logoPath)" />
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { withBase } from "@vuepress/client";
+
+const logoPath = ref("/images/hero.png");
+</script>
+
You can also access the helper by $withBase
directly:
<img :src="$withBase('/images/hero.png')" alt="VuePress Logo">
+
Although it is not a common usage, you can reference images from dependent packages:
npm install -D package-name
+

+
The path aliases that set in config file are also supported:
import { getDirname, path } from "@vuepress/utils";
+
+const __dirname = getDirname(import.meta.url);
+
+export default {
+ alias: {
+ "@alias": path.resolve(__dirname, "./path/to/some/dir"),
+ },
+};
+

+
你可以在你的 Markdown 内容中使用相对路径来引用静态资源:

+
一般情况下,我们推荐你使用这种方式来引用图片,因为人们通常会把图片放在引用它的 Markdown 文件附近。
你可以把一些静态资源放在 Public 目录中,它们会被复制到最终生成的网站的根目录下。
`,7),k=n("code",null,".vuepress/public",-1),m=p(`在下列这些情况中,你可能会用到它:
以我们文档的源文件为例,我们把 VuePress 的 Logo 放在了 Public 目录下:
└─ docs
+ ├─ .vuepress
+ | └─ public
+ | └─ images
+ | └─ hero.png # <- Logo 文件
+ └─ guide
+ └─ assets.md # <- 我们在这里
+
我们可以这样在当前页面引用 Logo :
Input

+
Output
在大多数情况下,你不需要担心这些 Public 文件的引用路径,因为 VuePress 会自动帮你处理 base
前缀:
<!-- 你不需要给 `/images/hero.png` 手动添加 `/bar/` 前缀 -->\n\n\n
<template>
+ <img :src="withBase(logoPath)" />
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { withBase } from "@vuepress/client";
+
+const logoPath = ref("/images/hero.png");
+</script>
+
你也可以通过 $withBase
来直接使用这个工具函数:
<img :src="$withBase('/images/hero.png')" alt="VuePress Logo">
+
尽管这不是常见用法,但是你可以从依赖包中引用图片:
npm install -D package-name
+

+
在配置文件中设置的路径别名也同样支持:
import { getDirname, path } from "@vuepress/utils";
+
+const __dirname = getDirname(import.meta.url);
+
+export default {
+ alias: {
+ "@alias": path.resolve(__dirname, "./path/to/some/dir"),
+ },
+};
+

+
该插件会给你的站点添加一个 返回顶部 按钮。当页面向下滚动时,该按钮会显示在页面的右下角,点击它就会滚动到页面顶部。
该插件已经集成到默认主题中。
npm i -D @vuepress/plugin-back-to-top@next
+
import { backToTopPlugin } from "@vuepress/plugin-back-to-top";
+
+export default {
+ plugins: [backToTopPlugin()],
+};
+
你可以通过 CSS 变量来自定义 返回顶部 按钮的样式:
File not found
This plugin will add a back to top button to your site. The button will be displayed in the bottom right corner of the page when scrolling down. By clicking the button, the page will scroll to the top.
This plugin has been integrated into the default theme.
npm i -D @vuepress/plugin-back-to-top@next
+
import { backToTopPlugin } from "@vuepress/plugin-back-to-top";
+
+export default {
+ plugins: [backToTopPlugin()],
+};
+
You can customize the style of the back to top button via CSS variables:
File not found
import { viteBundler } from "vuepress";
+// import { webpackBundler } from 'vuepress-webpack'
+
+export default {
+ bundler: viteBundler({
+ vuePluginOptions: {
+ template: {
+ compilerOptions: {
+ isCustomElement: (tag) => tag === "center",
+ },
+ },
+ },
+ }),
+};
+
import { viteBundler } from "vuepress";
+// import { webpackBundler } from 'vuepress-webpack'
+
+export default {
+ bundler: viteBundler({
+ vuePluginOptions: {
+ template: {
+ compilerOptions: {
+ isCustomElement: (tag) => tag === "center",
+ },
+ },
+ },
+ }),
+};
+
执行 vuepress --help
来获取下列帮助信息:
Usage:
+ $ vuepress <command> [options]
+
+Commands:
+ dev [sourceDir] Start development server
+ build [sourceDir] Build to static site
+ info Display environment information
+
+For more info, run any command with the \`--help\` flag:
+ $ vuepress dev --help
+ $ vuepress build --help
+ $ vuepress info --help
+
+Options:
+ -v, --version Display version number
+ -h, --help Display this message
+
启动一个开发服务器,在本地开发你的 VuePress 站点。
Usage:
+ $ vuepress dev [sourceDir]
+
+Options:
+ -c, --config <config> Set path to config file
+ -p, --port <port> Use specified port (default: 8080)
+ -t, --temp <temp> Set the directory of the temporary files
+ --host <host> Use specified host (default: 0.0.0.0)
+ --cache <cache> Set the directory of the cache files
+ --clean-temp Clean the temporary files before dev
+ --clean-cache Clean the cache files before dev
+ --open Open browser when ready
+ --debug Enable debug mode
+ --no-watch Disable watching page and config files (default: true)
+ -v, --version Display version number
+ -h, --help Display this message
+
提示
通过命令行设置的配置项,会覆盖你配置文件中的同名配置项。
Usage:
+ $ vuepress build [sourceDir]
+
+Options:
+ -c, --config <config> Set path to config file
+ -d, --dest <dest> Set the directory build output (default: .vuepress/dist)
+ -t, --temp <temp> Set the directory of the temporary files
+ --cache <cache> Set the directory of the cache files
+ --clean-temp Clean the temporary files before build
+ --clean-cache Clean the cache files before build
+ --debug Enable debug mode
+ -v, --version Display version number
+ -h, --help Display this message
+
提示
通过命令行设置的配置项,会覆盖你配置文件中的同名配置项。
输出当前系统和依赖相关的信息。
在你想要检查你的环境,或者提交 Issue 时候,可以使用该命令。
`,5);function x(D,S){const l=t("NpmBadge"),n=t("ExternalLinkIcon"),r=t("RouterLink");return o(),c("div",null,[v,s(l,{package:"@vuepress/cli"}),a("p",null,[e("VuePress 命令行接口是由 "),a("a",m,[e("@vuepress/cli"),s(n)]),e(" 包提供的。它包含在 "),a("a",b,[e("vuepress"),s(n)]),e(" 包之中,当然你也可以单独安装它。")]),h,a("div",k,[f,a("p",null,[e("VuePress 使用了 "),a("a",g,[e("debug"),s(n)]),e(" 模块。")]),_]),y,a("p",null,[e("将你的 VuePress 站点构建成静态文件,以便你进行后续"),s(r,{to:"/zh/guide/deployment.html"},{default:d(()=>[e("部署")]),_:1}),e("。")]),w])}const B=p(u,[["render",x],["__file","cli.html.vue"]]);export{B as default}; diff --git a/assets/cli.html-2761a139.js b/assets/cli.html-2761a139.js new file mode 100644 index 00000000..c33fc973 --- /dev/null +++ b/assets/cli.html-2761a139.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-a951be94","path":"/reference/cli.html","title":"Command Line Interface","lang":"en-US","frontmatter":{"icon":"bi:terminal-fill","description":"VuePress CLI is provided by @vuepress/cli (https://www.npmjs.com/package/@vuepress/cli) package. It is included by the vuepress (https://www.npmjs.com/package/vuepress) package,...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/cli.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/cli.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Command Line Interface"}],["meta",{"property":"og:description","content":"VuePress CLI is provided by @vuepress/cli (https://www.npmjs.com/package/@vuepress/cli) package. It is included by the vuepress (https://www.npmjs.com/package/vuepress) package,..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Command Line Interface\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"dev","slug":"dev","link":"#dev","children":[]},{"level":2,"title":"build","slug":"build","link":"#build","children":[]},{"level":2,"title":"info","slug":"info","link":"#info","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.24,"words":373},"filePathRelative":"reference/cli.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/cli.html-cfbcbfaf.js b/assets/cli.html-cfbcbfaf.js new file mode 100644 index 00000000..3d994fd2 --- /dev/null +++ b/assets/cli.html-cfbcbfaf.js @@ -0,0 +1,46 @@ +import{_ as o,W as p,X as c,Y as n,$ as a,a0 as e,Z as d,a1 as i,D as t}from"./framework-46b0e263.js";const u={},v=a("h1",{id:"command-line-interface",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#command-line-interface","aria-hidden":"true"},"#"),e(" Command Line Interface")],-1),m={href:"https://www.npmjs.com/package/@vuepress/cli",target:"_blank",rel:"noopener noreferrer"},b={href:"https://www.npmjs.com/package/vuepress",target:"_blank",rel:"noopener noreferrer"},h=i(`Run vuepress --help
to get following help messages:
Usage:
+ $ vuepress <command> [options]
+
+Commands:
+ dev [sourceDir] Start development server
+ build [sourceDir] Build to static site
+ info Display environment information
+
+For more info, run any command with the \`--help\` flag:
+ $ vuepress dev --help
+ $ vuepress build --help
+ $ vuepress info --help
+
+Options:
+ -v, --version Display version number
+ -h, --help Display this message
+
Start a development server to develop your VuePress site locally.
Usage:
+ $ vuepress dev [sourceDir]
+
+Options:
+ -c, --config <config> Set path to config file
+ -p, --port <port> Use specified port (default: 8080)
+ -t, --temp <temp> Set the directory of the temporary files
+ --host <host> Use specified host (default: 0.0.0.0)
+ --cache <cache> Set the directory of the cache files
+ --clean-temp Clean the temporary files before dev
+ --clean-cache Clean the cache files before dev
+ --open Open browser when ready
+ --debug Enable debug mode
+ --no-watch Disable watching page and config files (default: true)
+ -v, --version Display version number
+ -h, --help Display this message
+
Tips
Options set by CLI will override those options with the same name in your config file.
Usage:
+ $ vuepress build [sourceDir]
+
+Options:
+ -c, --config <config> Set path to config file
+ -d, --dest <dest> Set the directory build output (default: .vuepress/dist)
+ -t, --temp <temp> Set the directory of the temporary files
+ --cache <cache> Set the directory of the cache files
+ --clean-temp Clean the temporary files before build
+ --clean-cache Clean the cache files before build
+ --debug Enable debug mode
+ -v, --version Display version number
+ -h, --help Display this message
+
Tips
Options set by CLI will override those options with the same name in your config file.
Outputs information about your system and dependencies.
This command would be helpful when you want to check your environment or report an issue.
`,5);function x(D,C){const l=t("NpmBadge"),s=t("ExternalLinkIcon"),r=t("RouterLink");return p(),c("div",null,[v,n(l,{package:"@vuepress/cli"}),a("p",null,[e("VuePress CLI is provided by "),a("a",m,[e("@vuepress/cli"),n(s)]),e(" package. It is included by the "),a("a",b,[e("vuepress"),n(s)]),e(" package, and you can also install it separately.")]),h,a("div",k,[f,a("p",null,[e("VuePress is using "),a("a",g,[e("debug"),n(s)]),e(" module.")]),_]),y,a("p",null,[e("Build your VuePress site to static files, which are ready for "),n(r,{to:"/guide/deployment.html"},{default:d(()=>[e("deployment")]),_:1}),e(".")]),w])}const B=o(u,[["render",x],["__file","cli.html.vue"]]);export{B as default}; diff --git a/assets/cli.html-e7d4e52b.js b/assets/cli.html-e7d4e52b.js new file mode 100644 index 00000000..4dd749ac --- /dev/null +++ b/assets/cli.html-e7d4e52b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-9beb15b6","path":"/zh/reference/cli.html","title":"命令行接口","lang":"zh-CN","frontmatter":{"icon":"bi:terminal-fill","description":"VuePress 命令行接口是由 @vuepress/cli (https://www.npmjs.com/package/@vuepress/cli) 包提供的。它包含在 vuepress (https://www.npmjs.com/package/vuepress) 包之中,当然你也可以单独安装它。 执行 vuepress --help 来获取下...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/cli.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/cli.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"命令行接口"}],["meta",{"property":"og:description","content":"VuePress 命令行接口是由 @vuepress/cli (https://www.npmjs.com/package/@vuepress/cli) 包提供的。它包含在 vuepress (https://www.npmjs.com/package/vuepress) 包之中,当然你也可以单独安装它。 执行 vuepress --help 来获取下..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"命令行接口\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"dev","slug":"dev","link":"#dev","children":[]},{"level":2,"title":"build","slug":"build","link":"#build","children":[]},{"level":2,"title":"info","slug":"info","link":"#info","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.51,"words":453},"filePathRelative":"zh/reference/cli.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/client-api.html-787be4ae.js b/assets/client-api.html-787be4ae.js new file mode 100644 index 00000000..1e05661a --- /dev/null +++ b/assets/client-api.html-787be4ae.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-a84e51b8","path":"/reference/client-api.html","title":"Client API","lang":"en-US","frontmatter":{"icon":"fa6-brands:chrome","description":"Client API is provided by @vuepress/client (https://www.npmjs.com/package/@vuepress/client) package, which is used for developing client files. Composition API usePageData Detai...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/client-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/client-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Client API"}],["meta",{"property":"og:description","content":"Client API is provided by @vuepress/client (https://www.npmjs.com/package/@vuepress/client) package, which is used for developing client files. Composition API usePageData Detai..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Client API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"usePageData","slug":"usepagedata","link":"#usepagedata","children":[]},{"level":3,"title":"usePageFrontmatter","slug":"usepagefrontmatter","link":"#usepagefrontmatter","children":[]},{"level":3,"title":"usePageHead","slug":"usepagehead","link":"#usepagehead","children":[]},{"level":3,"title":"usePageHeadTitle","slug":"usepageheadtitle","link":"#usepageheadtitle","children":[]},{"level":3,"title":"usePageLang","slug":"usepagelang","link":"#usepagelang","children":[]},{"level":3,"title":"useRouteLocale","slug":"useroutelocale","link":"#useroutelocale","children":[]},{"level":3,"title":"useSiteData","slug":"usesitedata","link":"#usesitedata","children":[]},{"level":3,"title":"useSiteLocaleData","slug":"usesitelocaledata","link":"#usesitelocaledata","children":[]}]},{"level":2,"title":"Helpers","slug":"helpers","link":"#helpers","children":[{"level":3,"title":"defineClientConfig","slug":"defineclientconfig","link":"#defineclientconfig","children":[]},{"level":3,"title":"withBase","slug":"withbase","link":"#withbase","children":[]}]},{"level":2,"title":"Constants","slug":"constants","link":"#constants","children":[{"level":3,"title":"__VUEPRESS_VERSION__","slug":"vuepress-version","link":"#vuepress-version","children":[]},{"level":3,"title":"__VUEPRESS_BASE__","slug":"vuepress-base","link":"#vuepress-base","children":[]},{"level":3,"title":"__VUEPRESS_DEV__","slug":"vuepress-dev","link":"#vuepress-dev","children":[]},{"level":3,"title":"__VUEPRESS_SSR__","slug":"vuepress-ssr","link":"#vuepress-ssr","children":[]}]},{"level":2,"title":"Advanced","slug":"advanced","link":"#advanced","children":[{"level":3,"title":"resolvers","slug":"resolvers","link":"#resolvers","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.42,"words":425},"filePathRelative":"reference/client-api.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/client-api.html-79f0beda.js b/assets/client-api.html-79f0beda.js new file mode 100644 index 00000000..5567b5bf --- /dev/null +++ b/assets/client-api.html-79f0beda.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-332177d5","path":"/zh/reference/client-api.html","title":"客户端 API","lang":"zh-CN","frontmatter":{"icon":"fa6-brands:chrome","description":"客户端 API 是由 @vuepress/client (https://www.npmjs.com/package/@vuepress/client) Package 提供的,用于开发客户端文件。 Composition API usePageData 详情:; 返回当前页面数据的 Ref 对象。 参考:; Node API > Page 属性 > ...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/client-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/client-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"客户端 API"}],["meta",{"property":"og:description","content":"客户端 API 是由 @vuepress/client (https://www.npmjs.com/package/@vuepress/client) Package 提供的,用于开发客户端文件。 Composition API usePageData 详情:; 返回当前页面数据的 Ref 对象。 参考:; Node API > Page 属性 > ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"客户端 API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"usePageData","slug":"usepagedata","link":"#usepagedata","children":[]},{"level":3,"title":"usePageFrontmatter","slug":"usepagefrontmatter","link":"#usepagefrontmatter","children":[]},{"level":3,"title":"usePageHead","slug":"usepagehead","link":"#usepagehead","children":[]},{"level":3,"title":"usePageHeadTitle","slug":"usepageheadtitle","link":"#usepageheadtitle","children":[]},{"level":3,"title":"usePageLang","slug":"usepagelang","link":"#usepagelang","children":[]},{"level":3,"title":"useRouteLocale","slug":"useroutelocale","link":"#useroutelocale","children":[]},{"level":3,"title":"useSiteData","slug":"usesitedata","link":"#usesitedata","children":[]},{"level":3,"title":"useSiteLocaleData","slug":"usesitelocaledata","link":"#usesitelocaledata","children":[]}]},{"level":2,"title":"工具函数","slug":"工具函数","link":"#工具函数","children":[{"level":3,"title":"defineClientConfig","slug":"defineclientconfig","link":"#defineclientconfig","children":[]},{"level":3,"title":"withBase","slug":"withbase","link":"#withbase","children":[]}]},{"level":2,"title":"常量","slug":"常量","link":"#常量","children":[{"level":3,"title":"__VUEPRESS_VERSION__","slug":"vuepress-version","link":"#vuepress-version","children":[]},{"level":3,"title":"__VUEPRESS_BASE__","slug":"vuepress-base","link":"#vuepress-base","children":[]},{"level":3,"title":"__VUEPRESS_DEV__","slug":"vuepress-dev","link":"#vuepress-dev","children":[]},{"level":3,"title":"__VUEPRESS_SSR__","slug":"vuepress-ssr","link":"#vuepress-ssr","children":[]}]},{"level":2,"title":"进阶能力","slug":"进阶能力","link":"#进阶能力","children":[{"level":3,"title":"resolvers","slug":"resolvers","link":"#resolvers","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.07,"words":620},"filePathRelative":"zh/reference/client-api.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/client-api.html-9d516b34.js b/assets/client-api.html-9d516b34.js new file mode 100644 index 00000000..8bf1367a --- /dev/null +++ b/assets/client-api.html-9d516b34.js @@ -0,0 +1,14 @@ +import{_ as r,W as u,X as d,Y as a,$ as e,a0 as n,Z as s,a1 as i,D as o}from"./framework-46b0e263.js";const h={},f=e("h1",{id:"client-api",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#client-api","aria-hidden":"true"},"#"),n(" Client API")],-1),g={href:"https://www.npmjs.com/package/@vuepress/client",target:"_blank",rel:"noopener noreferrer"},_=e("h2",{id:"composition-api",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#composition-api","aria-hidden":"true"},"#"),n(" Composition API")],-1),v=e("h3",{id:"usepagedata",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#usepagedata","aria-hidden":"true"},"#"),n(" usePageData")],-1),k=e("li",null,[e("p",null,"Details:"),e("p",null,"Returns the page data ref object of current page.")],-1),m=e("p",null,"Also see:",-1),b=e("h3",{id:"usepagefrontmatter",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#usepagefrontmatter","aria-hidden":"true"},"#"),n(" usePageFrontmatter")],-1),x=e("ul",null,[e("li",null,[e("p",null,"Details:"),e("p",null,"Returns the frontmatter ref object of current page."),e("p",null,[n("The value is the "),e("code",null,"frontmatter"),n(" property of the page data.")])])],-1),y=e("h3",{id:"usepagehead",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#usepagehead","aria-hidden":"true"},"#"),n(" usePageHead")],-1),P=e("p",null,"Details:",-1),w=e("p",null,"Returns the head config ref object of current page.",-1),D=i('Details:
Returns the head title ref object of current page.
The value is obtained by joining the page title and site title.
Details:
Returns the language ref object of current page.
The value is the lang
property of the page data.
Details:
Returns the site data ref object.
Details:
Returns the site data ref object of current locale.
The properties of current locale have been merged into the root-level properties.
There are some constants that available in the client side code.
To shim the types of these constants in client side code, add @vuepress/client/types
to your tsconfig.json
:
{
+ "compilerOptions": {
+ "types": ["@vuepress/client/types"]
+ }
+}
+
__VUEPRESS_VERSION__
Type: string
Details:
Version of VuePress core package.
__VUEPRESS_BASE__
__VUEPRESS_DEV__
Type: boolean
Details:
An environment flag indicating whether it is currently running in dev
mode.
__VUEPRESS_SSR__
Type: boolean
Details:
An environment flag indicating whether it is currently running in server-side-rendering (SSR) build.
Type: Record<string, Function>
Details:
An reactive object, methods of which determining how to resolve global computed.
Example:
Customizing the format of <title>
in client config file:
import { defineClientConfig, resolvers } from "@vuepress/client";
+
+export default defineClientConfig({
+ enhance({ app, router, siteData }) {
+ resolvers.resolvePageHeadTitle = (page, siteLocale) =>
+ \`\${siteLocale.title} > \${page.title}\`;
+ },
+});
+
Warning
resolvers
will affect the basic functionality of VuePress. Please make sure you have fully understood its purpose before modifying it.
详情:
返回当前页面 Head 中的标题的 Ref 对象。
它的值是连接页面标题和站点标题后得到的。
详情:
返回当前页面语言的 Ref 对象。
它的值是页面数据的 lang
属性。
详情:
返回站点数据的 Ref 对象。
详情:
返回当前 locale 的站点数据的 Ref 对象。
当前 locale 中的配置已经合并到顶层配置中。
在客户端代码中有一些常量可以使用。
如果想要把这些常量的类型定义补充到你的代码环境中,请将 @vuepress/client/types
添加到你的 tsconfig.json
里:
{
+ "compilerOptions": {
+ "types": ["@vuepress/client/types"]
+ }
+}
+
__VUEPRESS_VERSION__
类型: string
详情:
VuePress Core 的版本号。
__VUEPRESS_BASE__
__VUEPRESS_DEV__
类型: boolean
详情:
一个环境标记,用于标识当前是否运行在 dev
模式下。
__VUEPRESS_SSR__
类型: boolean
详情:
一个环境标记,用于标识当前是否运行在服务端渲染 (SSR) 环境下。
类型: Record<string, Function>
详情:
一个响应式对象,其中的方法决定了如何获取全局计算属性。
示例:
在客户端配置文件中自定义 <title>
的格式:
import { defineClientConfig, resolvers } from "@vuepress/client";
+
+export default defineClientConfig({
+ enhance({ app, router, siteData }) {
+ resolvers.resolvePageHeadTitle = (page, siteLocale) =>
+ \`\${siteLocale.title} > \${page.title}\`;
+ },
+});
+
警告
resolvers
会直接影响 VuePress 的基础功能,在修改前请确保你已充分了解其用途。
Props:
'tip' | 'warning' | 'danger'
'tip'
string
''
'top' | 'middle' | 'bottom' | undefined
undefined
Example:
Input
- VuePress - <Badge type="tip" text="v2" vertical="top" />
+- VuePress - <Badge type="warning" text="v2" vertical="middle" />
+- VuePress - <Badge type="danger" text="v2" vertical="bottom" />
+
Output
`,4),q=u(`Details:
Wrapper of the CodeGroupItem components.
Props:
string
true
boolean
false
Details:
This component must be placed inside a CodeGroup component.
Use the active
prop to set the initial active item, or the first item will be activated by default.
Example:
Input
<CodeGroup>
+ <CodeGroupItem title="PNPM">
+
+\`\`\`bash:no-line-numbers
+pnpm install
+\`\`\`
+
+ </CodeGroupItem>
+
+ <CodeGroupItem title="YARN">
+
+\`\`\`bash:no-line-numbers
+yarn install
+\`\`\`
+
+ </CodeGroupItem>
+
+ <CodeGroupItem title="NPM" active>
+
+\`\`\`bash:no-line-numbers
+npm install
+\`\`\`
+
+ </CodeGroupItem>
+</CodeGroup>
+
Output
`,7),x=n("div",{class:"language-bash","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"pnpm"),a(),n("span",{class:"token function"},"install"),a(` +`)])])],-1),C=n("div",{class:"language-bash","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"yarn"),a(),n("span",{class:"token function"},"install"),a(` +`)])])],-1),y=n("div",{class:"language-bash","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"npm"),a(),n("span",{class:"token function"},"install"),a(` +`)])])],-1),w={class:"hint-container warning"},P=n("p",{class:"hint-container-title"},"Note",-1),G=n("p",null,[a("You must add an empty line between the starting tag of "),n("code",null,"<ClientOnly>
+ <NonSsrFriendlyComponent />
+</ClientOnly>
+
Details:
This component and its children will only be rendered in client-side. That means, it will not be rendered to HTML during build (SSR).
If a component is trying to access Browser / DOM APIs directly in setup()
, an error will occur during build because those APIs are unavailable in Node.js environment. In such case, you could do either:
onBeforeMount()
or onMounted()
hook.<ClientOnly>
.Props:
string
false
Usage:
<Content page-key="v-xxxxxx" />
+
Props:
'tip' | 'warning' | 'danger'
'tip'
string
''
'top' | 'middle' | 'bottom' | undefined
undefined
示例:
输入
- VuePress - <Badge type="tip" text="v2" vertical="top" />
+- VuePress - <Badge type="warning" text="v2" vertical="middle" />
+- VuePress - <Badge type="danger" text="v2" vertical="bottom" />
+
输出
`,4),f=i(`详情:
CodeGroupItem 组件的 Wrapper 。
Props:
string
true
boolean
false
详情:
该组件必须放置在 CodeGroup 组件的内部。
可以通过 active
Prop 来设置初始激活的元素。如果不设置,默认激活第一个元素。
示例:
输入
<CodeGroup>
+ <CodeGroupItem title="PNPM">
+
+\`\`\`bash:no-line-numbers
+pnpm install
+\`\`\`
+
+ </CodeGroupItem>
+
+ <CodeGroupItem title="YARN">
+
+\`\`\`bash:no-line-numbers
+yarn install
+\`\`\`
+
+ </CodeGroupItem>
+
+ <CodeGroupItem title="NPM" active>
+
+\`\`\`bash:no-line-numbers
+npm install
+\`\`\`
+
+ </CodeGroupItem>
+</CodeGroup>
+
输出
`,7),x=n("div",{class:"language-bash","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"pnpm"),a(),n("span",{class:"token function"},"install"),a(` +`)])])],-1),C=n("div",{class:"language-bash","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"yarn"),a(),n("span",{class:"token function"},"install"),a(` +`)])])],-1),P=n("div",{class:"language-bash","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"npm"),a(),n("span",{class:"token function"},"install"),a(` +`)])])],-1),w={class:"hint-container warning"},B=n("p",{class:"hint-container-title"},"注意",-1),G=n("p",null,[a("你必须在 "),n("code",null,"<ClientOnly>
+ <NonSsrFriendlyComponent />
+</ClientOnly>
+
详情:
该组件和它的子元素只会在客户端被渲染。也就是说,它不会在构建 (SSR) 过程中被渲染到 HTML 内。
如果一个组件在 setup()
中直接使用 浏览器 / DOM API ,它会导致构建过程报错,因为这些 API 在 Node.js 的环境中是无法使用的。在这种情况下,你可以选择一种方式:
onBeforeMount()
或 onMounted()
Hook 中使用 浏览器 / DOM API 。<ClientOnly>
包裹这个组件。Props:
string
false
使用:
<Content page-key="v-xxxxxx" />
+
import { defaultTheme } from "@vuepress/theme-default";
+
+export default {
+ theme: defaultTheme({
+ // 在这里进行配置
+ }),
+};
+
该章节内的配置项可以作为一般配置使用,也可以使用在 locales 内。
类型: boolean
默认值: true
详情:
是否启用切换颜色模式的功能。
如果设置为 true
,将会在导航栏展示一个切换颜色模式的按钮。
参考:
类型: string
默认值: /
详情:
首页的路径。
它将被用于:
类型: false | (NavbarItem | NavbarGroup | string)[]
默认值: []
详情:
导航栏配置。
设置为 false
可以禁用导航栏。
为了配置导航栏元素,你可以将其设置为 导航栏数组 ,其中的每个元素是 NavbarItem
对象、 NavbarGroup
对象、或者字符串:
NavbarItem
对象应该有一个 text
字段和一个 link
字段,还有一个可选的 activeMatch
字段。NavbarGroup
对象应该有一个 text
字段和一个 children
字段。 children
字段同样是一个 导航栏数组 。NavbarItem
对象,将页面标题作为 text
,将页面路由路径作为 link
。示例 1:
export default {
+ theme: defaultTheme({
+ navbar: [
+ // NavbarItem
+ {
+ text: "Foo",
+ link: "/foo/",
+ },
+ // NavbarGroup
+ {
+ text: "Group",
+ children: ["/group/foo.md", "/group/bar.md"],
+ },
+ // 字符串 - 页面文件路径
+ "/bar/README.md",
+ ],
+ }),
+};
+
export default {
+ theme: defaultTheme({
+ navbar: [
+ // 嵌套 Group - 最大深度为 2
+ {
+ text: "Group",
+ children: [
+ {
+ text: "SubGroup",
+ children: ["/group/sub/foo.md", "/group/sub/bar.md"],
+ },
+ ],
+ },
+ // 控制元素何时被激活
+ {
+ text: "Group 2",
+ children: [
+ {
+ text: "Always active",
+ link: "/",
+ // 该元素将一直处于激活状态
+ activeMatch: "/",
+ },
+ {
+ text: "Active on /foo/",
+ link: "/not-foo/",
+ // 该元素在当前路由路径是 /foo/ 开头时激活
+ // 支持正则表达式
+ activeMatch: "^/foo/",
+ },
+ ],
+ },
+ ],
+ }),
+};
+
类型: null | string
详情:
Logo 图片的 URL。
Logo 图片将会显示在导航栏的左端。
设置为 null
可以禁用 Logo 。
示例:
export default {
+ theme: defaultTheme({
+ // Public 文件路径
+ logo: "/images/hero.png",
+ // URL
+ logo: "https://vuejs.org/images/logo.png",
+ }),
+};
+
类型: null | string
详情:
在夜间模式中使用的 Logo 图片的 URL。
如果你想在夜间模式中使用不同的 Logo 图片,就可以使用该配置项。
设置为 null
可以在夜间模式下禁用 Logo 。忽略该配置项将会在夜间模式中使用 logo 配置。
参考:
类型: string
详情:
项目仓库的 URL。
它将被用作 仓库链接 的链接。仓库链接 将会显示为导航栏的最后一个元素。
export default {
+ theme: defaultTheme({
+ // 如果你按照 \`organization/repository\` 的格式设置它
+ // 我们会将它作为一个 GitHub 仓库
+ repo: "vuejs/vuepress",
+ // 你也可以直接将它设置为一个 URL
+ repo: "https://gitlab.com/foo/bar",
+ }),
+};
+
类型: string
详情:
项目仓库的标签。
它将被用作 仓库链接 的文字。仓库链接 将会显示为导航栏的最后一个元素。
如果你不明确指定该配置项,它将会根据 repo 配置项自动推断。
类型: string
详情:
选择语言菜单 的 aria-label
属性。
它主要是为了站点的可访问性 (a11y) 。
类型: string
详情:
Locale 的语言名称。
该配置项 仅能在主题配置的 locales 的内部生效 。它将被用作 locale 的语言名称,展示在 选择语言菜单 内。
示例:
export default {
+ locales: {
+ "/": {
+ lang: "en-US",
+ },
+ "/zh/": {
+ lang: "zh-CN",
+ },
+ },
+ theme: defaultTheme({
+ locales: {
+ "/": {
+ selectLanguageName: "English",
+ },
+ "/zh/": {
+ selectLanguageName: "简体中文",
+ },
+ },
+ }),
+};
+
设置为 false
可以禁用侧边栏。
如果你设置为 'auto'
,侧边栏会根据页面标题自动生成。
为了手动配置侧边栏元素,你可以将其设置为 侧边栏数组 ,其中的每个元素是一个 SidebarItem
对象或者一个字符串:
SidebarItem
对象应该有一个 text
字段,有一个可选的 link
字段、一个可选的 children
字段和一个可选的 collapsible
字段。 children
字段同样是一个 侧边栏数组 。 collapsible
字段来控制它是否可折叠。SidebarItem
对象,将页面标题作为 text
,将页面路由路径作为 link
,并根据页面小标题自动生成 children
。如果你想在不同子路径中使用不同的侧边栏,你可以将该配置项设置为 侧边栏对象 :
export default {
+ theme: defaultTheme({
+ // 侧边栏数组
+ // 所有页面会使用相同的侧边栏
+ sidebar: [
+ // SidebarItem
+ {
+ text: "Foo",
+ link: "/foo/",
+ children: [
+ // SidebarItem
+ {
+ text: "github",
+ link: "https://github.com",
+ children: [],
+ },
+ // 字符串 - 页面文件路径
+ "/foo/bar.md",
+ ],
+ },
+ // 字符串 - 页面文件路径
+ "/bar/README.md",
+ ],
+ }),
+};
+
export default {
+ theme: defaultTheme({
+ // 侧边栏对象
+ // 不同子路径下的页面会使用不同的侧边栏
+ sidebar: {
+ "/guide/": [
+ {
+ text: "Guide",
+ children: ["/guide/README.md", "/guide/getting-started.md"],
+ },
+ ],
+ "/reference/": [
+ {
+ text: "Reference",
+ children: ["/reference/cli.md", "/reference/config.md"],
+ },
+ ],
+ },
+ }),
+};
+
export default {
+ theme: defaultTheme({
+ // 可折叠的侧边栏
+ sidebar: {
+ "/reference/": [
+ {
+ text: "VuePress Reference",
+ collapsible: true,
+ children: ["/reference/cli.md", "/reference/config.md"],
+ },
+ {
+ text: "Bundlers Reference",
+ collapsible: true,
+ children: [
+ "/reference/bundler/vite.md",
+ "/reference/bundler/webpack.md",
+ ],
+ },
+ ],
+ },
+ }),
+};
+
详情:
设置根据页面标题自动生成的侧边栏的最大深度。
0
来禁用所有级别的页面标题。1
来包含 <h2>
标题。2
来包含 <h2>
和 <h3>
标题。类型: string
默认值: 'Edit this page'
详情:
编辑此页 链接的文字。
类型: string
详情:
编辑此页 链接的 Pattern 。
它将会用于生成 编辑此页 的链接。
如果你不设置该选项,则会根据 docsRepo 配置项来推断 Pattern 。但是如果你的文档仓库没有托管在常用的平台上,比如 GitHub 、 GitLab 、 Bitbucket 、 Gitee 等,那么你必须设置该选项才能使 编辑此页 链接正常工作。
用法:
Pattern | 描述 |
---|---|
:repo | 文档仓库 URL ,即 docsRepo |
:branch | 文档仓库分支 ,即 docsBranch |
:path | 页面源文件的路径,即 docsDir 拼接上页面文件的相对路径 |
示例:
export default {
+ theme: defaultTheme({
+ docsRepo: "https://gitlab.com/owner/name",
+ docsBranch: "master",
+ docsDir: "docs",
+ editLinkPattern: ":repo/-/edit/:branch/:path",
+ }),
+};
+
则会生成类似于 'https://gitlab.com/owner/name/-/edit/master/docs/path/to/file.md'
的链接。
类型: string
详情:
文档源文件的仓库 URL 。
它将会用于生成 编辑此页 的链接。
如果你不设置该选项,则默认会使用 repo 配置项。但是如果你的文档源文件是在一个不同的仓库内,你就需要设置该配置项了。
类型: string
默认值: 'main'
详情:
文档源文件的仓库分支。
它将会用于生成 编辑此页 的链接。
类型: string
默认值: ''
详情:
文档源文件存放在仓库中的目录名。
它将会用于生成 编辑此页 的链接。
类型: string
默认值: 'Last Updated'
详情:
最近更新时间戳 标签的文字。
类型: string
默认值: 'Contributors'
详情:
贡献者列表 标签的文字。
类型: string[]
默认值: ['Not Found']
详情:
404 页面的提示信息。
当用户进入 404 页面时,会从数组中随机选取一条信息进行展示。
类型: string
默认值: 'Back to home'
详情:
404 页面中 返回首页 链接的文字。
类型: string
默认值: 'toggle color mode'
详情:
切换颜色模式按钮的标题文字。
它主要是为了站点的可访问性 (a11y) 。
参考:
类型: string
默认值: 'toggle sidebar'
详情:
切换侧边栏按钮的标题文字。
它主要是为了站点的可访问性 (a11y) 。
详情:
设置默认主题使用的插件。
默认主题使用了一些插件,如果你确实不需要该插件,你可以选择禁用它。在禁用插件之前,请确保你已了解它的用途。
ContainerType
类型为:
tip
warning
danger
details
codeGroup
codeGroupItem
Type: string
Default: /
Details:
The base URL the site will be deployed at.
You will need to set this if you plan to deploy your site under a sub path. It should always start and end with a slash. For example, if you plan to deploy your site to GitHub pages at https://foo.github.io/bar/
, then you should set base
to "/bar/"
.
The base
is automatically prepended to all the URLs that start with /
in other options, so you only need to specify it once.
Notice that base
should be an absolute URL pathname starting and ending with /
.
Type: string
Default: en-US
Details:
Language for the site.
This will be the lang
attribute of the <html>
tag in the rendered HTML.
This can be specified in different locales.
Type: string
Default: ''
Details:
Title for the site.
This will be the suffix for all page titles, and displayed in the navbar in the default theme.
This can be specified in different locales.
Also see:
Type: string
Default: ''
Details:
Description for the site.
This will be the content
attribute of <meta name="description" />
tag in the rendered HTML, which will be overrode by the description
field of page frontmatter.
This can be specified in different locales.
Type: HeadConfig[]
Default: []
Details:
Extra tags to inject into the <head>
tag in the rendered HTML.
You can specify each tag in the form of [tagName, { attrName: attrValue }, innerHTML?]
.
This can be specified in different locales.
Example:
To add a custom favicon:
export default {
+ head: [["link", { rel: "icon", href: "/images/logo.png" }]],
+};
+
Rendered as:
<head>
+ <link rel="icon" href="/images/logo.png" />
+</head>
+
Type: { [path: string]: Partial<SiteLocaleData> }
Default: {}
Details:
Specify locales for i18n support.
Acceptable fields:
Type: Bundler
Details:
Set the bundler of your site.
If this option is not set, the default bundler will be used:
vuepress
or vuepress-vite
, the default bundler is vite.vuepress-webpack
, the default bundler is webpack.Type: string
Default: `${sourceDir}/.vuepress/dist`
Details:
Specify the output directory for vuepress build
command.
Type: string
Default: `${sourceDir}/.vuepress/.temp`
Details:
Specify the directory for temporary files.
Note
Since VuePress will load temp files during dev and build, the temp directory should be inside project root to resolve dependencies correctly.
Type: string
Default: `${sourceDir}/.vuepress/.cache`
Details:
Specify the directory for cache files.
Type: string[]
Default: ['**/*.md', '!.vuepress', '!node_modules']
Details:
Specify the patterns of files you want to be resolved as pages. The patterns are relative to the source directory.
Type: string | null
Default: null
Details:
Specify the pattern to generate permalink.
This will be overrode by the permalinkPattern
field of page frontmatter.
Type: string
Default: '0.0.0.0'
Details:
Specify the host to use for the dev server.
Type: number
Default: 8080
Details:
Specify the port to use for the dev server.
Type: boolean
Default: false
Details:
Whether to open the browser after dev-server had been started.
Type: string
Default: '@vuepress/client/templates/dev.html'
Details:
Specify the path of the HTML template to be used for dev.
Type: ((file: string, type: string) => boolean)) | boolean
Default: true
Details:
A function to control what files should have <link rel="preload">
resource hints generated. Set to true
or false
to enable or disable totally.
By default, only those files that are required by current page will be preloaded. So you can keep it true
in most cases.
Type: ((file: string, type: string) => boolean)) | boolean
Default: true
Details:
A function to control what files should have <link rel="prefetch">
resource hints generated. Set to true
or false
to enable or disable for all files.
If you set it to true
, all files that required by other pages will be prefetched. This is good for small sites, which will speed up the navigation, but it might not be a good idea if you have lots of pages in your site.
Type: string
Default: '@vuepress/client/templates/build.html'
Details:
Specify the path of the HTML template to be used for build.
Type: AnchorPluginOptions | false
Default:
const defaultOptions = {
+ level: [1, 2, 3, 4, 5, 6],
+ permalink: anchorPlugin.permalink.ariaHidden({
+ class: "header-anchor",
+ symbol: "#",
+ space: true,
+ placement: "before",
+ }),
+};
+
Type: AssetsPluginOptions | false
Details:
Options for VuePress built-in markdown-it assets plugin.
Set to false
to disable this plugin.
Warning
You should not configure it unless you understand what it is for.
Type: boolean | number
Default: true
Details:
Configure code line numbers.
boolean
value is to enable line numbers or not.number
value is the minimum number of lines to enable line numbers. For example, if you set it to 4
, line numbers will only be enabled when your code block has at least 4 lines of code.Type: boolean
Default: true
Details:
Enable the extra wrapper of the <pre>
tag or not.
The wrapper is required by the highlightLines
and lineNumbers
. That means, if you disable preWrapper
, the line highlighting and line numbers will also be disabled.
Type: boolean
Default: true
Details:
Add v-pre
directive to <pre>
tag of code block or not.
Type: boolean
Default: true
Details:
Add v-pre
directive to <code>
tag of inline code or not.
Warning
You should not configure it unless you understand what it is for.
Type: HeadersPluginOptions | false
Default:
const defaultOptions = {
+ level: [2, 3],
+};
+
Type: (str: string) => string
Default: (str) => str
Details:
A function to handle the import path of the import code syntax.
Type: LinksPluginOptions | false
Details:
Options for VuePress built-in markdown-it links plugin.
It will convert internal links to <RouterLink>
, and add extra attributes and icon to external links.
Set to false
to disable this plugin.
Type: 'a' | 'RouterLink'
Default: 'RouterLink'
Details:
Tag for internal links.
By default, this plugin will transform internal links to <RouterLink>
. You can set this option to 'a'
to disable this feature.
Type: Record<string, string>
Default: { target: '_blank', rel: 'noopener noreferrer' }
Details:
Additional attributes for external links.
Warning
You should not configure it unless you understand what it is for.
Type: TocPluginOptions | false
Default:
const defaultOptions = {
+ level: [2, 3],
+};
+
类型: string
默认值: /
详情:
部署站点的基础路径。
如果你想让你的网站部署到一个子路径下,你将需要设置它。它的值应当总是以斜杠开始,并以斜杠结束。举例来说,如果你想将你的网站部署到 https://foo.github.io/bar/
,那么 base
应该被设置成 "/bar/"
。
base
将会作为前缀自动地插入到所有以 /
开始的其他选项的链接中,所以你只需要指定一次。
需要注意的是, base
应该是一个以 /
开始和结束的绝对路径名。
类型: string
默认值: en-US
详情:
站点的语言。
它将会在最终渲染出的 HTML 中作为 <html>
标签的 lang
属性。
它可以设置在不同语言的 locales 中。
参考:
类型: string
默认值: ''
详情:
站点的标题。
它将会作为所有页面标题的后缀,并且在默认主题的导航栏中显示。
它可以设置在不同语言的 locales 中。
参考:
类型: string
默认值: ''
详情:
站点的描述。
它将会在最终渲染出的 HTML 中作为 <meta name="description" />
标签的 content
属性。它会被每个页面的 Frontmatter 中的 description
字段覆盖。
它可以设置在不同语言的 locales 中。
类型: HeadConfig[]
默认值: []
详情:
在最终渲染出的 HTML 的 <head>
标签内加入的额外标签。
你可以通过 [tagName, { attrName: attrValue }, innerHTML?]
的格式来添加标签。
它可以设置在不同语言的 locales 中。
示例:
增加一个自定义的 favicon :
export default {
+ head: [["link", { rel: "icon", href: "/images/logo.png" }]],
+};
+
渲染为:
<head>
+ <link rel="icon" href="/images/logo.png" />
+</head>
+
类型: { [path: string]: Partial<SiteLocaleData> }
默认值: {}
详情:
多语言支持的各个语言 locales 。
可以使用的字段有:
类型: Bundler
详情:
设置站点要使用的打包工具。
如果不设置该选项,将会使用默认的打包工具:
vuepress
或 vuepress-vite
时,默认的打包工具是 Vite 。vuepress-webpack
时,默认的打包工具是 Webpack 。类型: string
默认值: `${sourceDir}/.vuepress/dist`
详情:
指定 vuepress build
命令的输出目录。
类型: string
默认值: `${sourceDir}/.vuepress/.temp`
详情:
指定临时文件目录。
注意
VuePress 在开发和构建时会加载临时文件,因此临时文件目录应位于项目根目录内部,以便可以正确地解析到依赖。
类型: string
默认值: `${sourceDir}/.vuepress/.cache`
详情:
指定缓存文件目录。
类型: string[]
默认值: ['**/*.md', '!.vuepress', '!node_modules']
详情:
指定页面文件的 Patterns 。这些 Patterns 是相对于 Source 目录的。
类型: string | null
默认值: null
详情:
指定为页面生成永久链接的 Pattern 。
它会被每个页面的 Frontmatter 中的 permalinkPattern
字段覆盖。
类型: string
默认值: '0.0.0.0'
详情:
指定开发服务器的主机名。
类型: number
默认值: 8080
详情:
指定开发服务器的端口号。
类型: boolean
默认值: false
详情:
是否在开发服务器启动后打开浏览器。
类型: string
默认值: '@vuepress/client/templates/dev.html'
详情:
指定开发时使用的 HTML 模板。
类型: ((file: string, type: string) => boolean)) | boolean
默认值: true
详情:
一个函数,用来控制哪些文件是需要生成对应的 <link rel="preload">
标签的。设置为 true
或者 false
来完全启用或禁用它。
默认情况下,只有当前页面所需的文件会被预加载。所以在绝大部分情况下,你只需要使用 true
就可以了。
类型: ((file: string, type: string) => boolean)) | boolean
默认值: true
详情:
一个函数,用来控制哪些文件是需要生成对应的 <link rel="prefetch">
标签的。设置为 true
或者 false
来完全启用或禁用它。
如果你将它设置为 true
,所有其它页面所需的文件都会被预拉取。这对于小型站点来说是十分有帮助的,因为它会大大提升页面切换的速度。但是在你的网站有很多页面时不建议你这么做。
类型: string
默认值: '@vuepress/client/templates/build.html'
详情:
指定构建时使用的 HTML 模板。
类型: AnchorPluginOptions | false
默认值:
const defaultOptions = {
+ level: [1, 2, 3, 4, 5, 6],
+ permalink: anchorPlugin.permalink.ariaHidden({
+ class: "header-anchor",
+ symbol: "#",
+ space: true,
+ placement: "before",
+ }),
+};
+
类型: AssetsPluginOptions | false
详情:
VuePress 内置的 markdown-it assets 插件的配置项。
设置为 false
可以禁用该插件。
警告
除非你了解它的用途,否则你不应该设置该配置项。
类型: boolean | number
默认值: true
详情:
配置代码块行号。
boolean
代表是否启用代码块行号。number
代表显示行号所需的最少行数。例如,如果你将它设置为 4
,那么只有在你的代码块包含至少 4 行代码时才会启用行号。类型: boolean
默认值: true
详情:
是否在 <pre>
标签外额外包裹一层。
highlightLines
和 lineNumbers
依赖于这个额外的包裹层。这换句话说,如果你禁用了 preWrapper
,那么行高亮和行号也会被同时禁用。
类型: boolean
默认值: true
详情:
是否在代码块的 <pre>
标签上添加 v-pre
指令。
类型: boolean
默认值: true
详情:
是否在行内代码的 <code>
标签上添加 v-pre
指令。
警告
除非你了解它的用途,否则你不应该设置该配置项。
类型: HeadersPluginOptions | false
默认值:
const defaultOptions = {
+ level: [2, 3],
+};
+
类型: (str: string) => string
默认值: (str) => str
详情:
一个函数,用于处理导入代码语法中的文件导入路径。
类型: LinkPluginOptions | false
详情:
VuePress 内置的 markdown-it 链接插件的配置项。
它可以把站内链接转换为 <RouterLink>
,并且可以在站外链接上添加额外的属性和图标。
设置为 false
可以禁用该插件。
类型: string
默认值: 'RouterLink'
详情:
内部链接所使用的标签。
默认情况下,该插件会把内部链接转换为 <RouterLink>
。你可以把该选项设置为 'a'
来禁用这个功能。
类型: Record<string, string>
默认值: { target: '_blank', rel: 'noopener noreferrer' }
详情:
为外部链接添加额外的属性。
类型: (str: string) => string
详情:
默认使用的 slugify 函数。
类型: TocPluginOptions | false
默认值:
const defaultOptions = {
+ level: [2, 3],
+};
+
import { defaultTheme } from "@vuepress/theme-default";
+
+export default {
+ theme: defaultTheme({
+ // set config here
+ }),
+};
+
Config of this section can be used as normal config, and can also be used in the locales option.
Type: boolean
Default: true
Details:
Enable color mode switching or not.
If set to true
, a button to switch color mode will be displayed in the navbar.
Also see:
Type: string
Default: /
Details:
Specify the path of the homepage.
This will be used for:
Type: false | (NavbarItem | NavbarGroup | string)[]
Default: []
Details:
Configuration of navbar.
Set to false
to disable navbar.
To configure the navbar items, you can set it to a navbar array, each item of which could be a NavbarItem
object, a NavbarGroup
object, or a string:
NavbarItem
object should have a text
field and a link
field, could have an optional activeMatch
field.NavbarGroup
object should have a text
field and a children
field. The children
field should be a navbar array, too.NavbarItem
object, using the page title as text
, and the page route path as link
.Example 1:
export default {
+ theme: defaultTheme({
+ navbar: [
+ // NavbarItem
+ {
+ text: "Foo",
+ link: "/foo/",
+ },
+ // NavbarGroup
+ {
+ text: "Group",
+ children: ["/group/foo.md", "/group/bar.md"],
+ },
+ // string - page file path
+ "/bar/README.md",
+ ],
+ }),
+};
+
export default {
+ theme: defaultTheme({
+ navbar: [
+ // nested group - max depth is 2
+ {
+ text: "Group",
+ children: [
+ {
+ text: "SubGroup",
+ children: ["/group/sub/foo.md", "/group/sub/bar.md"],
+ },
+ ],
+ },
+ // control when should the item be active
+ {
+ text: "Group 2",
+ children: [
+ {
+ text: "Always active",
+ link: "/",
+ // this item will always be active
+ activeMatch: "/",
+ },
+ {
+ text: "Active on /foo/",
+ link: "/not-foo/",
+ // this item will be active when current route path starts with /foo/
+ // regular expression is supported
+ activeMatch: "^/foo/",
+ },
+ ],
+ },
+ ],
+ }),
+};
+
Type: null | string
Details:
Specify the url of logo image.
The logo image will be displayed at the left end of the navbar.
Set to null
to disable logo.
Example:
export default {
+ theme: defaultTheme({
+ // public file path
+ logo: "/hero.png",
+ // url
+ logo: "https://vuejs.org/images/logo.png",
+ }),
+};
+
Type: null | string
Details:
Specify the url of logo image to be used in dark mode.
You can make use of this option if you want to use different logo config in dark mode.
Set to null
to disable logo in dark mode. Omit this option to use logo in dark mode.
Also see:
Type: string
Details:
Specify the repository url of your project.
This will be used as the link of the repository link, which will be displayed as the last item of the navbar.
export default {
+ theme: defaultTheme({
+ // If you set it in the form of \`organization/repository\`
+ // we will take it as a GitHub repo
+ repo: "vuejs/vuepress",
+ // You can also set it to a URL directly
+ repo: "https://gitlab.com/foo/bar",
+ }),
+};
+
Type: string
Details:
Specify the repository label of your project.
This will be used as the text of the repository link, which will be displayed as the last item of the navbar.
If you don't set this option explicitly, it will be automatically inferred from the repo option.
Type: string
Details:
Specify the aria-label
attribute of the select language menu.
This is mainly for a11y purpose.
Type: string
Details:
Specify the name of the language of a locale.
This option will only take effect inside the locales of your theme config. It will be used as the language name of the locale, which will be displayed in the select language menu.
Example:
export default {
+ locales: {
+ "/": {
+ lang: "en-US",
+ },
+ "/zh/": {
+ lang: "zh-CN",
+ },
+ },
+ theme: defaultTheme({
+ locales: {
+ "/": {
+ selectLanguageName: "English",
+ },
+ "/zh/": {
+ selectLanguageName: "简体中文",
+ },
+ },
+ }),
+};
+
Set to false
to disable sidebar.
If you set it to 'auto'
, the sidebar will be automatically generated from the page headers.
To configure the sidebar items manually, you can set this option to a sidebar array, each item of which could be a SidebarItem
object or a string:
SidebarItem
object should have a text
field, could have an optional link
field, an optional children
field and an optional collapsible
field. The children
field should be a sidebar array. The collapsible
field controls whether the item is collapsible.SidebarItem
object, whose text
is the page title, link
is the page route path, and children
is automatically generated from the page headers.If you want to set different sidebar for different sub paths, you can set this option to a sidebar object:
export default {
+ theme: defaultTheme({
+ // sidebar array
+ // all pages will use the same sidebar
+ sidebar: [
+ // SidebarItem
+ {
+ text: "Foo",
+ link: "/foo/",
+ children: [
+ // SidebarItem
+ {
+ text: "github",
+ link: "https://github.com",
+ children: [],
+ },
+ // string - page file path
+ "/foo/bar.md",
+ ],
+ },
+ // string - page file path
+ "/bar/README.md",
+ ],
+ }),
+};
+
export default {
+ theme: defaultTheme({
+ // sidebar object
+ // pages under different sub paths will use different sidebar
+ sidebar: {
+ "/guide/": [
+ {
+ text: "Guide",
+ children: ["/guide/README.md", "/guide/getting-started.md"],
+ },
+ ],
+ "/reference/": [
+ {
+ text: "Reference",
+ children: ["/reference/cli.md", "/reference/config.md"],
+ },
+ ],
+ },
+ }),
+};
+
export default {
+ theme: defaultTheme({
+ // collapsible sidebar
+ sidebar: {
+ "/reference/": [
+ {
+ text: "VuePress Reference",
+ collapsible: true,
+ children: ["/reference/cli.md", "/reference/config.md"],
+ },
+ {
+ text: "Bundlers Reference",
+ collapsible: true,
+ children: [
+ "/reference/bundler/vite.md",
+ "/reference/bundler/webpack.md",
+ ],
+ },
+ ],
+ },
+ }),
+};
+
Details:
Set the maximum depth of the sidebar children which are automatically generated from the page headers.
0
to disable all levels of headers.1
to include <h2>
headers.2
to include <h2>
and <h3>
headers.Type: string
Default: 'Edit this page'
Details:
Specify the text of the edit this page link.
Type: string
Details:
Specify the pattern of the edit this page link.
This will be used for generating the edit this page link.
If you don't set this option, the pattern will be inferred from the docsRepo option. But if your documentation repository is not hosted on a common platform, for example, GitHub, GitLab, Bitbucket, Gitee, etc., you have to set this option explicitly to make the edit this page link work.
Usage:
Pattern | Description |
---|---|
:repo | The docs repo url, i.e. docsRepo |
:branch | The docs repo branch, i.e. docsBranch |
:path | The path of the page source file, i.e. docsDir joins the relative path of the page file |
Example:
export default {
+ theme: defaultTheme({
+ docsRepo: "https://gitlab.com/owner/name",
+ docsBranch: "master",
+ docsDir: "docs",
+ editLinkPattern: ":repo/-/edit/:branch/:path",
+ }),
+};
+
The generated link will look like 'https://gitlab.com/owner/name/-/edit/master/docs/path/to/file.md'
.
Type: string
Details:
Specify the repository url of your documentation source files.
This will be used for generating the edit this page link.
If you don't set this option, it will use the repo option by default. But if your documentation source files are in a different repository, you will need to set this option.
Type: string
Default: 'main'
Details:
Specify the repository branch of your documentation source files.
This will be used for generating the edit this page link.
Type: string
Default: ''
Details:
Specify the directory of your documentation source files in the repository.
This will be used for generating the edit this page link.
Type: string
Default: 'Last Updated'
Details:
Specify the text of the last updated timestamp label.
Type: string
Default: 'Contributors'
Details:
Specify the text of the contributors list label.
Type: string[]
Default: ['Not Found']
Details:
Specify the messages of the 404 page.
The message will be randomly picked from the array when users enter the 404 page.
Type: string
Default: 'Back to home'
Details:
Specify the text of the back to home link in the 404 page.
Type: string
Default: 'toggle color mode'
Details:
Title text for the color mode toggle button.
This is mainly for a11y purpose.
Also see:
Type: string
Default: 'toggle sidebar'
Details:
Title text for sidebar toggle button.
This is mainly for a11y purpose.
Details:
Configure the plugins that used by default theme.
Default theme is using some plugins by default. You can disable a plugin if you really do not want to use it. Make sure you understand what the plugin is for before disabling it.
ContainerType
type is:
tip
warning
danger
details
codeGroup
codeGroupItem
Without any configuration, the VuePress site is pretty minimal. To customize your site, let’s first create a .vuepress
directory inside your docs directory. This is where all VuePress-specific files will be placed. Your project structure is probably like this:
├─ docs
+│ ├─ .vuepress
+│ │ └─ config.js
+│ └─ README.md
+├─ .gitignore
+└─ package.json
+
The essential file for configuring a VuePress site is .vuepress/config.js
, while TypeScript config file is also supported. You can use .vuepress/config.ts
instead to get better types hint for VuePress config.
To be more specific, we have a convention for config file paths (in order of precedence):
cwd
: vuepress.config.ts
vuepress.config.js
vuepress.config.mjs
sourceDir
: .vuepress/config.ts
.vuepress/config.js
.vuepress/config.mjs
vuepress dev docs --config my-config.js
+
A basic config file looks like this:
import { defineUserConfig } from "vuepress";
+
+export default defineUserConfig({
+ lang: "en-US",
+ title: "Hello VuePress",
+ description: "Just playing around",
+});
+
In most cases, the config file is sufficient to configure your VuePress site. However, sometimes users may want to add some client-side code directly. To help with this, VuePress also supports a client config file:
├─ docs
+│ ├─ .vuepress
+│ │ ├─ client.js <--- client config file
+│ │ └─ config.js <--- config file
+│ └─ README.md
+├─ .gitignore
+└─ package.json
+
Similarly, we also have a convention for client config file paths (in order of precedence):
cwd
: vuepress.client.ts
vuepress.client.js
vuepress.client.mjs
sourceDir
: .vuepress/client.ts
.vuepress/client.js
.vuepress/client.mjs
A basic client config file looks like this:
import { defineClientConfig } from "@vuepress/client";
+
+export default defineClientConfig({
+ enhance({ app, router, siteData }) {},
+ setup() {},
+ rootComponents: [],
+});
+
如果没有任何配置,你的 VuePress 站点仅有一些最基础的功能。为了更好地自定义你的网站,让我们首先在你的文档目录下创建一个 .vuepress
目录,所有 VuePress 相关的文件都将会被放在这里。你的项目结构可能是这样:
├─ docs
+│ ├─ .vuepress
+│ │ └─ config.js
+│ └─ README.md
+├─ .gitignore
+└─ package.json
+
VuePress 站点的基本配置文件是 .vuepress/config.js
,但也同样支持 TypeScript 配置文件。你可以使用 .vuepress/config.ts
来得到更好的类型提示。
具体而言,我们对于配置文件的路径有着约定(按照优先顺序):
cwd
下: vuepress.config.ts
vuepress.config.js
vuepress.config.mjs
sourceDir
下: .vuepress/config.ts
.vuepress/config.js
.vuepress/config.mjs
vuepress dev docs --config my-config.js
+
一个基础的配置文件是这样的:
import { defineUserConfig } from "vuepress";
+
+export default defineUserConfig({
+ lang: "zh-CN",
+ title: "你好, VuePress !",
+ description: "这是我的第一个 VuePress 站点",
+});
+
在大多数情况下,配置文件已经足够帮助你配置好你的 VuePress 站点。不过,有些时候用户们可能希望直接添加一些客户端代码。 VuePress 通过客户端配置文件来支持这种需求:
├─ docs
+│ ├─ .vuepress
+│ │ ├─ client.js <--- 客户端配置文件
+│ │ └─ config.js <--- 配置文件
+│ └─ README.md
+├─ .gitignore
+└─ package.json
+
同样的,我们也有关于客户端配置文件的路径约定(按照优先顺序):
cwd
下: vuepress.client.ts
vuepress.client.js
vuepress.client.mjs
sourceDir
下: .vuepress/client.ts
.vuepress/client.js
.vuepress/client.mjs
一个基础的客户端配置文件是这样的:
import { defineClientConfig } from "@vuepress/client";
+
+export default defineClientConfig({
+ enhance({ app, router, siteData }) {},
+ setup() {},
+ rootComponents: [],
+});
+
npm i -D @vuepress/plugin-container@next
+
import { containerPlugin } from "@vuepress/plugin-container";
+
+export default {
+ plugins: [
+ containerPlugin({
+ // options
+ }),
+ ],
+};
+
::: <type> [info]
+[content]
+
+:::
+
type
is required and should be specified via type option.info
is optional, and the default value can be specified via defaultInfo
in locales option.content
can be any valid markdown content.Tips
This plugin can be used multiple times to support different types of containers.
Type: Record<string, { defaultInfo: string }>
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 option.
Example:
export default {
+ plugins: [
+ containerPlugin({
+ type: "tip",
+ locales: {
+ "/": {
+ defaultInfo: "TIP",
+ },
+ "/zh/": {
+ defaultInfo: "提示",
+ },
+ },
+ }),
+ ],
+};
+
Type: (info: string) => string
Default:
(info: string): string =>
+ \`<div class="custom-container \${type}">\${
+ info ? \`<p class="custom-container-title">\${info}</p>\` : ""
+ }\\n\`;
+
Details:
A function to render the starting tag of the container.
The first param is the info
part of container syntax.
This option will not take effect if you don't specify the after option.
Type: (info: string) => string
Default:
(): string => "</div>\\n";
+
Details:
A function to render the ending tag of the container.
The first param is the info
part of container syntax.
This option will not take effect if you don't specify the before option.
type MarkdownItContainerRenderFunction = (
+ tokens: Token[],
+ index: number,
+ options: any,
+ env: MarkdownEnv,
+ self: Renderer
+) => string;
+
npm i -D @vuepress/plugin-container@next
+
import { containerPlugin } from "@vuepress/plugin-container";
+
+export default {
+ plugins: [
+ containerPlugin({
+ // 配置项
+ }),
+ ],
+};
+
::: <type> [info]
+[content]
+
+:::
+
type
是必需的,应通过 type 配置项来指定。info
是可选的,其默认值可以通过 locales 的 defaultInfo
配置项来指定。content
可是任何合法的 Markdown 内容。提示
该插件可以被多次使用,以便支持不同类型的容器。
类型: Record<string, { defaultInfo: string }>
详情:
容器在不同 locales 下的默认 info
。
如果没有指定该配置项,默认 info
会使用大写的 type 。
示例:
export default {
+ plugins: [
+ containerPlugin({
+ type: "tip",
+ locales: {
+ "/": {
+ defaultInfo: "TIP",
+ },
+ "/zh/": {
+ defaultInfo: "提示",
+ },
+ },
+ }),
+ ],
+};
+
类型: (info: string) => string
默认值:
(info: string): string =>
+ \`<div class="custom-container \${type}">\${
+ info ? \`<p class="custom-container-title">\${info}</p>\` : ""
+ }\\n\`;
+
类型: (info: string) => string
默认值:
(): string => "</div>\\n";
+
type MarkdownItContainerRenderFunction = (
+ tokens: Token[],
+ index: number,
+ options: any,
+ env: MarkdownEnv,
+ self: Renderer
+) => string;
+
In the packages
directory:
bundler-vite
: The VuePress bundler package with vite. Use vite to dev
and build
VuePress app that generated by @vuepress/core
.bundler-webpack
: The VuePress bundler package with webpack. Use webpack to dev
and build
VuePress app that generated by @vuepress/core
.cli
: The VuePress command line interface (CLI) package. It will resolve user config file, and create VuePress app with @vuepress/core
, then execute corresponding command.client
: The VuePress client package. Provides the client entry, and exports types and composable utils that can be used in client side development.core
: The VuePress core. Provides pure Node API to generate VuePress app, including page handling, plugin system and data preparation.markdown
: The VuePress markdown package. Use markdown-it
as the markdown parser and integrate some plugins to be used in VuePress.shared
: Utilities that shared between node side and client side.utils
: Utilities that should only be used in node side.In the ecosystem
directory:
plugin-${name}
: Official plugins.theme-default
: The default theme.vuepress
: A wrapper of vuepress-vite
.vuepress-vite
: A wrapper of @vuepress/cli
+ @vuepress/bundler-vite
+ @vuepress/theme-default
. If users want to use default theme with vite, they can simply install this package.vuepress-webpack
: A wrapper of @vuepress/cli
+ @vuepress/bundler-webpack
+ @vuepress/theme-default
. If users want to use default theme with webpack, they can simply install this package.Pre-requirement:
',6),b={href:"http://nodejs.org",target:"_blank",rel:"noopener noreferrer"},f=o("strong",null,"version 14.18.0+",-1),v={href:"https://pnpm.io/",target:"_blank",rel:"noopener noreferrer"},g=o("strong",null,"version 7+",-1),_=n(`Clone the repo, and install dependencies:
pnpm install
+
Build source code:
pnpm build
+
Start developing the documentation site:
pnpm docs:dev
+
Main tools that used in this project:
`,7),w={href:"https://www.typescriptlang.org/",target:"_blank",rel:"noopener noreferrer"},k={href:"https://vitest.dev/",target:"_blank",rel:"noopener noreferrer"},y={href:"https://eslint.org/",target:"_blank",rel:"noopener noreferrer"},x={href:"https://prettier.io/",target:"_blank",rel:"noopener noreferrer"},P=n('pnpm build
The build
script uses tsc
and tsup
to compile TypeScript source files to JavaScript dist files.
Also, it will copy necessary resources from source directory to dist directory, because some source files (e.g. .vue
, .css
files) would not be processed by tsc
nor tsup
, but should keep the same relative path in the dist directory.
You may need to run this script first after your clone this repository, because the dist files are ignored by .gitignore
.
pnpm clean
The clean
script runs clean
script in all packages, cleaning all the dist files and caches. In other words, it will remove all the files that generated by build
, copy
scripts.
It's used before you want to re-build source files from a clean / initial state.
pnpm docs:*
pnpm docs:build
, pnpm docs:dev
, pnpm docs:clean
The docs:
prefix indicates that these scripts are for documentation, i.e. the docs
directory.
VuePress is using itself to build its own documentation site.
You need to run pnpm build
to build VuePress source files first, then run these docs:
scripts to develop and build our documentation.
pnpm docs:serve
Serve the documentation site locally.
You need to run pnpm docs:build
first to generate the documentation dist files, and then run pnpm docs:serve
to serve them.
pnpm lint
The lint
script uses ESLint to check all source files.
pnpm test
The test
script uses Vitest to run unit testings.
VuePress documentation is powered by VuePress itself, which is built from the source code of this repository.
All the markdown source files are placed in docs
directory. We are maintaining two translations:
/
path/zh/
pathWe have two different deployments:
',25),V={href:"https://www.netlify.com",target:"_blank",rel:"noopener noreferrer"},T={href:"https://v2.vuepress.vuejs.org",target:"_blank",rel:"noopener noreferrer"},I={href:"https://pages.github.com",target:"_blank",rel:"noopener noreferrer"},S={href:"https://vuepress.github.io",target:"_blank",rel:"noopener noreferrer"};function N(A,C){const t=a("ExternalLinkIcon");return r(),i("div",null,[l,p,o("p",null,[e("This repository employs a "),o("a",h,[e("monorepo"),s(t)]),e(" setup with "),o("a",u,[e("pnpm workspaces"),s(t)]),e(", and hosts a number of associated but separated packages.")]),m,o("ul",null,[o("li",null,[o("a",b,[e("Node.js"),s(t)]),e(),f]),o("li",null,[o("a",v,[e("pnpm"),s(t)]),e(),g])]),_,o("ul",null,[o("li",null,[o("a",w,[e("TypeScript"),s(t)]),e(" as the development language")]),o("li",null,[o("a",k,[e("Vitest"),s(t)]),e(" for unit testing")]),o("li",null,[o("a",y,[e("ESLint"),s(t)]),e(" + "),o("a",x,[e("Prettier"),s(t)]),e(" for code linting and formatting")])]),P,o("ul",null,[o("li",null,[e("Release deployment powered by "),o("a",V,[e("Netlify"),s(t)]),e(". This deployment is built from the latest released version, so users will not see unreleased changes. The domain name is "),o("a",T,[e("https://v2.vuepress.vuejs.org"),s(t)]),e(".")]),o("li",null,[e("Developer deployment powered by "),o("a",I,[e("GitHub Pages"),s(t)]),e(". This deployment is built from the latest commit, so developers could preview the latest changes. The domain name is "),o("a",S,[e("https://vuepress.github.io"),s(t)]),e(".")])])])}const U=d(c,[["render",N],["__file","contributing.html.vue"]]);export{U as default}; diff --git a/assets/contributing.html-6dc0f72e.js b/assets/contributing.html-6dc0f72e.js new file mode 100644 index 00000000..2e60f250 --- /dev/null +++ b/assets/contributing.html-6dc0f72e.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-e012c1f2","path":"/zh/contributing.html","title":"贡献指南","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:signs-post","sidebar":"auto","description":"概览 项目仓库借助于 pnpm 工作空间 (https://pnpm.io/zh/workspaces) 来实现 Monorepo (https://en.wikipedia.org/wiki/Monorepo) ,存放了多个互相关联的独立 Package 。 在 packages 目录下: bundler-vite: 基于 Vite 的 Bundle...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/contributing.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/contributing.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"贡献指南"}],["meta",{"property":"og:description","content":"概览 项目仓库借助于 pnpm 工作空间 (https://pnpm.io/zh/workspaces) 来实现 Monorepo (https://en.wikipedia.org/wiki/Monorepo) ,存放了多个互相关联的独立 Package 。 在 packages 目录下: bundler-vite: 基于 Vite 的 Bundle..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"贡献指南\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"概览","slug":"概览","link":"#概览","children":[]},{"level":2,"title":"开发配置","slug":"开发配置","link":"#开发配置","children":[]},{"level":2,"title":"开发脚本","slug":"开发脚本","link":"#开发脚本","children":[{"level":3,"title":"pnpm build","slug":"pnpm-build","link":"#pnpm-build","children":[]},{"level":3,"title":"pnpm clean","slug":"pnpm-clean","link":"#pnpm-clean","children":[]},{"level":3,"title":"pnpm docs:*","slug":"pnpm-docs","link":"#pnpm-docs","children":[]},{"level":3,"title":"pnpm lint","slug":"pnpm-lint","link":"#pnpm-lint","children":[]},{"level":3,"title":"pnpm test","slug":"pnpm-test","link":"#pnpm-test","children":[]}]},{"level":2,"title":"文档","slug":"文档","link":"#文档","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":3.46,"words":1038},"filePathRelative":"zh/contributing.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/contributing.html-e03745b5.js b/assets/contributing.html-e03745b5.js new file mode 100644 index 00000000..15cb7b17 --- /dev/null +++ b/assets/contributing.html-e03745b5.js @@ -0,0 +1,4 @@ +import{_ as r,W as a,X as s,$ as o,a0 as e,Y as n,a1 as c,D as t}from"./framework-46b0e263.js";const i={},p=o("h1",{id:"贡献指南",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#贡献指南","aria-hidden":"true"},"#"),e(" 贡献指南")],-1),l=o("h2",{id:"概览",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#概览","aria-hidden":"true"},"#"),e(" 概览")],-1),h={href:"https://pnpm.io/zh/workspaces",target:"_blank",rel:"noopener noreferrer"},u={href:"https://en.wikipedia.org/wiki/Monorepo",target:"_blank",rel:"noopener noreferrer"},b=c('在 packages
目录下:
bundler-vite
: 基于 Vite 的 Bundler 模块。使用 Vite 对 VuePress App 执行 dev
和 build
操作。bundler-webpack
: 基于 Webpack 的 Bundler 模块。使用 Webpack 对 VuePress App 执行 dev
和 build
操作。cli
: 命令行接口 (CLI) 模块。包含解析用户配置文件、调用 @vuepress/core
创建 VuePress App 、执行对应命令等功能。client
: Client 模块。包含客户端页面入口,并提供了客户端开发时可以用到的类型和工具函数。core
: Core 模块。提供 Node API 来创建 VuePress App ,包括页面逻辑、插件系统、数据准备等功能。markdown
: Markdown 模块。使用 markdown-it
作为 Markdown 解析器,并集成了一些 VuePress 中用到的插件。shared
: 既可以在 Node 端使用、也可以在客户端使用的工具函数模块。utils
: 仅可以在 Node 端使用的工具函数模块。在 ecosystem
目录下:
plugin-${name}
: 官方插件。theme-default
: 默认主题。vuepress
: 是 vuepress-vite
的封装。vuepress-vite
: 是 @vuepress/cli
+ @vuepress/bundler-vite
+ @vuepress/theme-default
的封装。如果用户想使用 默认主题 + Vite ,仅安装这个 Package 就可以了。vuepress-webpack
: 是 @vuepress/cli
+ @vuepress/bundler-webpack
+ @vuepress/theme-default
的封装。如果用户想使用 默认主题 + Webpack ,仅安装这个 Package 就可以了。开发要求:
',6),m={href:"http://nodejs.org",target:"_blank",rel:"noopener noreferrer"},_=o("strong",null,"version 14.18.0+",-1),v={href:"https://pnpm.io/zh/",target:"_blank",rel:"noopener noreferrer"},f=o("strong",null,"version 7+",-1),g=c(`克隆代码仓库,并安装依赖:
pnpm install
+
构建源代码:
pnpm build
+
开始开发项目文档网站:
pnpm docs:dev
+
本项目开发使用的一些主要工具:
`,7),k={href:"https://www.typescriptlang.org/",target:"_blank",rel:"noopener noreferrer"},x={href:"https://vitest.dev/",target:"_blank",rel:"noopener noreferrer"},V={href:"https://eslint.org/",target:"_blank",rel:"noopener noreferrer"},w={href:"https://prettier.io/",target:"_blank",rel:"noopener noreferrer"},P=c('pnpm build
build
命令会使用 tsc
和 tsup
将 TypeScript 源文件编译为 JavaScript 文件。
此外,它还会将必要的资源文件从源文件目录复制到输出目录。这是因为一些资源文件不会被 tsc
或 tsup
处理,但它们仍需要被放置到输出目录,并保持它们的项目对路径不变。
你在克隆代码仓库后,可能需要先执行该命令来确保项目代码可以顺利运行,因为编译后的输出目录被 .gitignore
排除在仓库以外了。
pnpm clean
clean
命令会执行所有子 Package 中的 clean
命令,清除所有的输出文件目录和缓存文件。换言之,它将移除所有通过 build
和 copy
命令生成的文件。
当你想要从最初状态重新构建源代码时,你可以执行该命令。
pnpm docs:*
pnpm docs:build
, pnpm docs:dev
, pnpm docs:clean
docs:
前缀表明,这些命令是针对文档 (documentation) 进行操作的,即 docs
目录。
VuePress 使用它自己来构建自己的文档网站。
你需要先执行 pnpm build
来构建 VuePress 源代码,然后再运行这些 docs:
开头的命令来开发或构建文档。
pnpm docs:serve
在本地启动文档网站服务器。
你需要先运行 pnpm docs:build
来生成文档网站的输出文件,然后再通过该命令来启动文档网站。
pnpm lint
lint
命令使用 ESLint 来检查所有源文件。
pnpm test
test
命令使用 Vitest 来运行单元测试。
VuePress 的文档是由 VuePress 自己驱动的,是由该仓库中的源码构建而来。
所有的 Markdown 源文件都放置在 docs
目录下。我们维护了两种翻译:
/
路径下/zh/
路径下我们部署了两套站点:
',25),N={href:"https://www.netlify.com",target:"_blank",rel:"noopener noreferrer"},y={href:"https://v2.vuepress.vuejs.org",target:"_blank",rel:"noopener noreferrer"},S={href:"https://pages.github.com",target:"_blank",rel:"noopener noreferrer"},A={href:"https://vuepress.github.io",target:"_blank",rel:"noopener noreferrer"};function B(C,E){const d=t("ExternalLinkIcon");return a(),s("div",null,[p,l,o("p",null,[e("项目仓库借助于 "),o("a",h,[e("pnpm 工作空间"),n(d)]),e(" 来实现 "),o("a",u,[e("Monorepo"),n(d)]),e(" ,存放了多个互相关联的独立 Package 。")]),b,o("ul",null,[o("li",null,[o("a",m,[e("Node.js"),n(d)]),e(),_]),o("li",null,[o("a",v,[e("pnpm"),n(d)]),e(),f])]),g,o("ul",null,[o("li",null,[o("a",k,[e("TypeScript"),n(d)]),e(" 作为开发语言")]),o("li",null,[o("a",x,[e("Vitest"),n(d)]),e(" 用于单元测试")]),o("li",null,[o("a",V,[e("ESLint"),n(d)]),e(" + "),o("a",w,[e("Prettier"),n(d)]),e(" 用于代码检查和格式化")])]),P,o("ul",null,[o("li",null,[e("在 "),o("a",N,[e("Netlify"),n(d)]),e(" 部署的 Release 版本。该站点是从最新发布的版本中构建而来,因此用户不会看到未发布的改动。域名为 "),o("a",y,[e("https://v2.vuepress.vuejs.org"),n(d)]),e("。")]),o("li",null,[e("在 "),o("a",S,[e("GitHub Pages"),n(d)]),e(" 部署的 Developer 版本。该站点是从最新的提交中构建而来,因此开发者可以预览最新的改动。域名为 "),o("a",A,[e("https://vuepress.github.io"),n(d)]),e("。")])])])}const M=r(i,[["render",B],["__file","contributing.html.vue"]]);export{M as default}; diff --git a/assets/contributing.html-f20968df.js b/assets/contributing.html-f20968df.js new file mode 100644 index 00000000..aa0c809b --- /dev/null +++ b/assets/contributing.html-f20968df.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6ce48554","path":"/contributing.html","title":"Contributing Guide","lang":"en-US","frontmatter":{"icon":"fa6-solid:signs-post","sidebar":"auto","description":"Overview This repository employs a monorepo (https://en.wikipedia.org/wiki/Monorepo) setup with pnpm workspaces (https://pnpm.io/workspaces), and hosts a number of associated bu...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/contributing.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/contributing.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Contributing Guide"}],["meta",{"property":"og:description","content":"Overview This repository employs a monorepo (https://en.wikipedia.org/wiki/Monorepo) setup with pnpm workspaces (https://pnpm.io/workspaces), and hosts a number of associated bu..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Contributing Guide\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Overview","slug":"overview","link":"#overview","children":[]},{"level":2,"title":"Development Setup","slug":"development-setup","link":"#development-setup","children":[]},{"level":2,"title":"Scripts","slug":"scripts","link":"#scripts","children":[{"level":3,"title":"pnpm build","slug":"pnpm-build","link":"#pnpm-build","children":[]},{"level":3,"title":"pnpm clean","slug":"pnpm-clean","link":"#pnpm-clean","children":[]},{"level":3,"title":"pnpm docs:*","slug":"pnpm-docs","link":"#pnpm-docs","children":[]},{"level":3,"title":"pnpm lint","slug":"pnpm-lint","link":"#pnpm-lint","children":[]},{"level":3,"title":"pnpm test","slug":"pnpm-test","link":"#pnpm-test","children":[]}]},{"level":2,"title":"Documentation","slug":"documentation","link":"#documentation","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.34,"words":702},"filePathRelative":"contributing.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/deployment.html-24cc7f5b.js b/assets/deployment.html-24cc7f5b.js new file mode 100644 index 00000000..1e67119e --- /dev/null +++ b/assets/deployment.html-24cc7f5b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4a7b6bf9","path":"/zh/guide/deployment.html","title":"部署","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:rocket","description":"下述的指南基于以下条件: Markdown 源文件放置在你项目的 docs 目录;; 使用的是默认的构建输出目录 (.vuepress/dist) ;; 使用 pnpm (https://pnpm.io/zh/) 作为包管理器,当然也支持使用 npm 或 yarn 。; VuePress 作为项目依赖安装,并在 package.json 中配置了如下脚...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/deployment.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/deployment.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"部署"}],["meta",{"property":"og:description","content":"下述的指南基于以下条件: Markdown 源文件放置在你项目的 docs 目录;; 使用的是默认的构建输出目录 (.vuepress/dist) ;; 使用 pnpm (https://pnpm.io/zh/) 作为包管理器,当然也支持使用 npm 或 yarn 。; VuePress 作为项目依赖安装,并在 package.json 中配置了如下脚..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"部署\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"GitHub Pages","slug":"github-pages","link":"#github-pages","children":[]},{"level":2,"title":"GitLab Pages","slug":"gitlab-pages","link":"#gitlab-pages","children":[]},{"level":2,"title":"Google Firebase","slug":"google-firebase","link":"#google-firebase","children":[]},{"level":2,"title":"Heroku","slug":"heroku","link":"#heroku","children":[]},{"level":2,"title":"Kinsta","slug":"kinsta","link":"#kinsta","children":[]},{"level":2,"title":"Edgio","slug":"edgio","link":"#edgio","children":[]},{"level":2,"title":"Netlify","slug":"netlify","link":"#netlify","children":[]},{"level":2,"title":"Vercel","slug":"vercel","link":"#vercel","children":[]},{"level":2,"title":"云开发 CloudBase","slug":"云开发-cloudbase","link":"#云开发-cloudbase","children":[]},{"level":2,"title":"21 云盒子","slug":"_21-云盒子","link":"#_21-云盒子","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":4.36,"words":1309},"filePathRelative":"zh/guide/deployment.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/deployment.html-355f7597.js b/assets/deployment.html-355f7597.js new file mode 100644 index 00000000..4cc71223 --- /dev/null +++ b/assets/deployment.html-355f7597.js @@ -0,0 +1,101 @@ +import{_ as c,W as p,X as u,$ as n,a0 as s,Y as e,Z as l,a1 as t,D as i}from"./framework-46b0e263.js";const r={},d=n("h1",{id:"deployment",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#deployment","aria-hidden":"true"},"#"),s(" Deployment")],-1),k=n("p",null,"The following guides are based on some shared assumptions:",-1),m=n("li",null,[s("You are placing your Markdown source files inside the "),n("code",null,"docs"),s(" directory of your project;")],-1),v=n("li",null,[s("You are using the default build output location ("),n("code",null,".vuepress/dist"),s(");")],-1),h={href:"https://pnpm.io",target:"_blank",rel:"noopener noreferrer"},b=n("li",null,[s("VuePress is installed as a local dependency in your project, and you have setup the following script in "),n("code",null,"package.json"),s(":")],-1),g=t(`{
+ "scripts": {
+ "docs:build": "vuepress build docs"
+ }
+}
+
If you are deploying to https://<USERNAME>.github.io/
, you can omit this step as base
defaults to "/"
.
If you are deploying to https://<USERNAME>.github.io/<REPO>/
, for example your repository is at https://github.com/<USERNAME>/<REPO>
, then set base
to "/<REPO>/"
.
name: docs
+
+on:
+ # trigger deployment on every push to main branch
+ push:
+ branches: [main]
+ # trigger deployment manually
+ workflow_dispatch:
+
+jobs:
+ docs:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ # fetch all commits to get last updated time or other git log info
+ fetch-depth: 0
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ # choose pnpm version to use
+ version: 7
+ # install deps with pnpm
+ run_install: true
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ # choose node.js version to use
+ node-version: 18
+ # cache deps for pnpm
+ cache: pnpm
+
+ # run build script
+ - name: Build VuePress site
+ run: pnpm docs:build
+
+ # please check out the docs of the workflow for more details
+ # @see https://github.com/crazy-max/ghaction-github-pages
+ - name: Deploy to GitHub Pages
+ uses: crazy-max/ghaction-github-pages@v2
+ with:
+ # deploy to gh-pages branch
+ target_branch: gh-pages
+ # deploy the default output dir of VuePress
+ build_dir: docs/.vuepress/dist
+ env:
+ # @see https://docs.github.com/en/actions/reference/authentication-in-a-workflow#about-the-github_token-secret
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
If you are deploying to https://<USERNAME>.gitlab.io/
, you can omit base
as it defaults to "/"
.
If you are deploying to https://<USERNAME>.gitlab.io/<REPO>/
, for example your repository is at https://gitlab.com/<USERNAME>/<REPO>
, then set base
to "/<REPO>/"
.
# choose a docker image to use
+image: node:18-buster
+
+pages:
+ # trigger deployment on every push to main branch
+ only:
+ - main
+
+ # cache node_modules
+ cache:
+ key:
+ files:
+ - pnpm-lock.yaml
+ paths:
+ - .pnpm-store
+
+ # Install pnpm
+ before_script:
+ - curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7
+ - pnpm config set store-dir .pnpm-store
+
+ # install dependencies and run build script
+ script:
+ - pnpm i --frozen-lockfile
+ - pnpm docs:build --dest public
+
+ artifacts:
+ paths:
+ - public
+
firebase.json
:
{
+ "hosting": {
+ "public": "./docs/.vuepress/dist",
+ "ignore": []
+ }
+}
+
.firebaserc
:
{
+ "projects": {
+ "default": "<YOUR_FIREBASE_ID>"
+ }
+}
+
pnpm docs:build
, deploy using the command firebase deploy
.heroku login
+
static.json
in the root of your project with the below content:static.json
:
{
+ "root": "./docs/.vuepress/dist"
+}
+
{
+ "scripts": {
+ "docs:build": "vuepress build docs"
+ }
+}
+
如果你准备发布到 https://<USERNAME>.github.io/
,你可以省略这一步,因为 base
默认就是 "/"
。
如果你准备发布到 https://<USERNAME>.github.io/<REPO>/
,也就是说你的仓库地址是 https://github.com/<USERNAME>/<REPO>
,则将 base
设置为 "/<REPO>/"
。
name: docs
+
+on:
+ # 每当 push 到 main 分支时触发部署
+ push:
+ branches: [main]
+ # 手动触发部署
+ workflow_dispatch:
+
+jobs:
+ docs:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ # “最近更新时间” 等 git 日志相关信息,需要拉取全部提交记录
+ fetch-depth: 0
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ # 选择要使用的 pnpm 版本
+ version: 7
+ # 使用 pnpm 安装依赖
+ run_install: true
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ # 选择要使用的 node 版本
+ node-version: 18
+ # 缓存 pnpm 依赖
+ cache: pnpm
+
+ # 运行构建脚本
+ - name: Build VuePress site
+ run: pnpm docs:build
+
+ # 查看 workflow 的文档来获取更多信息
+ # @see https://github.com/crazy-max/ghaction-github-pages
+ - name: Deploy to GitHub Pages
+ uses: crazy-max/ghaction-github-pages@v2
+ with:
+ # 部署到 gh-pages 分支
+ target_branch: gh-pages
+ # 部署目录为 VuePress 的默认输出目录
+ build_dir: docs/.vuepress/dist
+ env:
+ # @see https://docs.github.com/cn/actions/reference/authentication-in-a-workflow#about-the-github_token-secret
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
如果你准备发布到 https://<USERNAME>.gitlab.io/
,你可以省略这一步,因此 base
默认就是 "/"
。
如果你准备发布到 https://<USERNAME>.gitlab.io/<REPO>/
,也就是说你的仓库地址是 https://gitlab.com/<USERNAME>/<REPO>
,则将 base
设置为 "/<REPO>/"
。
# 选择你要使用的 docker 镜像
+image: node:18-buster
+
+pages:
+ # 每当 push 到 main 分支时触发部署
+ only:
+ - main
+
+ # 缓存 node_modules
+ cache:
+ key:
+ files:
+ - pnpm-lock.yaml
+ paths:
+ - .pnpm-store
+
+ # 安装 pnpm
+ before_script:
+ - curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7
+ - pnpm config set store-dir .pnpm-store
+
+ # 安装依赖并运行构建脚本
+ script:
+ - pnpm install --frozen-lockfile
+ - pnpm docs:build --dest public
+
+ artifacts:
+ paths:
+ - public
+
firebase.json
:
{
+ "hosting": {
+ "public": "./docs/.vuepress/dist",
+ "ignore": []
+ }
+}
+
.firebaserc
:
{
+ "projects": {
+ "default": "<YOUR_FIREBASE_ID>"
+ }
+}
+
pnpm docs:build
后, 使用 firebase deploy
指令来部署。heroku login
+
static.json
的文件,并包含下述内容:static.json
:
{
+ "root": "./docs/.vuepress/dist"
+}
+
pnpm install -g @cloudbase/cli
+
cloudbase init --without-template
+cloudbase framework:deploy
+
CloudBase CLI 首先会跳转到控制台进行登录授权,然后将会交互式进行确认。
确认信息后会立即进行部署,部署完成后,可以获得一个自动 SSL,CDN 加速的网站应用,你也可以搭配使用 GitHub Action 来持续部署 GitHub 上的 VuePress 应用。
也可以使用 cloudbase init --template vuepress
快速创建和部署一个新的 VuePress 应用。
Tips
Default theme will add DocSearch to the navbar once you configure this plugin correctly.
This plugin may not be used directly in other themes, so you'd better refer to the documentation of your theme for more details.
npm i -D @vuepress/plugin-docsearch@next
+
import { docsearchPlugin } from "@vuepress/plugin-docsearch";
+
+export default {
+ plugins: [
+ docsearchPlugin({
+ // options
+ }),
+ ],
+};
+
new Crawler({
+ appId: 'YOUR_APP_ID',
+ apiKey: 'YOUR_API_KEY',
+ rateLimit: 8,
+ startUrls: [
+ // These are urls which algolia start to craw
+ // If your site is divided in to mutiple parts,
+ // you may want to set mutiple entry links
+ 'https://YOUR_WEBSITE_URL/',
+ ],
+ sitemaps: [
+ // if you are using sitemap plugins (e.g.: vuepress-plugin-sitemap2), you may provide one
+ 'https://YOUR_WEBSITE_URL/sitemap.xml',
+ ],
+ ignoreCanonicalTo: false,
+ exclusionPatterns: [
+ // You can use this to stop algolia crawing some paths
+ ],
+ discoveryPatterns: [
+ // These are urls which algolia looking for,
+ 'https://YOUR_WEBSITE_URL/**',
+ ],
+ // Crawler schedule, set it according to your docs update frequency
+ schedule: 'at 02:00 every 1 day',
+ actions: [
+ // you may have mutiple actions, especially when you are deploying mutiple docs under one domain
+ {
+ // name the index with name you like
+ indexName: 'YOUR_INDEX_NAME',
+ // paths where the index take effect
+ pathsToMatch: ['https://YOUR_WEBSITE_URL/**'],
+ // controls how algolia extracts records from your site
+ recordExtractor: ({ $, helpers }) => {
+ // options for @vuepress/theme-default
+ return helpers.docsearch({
+ recordProps: {
+ lvl0: {
+ selectors: '.sidebar-heading.active',
+ defaultValue: 'Documentation',
+ },
+ lvl1: '.theme-default-content h1',
+ lvl2: '.theme-default-content h2',
+ lvl3: '.theme-default-content h3',
+ lvl4: '.theme-default-content h4',
+ lvl5: '.theme-default-content h5',
+ lvl6: '.theme-default-content h6',
+ content: '.theme-default-content p, .theme-default-content li',
+ },
+ indexHeadings: true,
+ })
+ },
+ },
+ ],
+ initialIndexSettings: {
+ // controls how index are initialized
+ // only has effects before index are initialize
+ // you may need to delete your index and recraw after modification
+ YOUR_INDEX_NAME: {
+ attributesForFaceting: ['type', 'lang'],
+ attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'],
+ attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'],
+ attributesToSnippet: ['content:10'],
+ camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'],
+ searchableAttributes: [
+ 'unordered(hierarchy_radio_camel.lvl0)',
+ 'unordered(hierarchy_radio.lvl0)',
+ 'unordered(hierarchy_radio_camel.lvl1)',
+ 'unordered(hierarchy_radio.lvl1)',
+ 'unordered(hierarchy_radio_camel.lvl2)',
+ 'unordered(hierarchy_radio.lvl2)',
+ 'unordered(hierarchy_radio_camel.lvl3)',
+ 'unordered(hierarchy_radio.lvl3)',
+ 'unordered(hierarchy_radio_camel.lvl4)',
+ 'unordered(hierarchy_radio.lvl4)',
+ 'unordered(hierarchy_radio_camel.lvl5)',
+ 'unordered(hierarchy_radio.lvl5)',
+ 'unordered(hierarchy_radio_camel.lvl6)',
+ 'unordered(hierarchy_radio.lvl6)',
+ 'unordered(hierarchy_camel.lvl0)',
+ 'unordered(hierarchy.lvl0)',
+ 'unordered(hierarchy_camel.lvl1)',
+ 'unordered(hierarchy.lvl1)',
+ 'unordered(hierarchy_camel.lvl2)',
+ 'unordered(hierarchy.lvl2)',
+ 'unordered(hierarchy_camel.lvl3)',
+ 'unordered(hierarchy.lvl3)',
+ 'unordered(hierarchy_camel.lvl4)',
+ 'unordered(hierarchy.lvl4)',
+ 'unordered(hierarchy_camel.lvl5)',
+ 'unordered(hierarchy.lvl5)',
+ 'unordered(hierarchy_camel.lvl6)',
+ 'unordered(hierarchy.lvl6)',
+ 'content',
+ ],
+ distinct: true,
+ attributeForDistinct: 'url',
+ customRanking: [
+ 'desc(weight.pageRank)',
+ 'desc(weight.level)',
+ 'asc(weight.position)',
+ ],
+ ranking: [
+ 'words',
+ 'filters',
+ 'typo',
+ 'attribute',
+ 'proximity',
+ 'exact',
+ 'custom',
+ ],
+ highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
+ highlightPostTag: '</span>',
+ minWordSizefor1Typo: 3,
+ minWordSizefor2Typos: 7,
+ allowTyposOnNumericTokens: false,
+ minProximity: 1,
+ ignorePlurals: true,
+ advancedSyntax: true,
+ attributeCriteriaComputedByMinProximity: true,
+ removeWordsIfNoResults: 'allOptional',
+ },
+ },
+})
+
The above recordProps
is the configuration used for the default theme. You can modify them according to the theme you are using.
Notice that the initialIndexSettings.YOUR_INDEX_NAME.attributesForFaceting
fields must include 'lang'
to make this plugin work properly.
Type: Record<string, DocsearchPluginOptions>
Details:
Options of this plugin in different locales.
All other options of this plugin are acceptable in locale config.
Example:
export default {
+ plugins: [
+ docsearchPlugin({
+ appId: "<APP_ID>",
+ apiKey: "<API_KEY>",
+ indexName: "<INDEX_NAME>",
+ locales: {
+ "/": {
+ placeholder: "Search Documentation",
+ translations: {
+ button: {
+ buttonText: "Search Documentation",
+ },
+ },
+ },
+ "/zh/": {
+ placeholder: "搜索文档",
+ translations: {
+ button: {
+ buttonText: "搜索文档",
+ },
+ },
+ },
+ },
+ }),
+ ],
+};
+
Type: boolean
Default: true
Details:
Whether to inject the default styles of DocSearch or not.
If you think the default styles of DocSearch is not compatible with your site, you can try to override the default styles, or set this option to false
to totally exclude the default styles.
When this option is disabled, you need to import your own styles for DocSearch. Also notice that all styles customization in Styles section would be unavailable.
:root {
+ --docsearch-primary-color: rgb(84, 104, 255);
+ --docsearch-text-color: rgb(28, 30, 33);
+ --docsearch-spacing: 12px;
+ --docsearch-icon-stroke-width: 1.4;
+ --docsearch-highlight-color: var(--docsearch-primary-color);
+ --docsearch-muted-color: rgb(150, 159, 175);
+ --docsearch-container-background: rgba(101, 108, 133, 0.8);
+ --docsearch-logo-color: rgba(84, 104, 255);
+
+ /* modal */
+ --docsearch-modal-width: 560px;
+ --docsearch-modal-height: 600px;
+ --docsearch-modal-background: rgb(245, 246, 247);
+ --docsearch-modal-shadow: inset 1px 1px 0 0 rgba(255, 255, 255, 0.5), 0 3px
+ 8px 0 rgba(85, 90, 100, 1);
+
+ /* searchbox */
+ --docsearch-searchbox-height: 56px;
+ --docsearch-searchbox-background: rgb(235, 237, 240);
+ --docsearch-searchbox-focus-background: #fff;
+ --docsearch-searchbox-shadow: inset 0 0 0 2px var(--docsearch-primary-color);
+
+ /* hit */
+ --docsearch-hit-height: 56px;
+ --docsearch-hit-color: rgb(68, 73, 80);
+ --docsearch-hit-active-color: #fff;
+ --docsearch-hit-background: #fff;
+ --docsearch-hit-shadow: 0 1px 3px 0 rgb(212, 217, 225);
+
+ /* key */
+ --docsearch-key-gradient: linear-gradient(
+ -225deg,
+ rgb(213, 219, 228) 0%,
+ rgb(248, 248, 248) 100%
+ );
+ --docsearch-key-shadow: inset 0 -2px 0 0 rgb(205, 205, 230), inset 0 0 1px 1px
+ #fff, 0 1px 2px 1px rgba(30, 35, 90, 0.4);
+
+ /* footer */
+ --docsearch-footer-height: 44px;
+ --docsearch-footer-background: #fff;
+ --docsearch-footer-shadow: 0 -1px 0 0 rgb(224, 227, 232), 0 -3px 6px 0 rgba(69, 98, 155, 0.12);
+}
+
Details:
This plugin will register a <Docsearch />
component globally, and you can use it without any props.
Put this component to where you want to place the docsearch button. For example, default theme puts this component to the end of the navbar.
Tips
This component is mainly used for theme development. You don't need to use it directly in most cases.
提示
当你正确配置该插件后,默认主题会把 DocSearch 按钮添加到导航栏。
该插件不一定能在其他主题中直接使用,因此你应参考主题本身的文档来获取更多信息。
npm i -D @vuepress/plugin-docsearch@next
+
import { docsearchPlugin } from "@vuepress/plugin-docsearch";
+
+export default {
+ plugins: [
+ docsearchPlugin({
+ // 配置项
+ }),
+ ],
+};
+
new Crawler({
+ appId: 'YOUR_APP_ID',
+ apiKey: 'YOUR_API_KEY',
+ rateLimit: 8,
+ startUrls: [
+ // 这是 Algolia 开始抓取网站的初始地址
+ // 如果你的网站被分为数个独立部分,你可能需要在此设置多个入口链接
+ 'https://YOUR_WEBSITE_URL/',
+ ],
+ sitemaps: [
+ // 如果你在使用 Sitemap 插件 (如: vuepress-plugin-sitemap2),你可以提供 Sitemap 链接
+ 'https://YOUR_WEBSITE_URL/sitemap.xml',
+ ],
+ ignoreCanonicalTo: false,
+ exclusionPatterns: [
+ // 你可以通过它阻止 Algolia 抓取某些 URL
+ ],
+ discoveryPatterns: [
+ // 这是 Algolia 抓取 URL 的范围
+ 'https://YOUR_WEBSITE_URL/**',
+ ],
+ // 爬虫执行的计划时间,可根据文档更新频率设置
+ schedule: 'at 02:00 every 1 day',
+ actions: [
+ // 你可以拥有多个 action,特别是你在一个域名下部署多个文档时
+ {
+ // 使用适当的名称为索引命名
+ indexName: 'YOUR_INDEX_NAME',
+ // 索引生效的路径
+ pathsToMatch: ['https://YOUR_WEBSITE_URL/**'],
+ // 控制 Algolia 如何抓取你的站点
+ recordExtractor: ({ $, helpers }) => {
+ // @vuepress/theme-default 的选项
+ return helpers.docsearch({
+ recordProps: {
+ lvl0: {
+ selectors: '.sidebar-heading.active',
+ defaultValue: 'Documentation',
+ },
+ lvl1: '.theme-default-content h1',
+ lvl2: '.theme-default-content h2',
+ lvl3: '.theme-default-content h3',
+ lvl4: '.theme-default-content h4',
+ lvl5: '.theme-default-content h5',
+ lvl6: '.theme-default-content h6',
+ content: '.theme-default-content p, .theme-default-content li',
+ },
+ indexHeadings: true,
+ })
+ },
+ },
+ ],
+ initialIndexSettings: {
+ // 控制索引如何被初始化,这仅当索引尚未生成时有效
+ // 你可能需要在修改后手动删除并重新生成新的索引
+ YOUR_INDEX_NAME: {
+ attributesForFaceting: ['type', 'lang'],
+ attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'],
+ attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'],
+ attributesToSnippet: ['content:10'],
+ camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'],
+ searchableAttributes: [
+ 'unordered(hierarchy_radio_camel.lvl0)',
+ 'unordered(hierarchy_radio.lvl0)',
+ 'unordered(hierarchy_radio_camel.lvl1)',
+ 'unordered(hierarchy_radio.lvl1)',
+ 'unordered(hierarchy_radio_camel.lvl2)',
+ 'unordered(hierarchy_radio.lvl2)',
+ 'unordered(hierarchy_radio_camel.lvl3)',
+ 'unordered(hierarchy_radio.lvl3)',
+ 'unordered(hierarchy_radio_camel.lvl4)',
+ 'unordered(hierarchy_radio.lvl4)',
+ 'unordered(hierarchy_radio_camel.lvl5)',
+ 'unordered(hierarchy_radio.lvl5)',
+ 'unordered(hierarchy_radio_camel.lvl6)',
+ 'unordered(hierarchy_radio.lvl6)',
+ 'unordered(hierarchy_camel.lvl0)',
+ 'unordered(hierarchy.lvl0)',
+ 'unordered(hierarchy_camel.lvl1)',
+ 'unordered(hierarchy.lvl1)',
+ 'unordered(hierarchy_camel.lvl2)',
+ 'unordered(hierarchy.lvl2)',
+ 'unordered(hierarchy_camel.lvl3)',
+ 'unordered(hierarchy.lvl3)',
+ 'unordered(hierarchy_camel.lvl4)',
+ 'unordered(hierarchy.lvl4)',
+ 'unordered(hierarchy_camel.lvl5)',
+ 'unordered(hierarchy.lvl5)',
+ 'unordered(hierarchy_camel.lvl6)',
+ 'unordered(hierarchy.lvl6)',
+ 'content',
+ ],
+ distinct: true,
+ attributeForDistinct: 'url',
+ customRanking: [
+ 'desc(weight.pageRank)',
+ 'desc(weight.level)',
+ 'asc(weight.position)',
+ ],
+ ranking: [
+ 'words',
+ 'filters',
+ 'typo',
+ 'attribute',
+ 'proximity',
+ 'exact',
+ 'custom',
+ ],
+ highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
+ highlightPostTag: '</span>',
+ minWordSizefor1Typo: 3,
+ minWordSizefor2Typos: 7,
+ allowTyposOnNumericTokens: false,
+ minProximity: 1,
+ ignorePlurals: true,
+ advancedSyntax: true,
+ attributeCriteriaComputedByMinProximity: true,
+ removeWordsIfNoResults: 'allOptional',
+ },
+ },
+})
+
上述 recordProps
是用于默认主题的配置,你可以根据你使用的主题来修改它们。
注意 initialIndexSettings.YOUR_INDEX_NAME.attributesForFaceting
字段必须包含 'lang'
,否则该插件将无法正常工作。
类型: Record<string, DocsearchPluginOptions>
详情:
在不同 locales 下对该插件进行不同的配置。
该插件的所有其他选项都可以在 locale 中进行配置。
示例:
export default {
+ plugins: [
+ docsearchPlugin({
+ appId: "<APP_ID>",
+ apiKey: "<API_KEY>",
+ indexName: "<INDEX_NAME>",
+ locales: {
+ "/": {
+ placeholder: "Search Documentation",
+ translations: {
+ button: {
+ buttonText: "Search Documentation",
+ },
+ },
+ },
+ "/zh/": {
+ placeholder: "搜索文档",
+ translations: {
+ button: {
+ buttonText: "搜索文档",
+ },
+ },
+ },
+ },
+ }),
+ ],
+};
+
类型: boolean
默认值: true
详情:
是否注入 DocSearch 的默认样式。
如果你认为 DocSearch 的默认样式和你的站点不兼容,你可以尝试覆盖默认样式,或者将该选项设置为 false
来完全移除默认样式。
当该选项被禁用时,你需要为 DocSearch 引入你自己的样式。同时要注意,你也无法再使用 样式 章节中提到的样式自定义能力。
:root {
+ --docsearch-primary-color: rgb(84, 104, 255);
+ --docsearch-text-color: rgb(28, 30, 33);
+ --docsearch-spacing: 12px;
+ --docsearch-icon-stroke-width: 1.4;
+ --docsearch-highlight-color: var(--docsearch-primary-color);
+ --docsearch-muted-color: rgb(150, 159, 175);
+ --docsearch-container-background: rgba(101, 108, 133, 0.8);
+ --docsearch-logo-color: rgba(84, 104, 255);
+
+ /* modal */
+ --docsearch-modal-width: 560px;
+ --docsearch-modal-height: 600px;
+ --docsearch-modal-background: rgb(245, 246, 247);
+ --docsearch-modal-shadow: inset 1px 1px 0 0 rgba(255, 255, 255, 0.5), 0 3px
+ 8px 0 rgba(85, 90, 100, 1);
+
+ /* searchbox */
+ --docsearch-searchbox-height: 56px;
+ --docsearch-searchbox-background: rgb(235, 237, 240);
+ --docsearch-searchbox-focus-background: #fff;
+ --docsearch-searchbox-shadow: inset 0 0 0 2px var(--docsearch-primary-color);
+
+ /* hit */
+ --docsearch-hit-height: 56px;
+ --docsearch-hit-color: rgb(68, 73, 80);
+ --docsearch-hit-active-color: #fff;
+ --docsearch-hit-background: #fff;
+ --docsearch-hit-shadow: 0 1px 3px 0 rgb(212, 217, 225);
+
+ /* key */
+ --docsearch-key-gradient: linear-gradient(
+ -225deg,
+ rgb(213, 219, 228) 0%,
+ rgb(248, 248, 248) 100%
+ );
+ --docsearch-key-shadow: inset 0 -2px 0 0 rgb(205, 205, 230), inset 0 0 1px 1px
+ #fff, 0 1px 2px 1px rgba(30, 35, 90, 0.4);
+
+ /* footer */
+ --docsearch-footer-height: 44px;
+ --docsearch-footer-background: #fff;
+ --docsearch-footer-shadow: 0 -1px 0 0 rgb(224, 227, 232), 0 -3px 6px 0 rgba(69, 98, 155, 0.12);
+}
+
详情:
该插件会全局注册一个 <Docsearch />
组件,你可以不传入任何 Props 来使用它。
将该组件放置在你想要显示 docsearch 按钮的地方。例如,默认主题将这个组件放在了导航栏的末尾。
提示
该组件主要用于主题开发。在大多数情况下你不需要直接使用该组件。
VuePress 默认主题有着大量的用户,因此我们对它进行了一些便于继承的设计,以便用户轻松进行定制化。
VuePress 提供了继承主题的基础能力,但不同的主题可能会提供不同的可继承的功能。因此,如果你使用的是一个社区主题的话,你最好参考主题本身的文档来了解如何继承它。
默认主题的 Layout
布局提供了一些插槽:
navbar
navbar-before
navbar-after
sidebar
sidebar-top
sidebar-bottom
page
page-top
page-bottom
page-content-top
page-content-bottom
在它们的帮助下,你可以很容易地添加或替换内容。下面通过一个示例来介绍一下如何使用布局插槽来继承默认主题。
首先,创建一个客户端配置文件 .vuepress/client.ts
:
import { defineClientConfig } from "@vuepress/client";
+import Layout from "./layouts/Layout.vue";
+
+export default defineClientConfig({
+ layouts: {
+ Layout,
+ },
+});
+
接下来,创建 .vuepress/layouts/Layout.vue
,并使用由默认主题的 Layout
布局提供的插槽:
<script setup>
+import ParentLayout from "@vuepress/theme-default/layouts/Layout.vue";
+</script>
+
+<template>
+ <ParentLayout>
+ <template #page-bottom>
+ <div class="my-footer">This is my custom page footer</div>
+ </template>
+ </ParentLayout>
+</template>
+
+<style lang="css">
+.my-footer {
+ text-align: center;
+}
+</style>
+
此时默认的 Layout
布局已经被你的本地布局覆盖,将会在除了首页外的所有页面添加一个自定义的页脚:
布局插槽十分实用,但有时候你可能会觉得它不够灵活。默认主题同样提供了替换单个组件的能力。
',15),v={href:"https://github.com/vuepress/vuepress-next/tree/main/ecosystem/theme-default/src/client/components",target:"_blank",rel:"noopener noreferrer"},m=s("code",null,"@theme",-1),g=s("code",null,"HomeFooter.vue",-1),b=s("code",null,"@theme/HomeFooter.vue",-1),h=e(`接下来,如果你想要替换 HomeFooter.vue
组件,只需要在配置文件 .vuepress/config.ts
中覆盖这个别名即可:
import { getDirname, path } from "@vuepress/utils";
+import { defaultTheme, defineUserConfig } from "vuepress";
+
+const __dirname = getDirname(import.meta.url);
+
+export default defineUserConfig({
+ theme: defaultTheme(),
+ alias: {
+ "@theme/HomeFooter.vue": path.resolve(
+ __dirname,
+ "./components/MyHomeFooter.vue"
+ ),
+ },
+});
+
除了在 .vuepress/config.ts
和 .vuepress/client.ts
中直接扩展默认主题以外,你可以通过继承默认主题来开发一个你自己的主题:
import type { Theme } from "@vuepress/core";
+import {
+ defaultTheme,
+ type DefaultThemeOptions,
+} from "@vuepress/theme-default";
+import { getDirname, path } from "@vuepress/utils";
+
+const __dirname = getDirname(import.meta.url);
+
+export const childTheme = (options: DefaultThemeOptions): Theme => {
+ return {
+ name: "vuepress-theme-child",
+ extends: defaultTheme(options),
+
+ // 在子主题的客户端配置文件中覆盖布局
+ clientConfigFile: path.resolve(__dirname, "./client.js"),
+
+ // 覆盖组件别名
+ alias: {
+ "@theme/HomeFooter.vue": path.resolve(
+ __dirname,
+ "./components/MyHomeFooter.vue"
+ ),
+ },
+ };
+};
+
VuePress default theme is widely used by users, so it is designed to be extendable, allowing users to make their own customization with ease.
VuePress provides basic ability to extend a theme, but different themes may have different features to be extended. Thus, if you are using a community theme, you'd better refer to the theme's own documentation for how to extending it.
Default theme's Layout
provides some slots:
navbar
navbar-before
navbar-after
sidebar
sidebar-top
sidebar-bottom
page
page-top
page-bottom
page-content-top
page-content-bottom
With the help of them, you can add or replace content easily. Here comes an example to introduce how to extend default theme with layout slots.
Firstly, create a client config file .vuepress/client.ts
:
import { defineClientConfig } from "@vuepress/client";
+import Layout from "./layouts/Layout.vue";
+
+export default defineClientConfig({
+ layouts: {
+ Layout,
+ },
+});
+
Next, create the .vuepress/layouts/Layout.vue
, and make use of the slots that provided by the Layout
of default theme:
<script setup>
+import ParentLayout from "@vuepress/theme-default/layouts/Layout.vue";
+</script>
+
+<template>
+ <ParentLayout>
+ <template #page-bottom>
+ <div class="my-footer">This is my custom page footer</div>
+ </template>
+ </ParentLayout>
+</template>
+
+<style lang="css">
+.my-footer {
+ text-align: center;
+}
+</style>
+
Then the default Layout
layout has been overridden by your own local layout, which will add a custom footer to every normal pages in default theme (excluding homepage):
The layout slots are useful, but sometimes you might find it's not flexible enough. Default theme also provides the ability to replace a single component.
',15),m={href:"https://github.com/vuepress/vuepress-next/tree/main/ecosystem/theme-default/src/client/components",target:"_blank",rel:"noopener noreferrer"},v=s("code",null,"@theme",-1),h=s("code",null,"HomeFooter.vue",-1),g=s("code",null,"@theme/HomeFooter.vue",-1),b=t(`Then, if you want to replace the HomeFooter.vue
component, just override the alias in your config file .vuepress/config.ts
:
import { getDirname, path } from "@vuepress/utils";
+import { defaultTheme, defineUserConfig } from "vuepress";
+
+const __dirname = getDirname(import.meta.url);
+
+export default defineUserConfig({
+ theme: defaultTheme(),
+ alias: {
+ "@theme/HomeFooter.vue": path.resolve(
+ __dirname,
+ "./components/MyHomeFooter.vue"
+ ),
+ },
+});
+
Instead of extending the default theme directly in .vuepress/config.ts
and .vuepress/client.ts
, you can also develop your own theme extending the default theme:
import type { Theme } from "@vuepress/core";
+import {
+ defaultTheme,
+ type DefaultThemeOptions,
+} from "@vuepress/theme-default";
+import { getDirname, path } from "@vuepress/utils";
+
+const __dirname = getDirname(import.meta.url);
+
+export const childTheme = (options: DefaultThemeOptions): Theme => {
+ return {
+ name: "vuepress-theme-child",
+ extends: defaultTheme(options),
+
+ // override layouts in child theme's client config file
+ clientConfigFile: path.resolve(__dirname, "./client.js"),
+
+ // override component alias
+ alias: {
+ "@theme/HomeFooter.vue": path.resolve(
+ __dirname,
+ "./components/MyHomeFooter.vue"
+ ),
+ },
+ };
+};
+
This plugin has been integrated into the default theme.
npm i -D @vuepress/plugin-external-link-icon@next
+
import { externalLinkIconPlugin } from "@vuepress/plugin-external-link-icon";
+
+export default {
+ plugins: [
+ externalLinkIconPlugin({
+ // options
+ }),
+ ],
+};
+
Type: Record<string, { openInNewWindow: string }>
Details:
The a11y text of the external link icon in different locales.
If this option is not specified, it will fallback to default text.
Example:
export default {
+ plugins: [
+ externalLinkIconPlugin({
+ locales: {
+ "/": {
+ openInNewWindow: "open in new window",
+ },
+ "/zh/": {
+ openInNewWindow: "在新窗口打开",
+ },
+ },
+ }),
+ ],
+};
+
Type: boolean
Details:
Whether to append an external link icon to external links in current page.
You can customize the style of the external link icon via CSS variables:
File not found
Details:
This plugin will register a <ExternalLinkIcon />
component globally, and you can use it without any props.
Tips
This component is mainly used for theme development. You don't need to use it directly in most cases.
该插件已经集成到默认主题中。
npm i -D @vuepress/plugin-external-link-icon@next
+
import { externalLinkIconPlugin } from "@vuepress/plugin-external-link-icon";
+
+export default {
+ plugins: [
+ externalLinkIconPlugin({
+ // 配置项
+ }),
+ ],
+};
+
类型: Record<string, { openInNewWindow: string }>
详情:
外部链接图标在不同 locales 下的 A11y 文字。
如果没有指定该配置项,它会降级使用默认文字。
示例:
export default {
+ plugins: [
+ externalLinkIconPlugin({
+ locales: {
+ "/": {
+ openInNewWindow: "open in new window",
+ },
+ "/zh/": {
+ openInNewWindow: "在新窗口打开",
+ },
+ },
+ }),
+ ],
+};
+
类型: boolean
详情:
是否在当前页面的外部链接的后面添加外部链接图标。
你可以通过 CSS 变量来自定义外部链接图标的样式:
File not found
详情:
该插件会全局注册一个 <ExternalLinkIcon />
组件,你可以不传入任何 Props 来使用它。
提示
该组件主要用于主题开发。在大多数情况下你不需要直接使用该组件。
{const{slotScopeIds:z}=y;z&&(D=D?D.concat(z):z);const S=o(g),q=_(i(g),y,S,P,k,D,J);return q&&hn(q)&&q.data==="]"?i(y.anchor=q):(Xe=!0,c(y.anchor=a("]"),S,q),q)},T=(g,y,P,k,D,J)=>{if(Xe=!0,y.el=null,J){const q=$(g);for(;;){const K=i(g);if(K&&K!==q)l(K);else break}}const z=i(g),S=o(g);return l(g),n(null,y,S,z,P,k,dn(S),D),z},$=g=>{let y=0;for(;g;)if(g=i(g),g&&hn(g)&&(g.data==="["&&y++,g.data==="]")){if(y===0)return i(g);y--}return g};return[f,h]}const Ee=li;function Ll(e){return $l(e,Fl)}function $l(e,t){const n=ao();n.__VUE__=!0;const{insert:s,remove:r,patchProp:i,createElement:o,createText:l,createComment:c,setText:a,setElementText:f,parentNode:h,nextSibling:p,setScopeId:_=He,insertStaticContent:C}=e,T=(u,d,m,b=null,E=null,R=null,M=!1,w=null,A=!!d.dynamicChildren)=>{if(u===d)return;u&&!dt(u,d)&&(b=O(u),ve(u,E,R,!0),u=null),d.patchFlag===-2&&(A=!1,d.dynamicChildren=null);const{type:x,ref:j,shapeFlag:F}=d;switch(x){case Tt:$(u,d,m,b);break;case Me:g(u,d,m,b);break;case Ut:u==null&&y(d,m,b,M);break;case Re:N(u,d,m,b,E,R,M,w,A);break;default:F&1?D(u,d,m,b,E,R,M,w,A):F&6?Q(u,d,m,b,E,R,M,w,A):(F&64||F&128)&&x.process(u,d,m,b,E,R,M,w,A,te)}j!=null&&E&&wn(j,u&&u.ref,R,d||u,!d)},$=(u,d,m,b)=>{if(u==null)s(d.el=l(d.children),m,b);else{const E=d.el=u.el;d.children!==u.children&&a(E,d.children)}},g=(u,d,m,b)=>{u==null?s(d.el=c(d.children||""),m,b):d.el=u.el},y=(u,d,m,b)=>{[u.el,u.anchor]=C(u.children,d,m,b,u.el,u.anchor)},P=({el:u,anchor:d},m,b)=>{let E;for(;u&&u!==d;)E=p(u),s(u,m,b),u=E;s(d,m,b)},k=({el:u,anchor:d})=>{let m;for(;u&&u!==d;)m=p(u),r(u),u=m;r(d)},D=(u,d,m,b,E,R,M,w,A)=>{M=M||d.type==="svg",u==null?J(d,m,b,E,R,M,w,A):q(u,d,E,R,M,w,A)},J=(u,d,m,b,E,R,M,w)=>{let A,x;const{type:j,props:F,shapeFlag:B,transition:W,dirs:X}=u;if(A=u.el=o(u.type,R,F&&F.is,F),B&8?f(A,u.children):B&16&&S(u.children,A,null,b,E,R&&j!=="foreignObject",M,w),X&&Ue(u,null,b,"created"),z(A,u,u.scopeId,M,b),F){for(const ie in F)ie!=="value"&&!jt(ie)&&i(A,ie,null,F[ie],R,u.children,b,E,I);"value"in F&&i(A,"value",null,F.value),(x=F.onVnodeBeforeMount)&&Te(x,b,u)}X&&Ue(u,null,b,"beforeMount");const le=(!E||E&&!E.pendingBranch)&&W&&!W.persisted;le&&W.beforeEnter(A),s(A,d,m),((x=F&&F.onVnodeMounted)||le||X)&&Ee(()=>{x&&Te(x,b,u),le&&W.enter(A),X&&Ue(u,null,b,"mounted")},E)},z=(u,d,m,b,E)=>{if(m&&_(u,m),b)for(let R=0;R{for(let x=A;x {const w=d.el=u.el;let{patchFlag:A,dynamicChildren:x,dirs:j}=d;A|=u.patchFlag&16;const F=u.props||ue,B=d.props||ue;let W;m&&ct(m,!1),(W=B.onVnodeBeforeUpdate)&&Te(W,m,d,u),j&&Ue(d,u,m,"beforeUpdate"),m&&ct(m,!0);const X=E&&d.type!=="foreignObject";if(x?K(u.dynamicChildren,x,w,m,b,X,R):M||re(u,d,w,null,m,b,X,R,!1),A>0){if(A&16)Z(w,d,F,B,m,b,E);else if(A&2&&F.class!==B.class&&i(w,"class",null,B.class,E),A&4&&i(w,"style",F.style,B.style,E),A&8){const le=d.dynamicProps;for(let ie=0;ie {W&&Te(W,m,d,u),j&&Ue(d,u,m,"updated")},b)},K=(u,d,m,b,E,R,M)=>{for(let w=0;w {if(m!==b){if(m!==ue)for(const w in m)!jt(w)&&!(w in b)&&i(u,w,m[w],null,M,d.children,E,R,I);for(const w in b){if(jt(w))continue;const A=b[w],x=m[w];A!==x&&w!=="value"&&i(u,w,x,A,M,d.children,E,R,I)}"value"in b&&i(u,"value",m.value,b.value)}},N=(u,d,m,b,E,R,M,w,A)=>{const x=d.el=u?u.el:l(""),j=d.anchor=u?u.anchor:l("");let{patchFlag:F,dynamicChildren:B,slotScopeIds:W}=d;W&&(w=w?w.concat(W):W),u==null?(s(x,m,b),s(j,m,b),S(d.children,m,j,E,R,M,w,A)):F>0&&F&64&&B&&u.dynamicChildren?(K(u.dynamicChildren,B,m,E,R,M,w),(d.key!=null||E&&d===E.subTree)&&Ri(u,d,!0)):re(u,d,m,j,E,R,M,w,A)},Q=(u,d,m,b,E,R,M,w,A)=>{d.slotScopeIds=w,u==null?d.shapeFlag&512?E.ctx.activate(d,m,b,M,A):L(d,m,b,E,R,M,A):_e(u,d,A)},L=(u,d,m,b,E,R,M)=>{const w=u.component=zl(u,b,E);if(sn(u)&&(w.ctx.renderer=te),Ql(w),w.asyncDep){if(E&&E.registerDep(w,ee),!u.el){const A=w.subTree=de(Me);g(null,A,d,m)}return}ee(w,u,d,m,E,R,M)},_e=(u,d,m)=>{const b=d.component=u.component;if(il(u,d,m))if(b.asyncDep&&!b.asyncResolved){oe(b,d,m);return}else b.next=d,Zo(b.update),b.update();else d.el=u.el,b.vnode=d},ee=(u,d,m,b,E,R,M)=>{const w=()=>{if(u.isMounted){let{next:j,bu:F,u:B,parent:W,vnode:X}=u,le=j,ie;ct(u,!1),j?(j.el=X.el,oe(u,j,M)):j=X,F&&kn(F),(ie=j.props&&j.props.onVnodeBeforeUpdate)&&Te(ie,W,j,X),ct(u,!0);const he=Hn(u),Fe=u.subTree;u.subTree=he,T(Fe,he,h(Fe.el),O(Fe),u,E,R),j.el=he.el,le===null&&ol(u,he.el),B&&Ee(B,E),(ie=j.props&&j.props.onVnodeUpdated)&&Ee(()=>Te(ie,W,j,X),E)}else{let j;const{el:F,props:B}=d,{bm:W,m:X,parent:le}=u,ie=Bt(d);if(ct(u,!1),W&&kn(W),!ie&&(j=B&&B.onVnodeBeforeMount)&&Te(j,le,d),ct(u,!0),F&&Y){const he=()=>{u.subTree=Hn(u),Y(F,u.subTree,u,E,null)};ie?d.type.__asyncLoader().then(()=>!u.isUnmounted&&he()):he()}else{const he=u.subTree=Hn(u);T(null,he,m,b,u,E,R),d.el=he.el}if(X&&Ee(X,E),!ie&&(j=B&&B.onVnodeMounted)){const he=d;Ee(()=>Te(j,le,he),E)}(d.shapeFlag&256||le&&Bt(le.vnode)&&le.vnode.shapeFlag&256)&&u.a&&Ee(u.a,E),u.isMounted=!0,d=m=b=null}},A=u.effect=new ms(w,()=>Sn(x),u.scope),x=u.update=()=>A.run();x.id=u.uid,ct(u,!0),x()},oe=(u,d,m)=>{d.component=u;const b=u.vnode.props;u.vnode=d,u.next=null,Al(u,d.props,b,m),Ml(u,d.children,m),Nt(),Ws(),Ft()},re=(u,d,m,b,E,R,M,w,A=!1)=>{const x=u&&u.children,j=u?u.shapeFlag:0,F=d.children,{patchFlag:B,shapeFlag:W}=d;if(B>0){if(B&128){lt(x,F,m,b,E,R,M,w,A);return}else if(B&256){Ie(x,F,m,b,E,R,M,w,A);return}}W&8?(j&16&&I(x,E,R),F!==x&&f(m,F)):j&16?W&16?lt(x,F,m,b,E,R,M,w,A):I(x,E,R,!0):(j&8&&f(m,""),W&16&&S(F,m,b,E,R,M,w,A))},Ie=(u,d,m,b,E,R,M,w,A)=>{u=u||Et,d=d||Et;const x=u.length,j=d.length,F=Math.min(x,j);let B;for(B=0;B j?I(u,E,R,!0,!1,F):S(d,m,b,E,R,M,w,A,F)},lt=(u,d,m,b,E,R,M,w,A)=>{let x=0;const j=d.length;let F=u.length-1,B=j-1;for(;x<=F&&x<=B;){const W=u[x],X=d[x]=A?tt(d[x]):Le(d[x]);if(dt(W,X))T(W,X,m,null,E,R,M,w,A);else break;x++}for(;x<=F&&x<=B;){const W=u[F],X=d[B]=A?tt(d[B]):Le(d[B]);if(dt(W,X))T(W,X,m,null,E,R,M,w,A);else break;F--,B--}if(x>F){if(x<=B){const W=B+1,X=W B)for(;x<=F;)ve(u[x],E,R,!0),x++;else{const W=x,X=x,le=new Map;for(x=X;x<=B;x++){const xe=d[x]=A?tt(d[x]):Le(d[x]);xe.key!=null&&le.set(xe.key,x)}let ie,he=0;const Fe=B-X+1;let _t=!1,Ns=0;const Lt=new Array(Fe);for(x=0;x =Fe){ve(xe,E,R,!0);continue}let De;if(xe.key!=null)De=le.get(xe.key);else for(ie=X;ie<=B;ie++)if(Lt[ie-X]===0&&dt(xe,d[ie])){De=ie;break}De===void 0?ve(xe,E,R,!0):(Lt[De-X]=x+1,De>=Ns?Ns=De:_t=!0,T(xe,d[De],m,null,E,R,M,w,A),he++)}const Fs=_t?kl(Lt):Et;for(ie=Fs.length-1,x=Fe-1;x>=0;x--){const xe=X+x,De=d[xe],Ls=xe+1 {const{el:R,type:M,transition:w,children:A,shapeFlag:x}=u;if(x&6){Ne(u.component.subTree,d,m,b);return}if(x&128){u.suspense.move(d,m,b);return}if(x&64){M.move(u,d,m,te);return}if(M===Re){s(R,d,m);for(let F=0;F w.enter(R),E);else{const{leave:F,delayLeave:B,afterLeave:W}=w,X=()=>s(R,d,m),le=()=>{F(R,()=>{X(),W&&W()})};B?B(R,X,le):le()}else s(R,d,m)},ve=(u,d,m,b=!1,E=!1)=>{const{type:R,props:M,ref:w,children:A,dynamicChildren:x,shapeFlag:j,patchFlag:F,dirs:B}=u;if(w!=null&&wn(w,null,m,u,!0),j&256){d.ctx.deactivate(u);return}const W=j&1&&B,X=!Bt(u);let le;if(X&&(le=M&&M.onVnodeBeforeUnmount)&&Te(le,d,u),j&6)v(u.component,m,b);else{if(j&128){u.suspense.unmount(m,b);return}W&&Ue(u,null,d,"beforeUnmount"),j&64?u.type.remove(u,d,m,E,te,b):x&&(R!==Re||F>0&&F&64)?I(x,d,m,!1,!0):(R===Re&&F&384||!E&&j&16)&&I(A,d,m),b&&mt(u)}(X&&(le=M&&M.onVnodeUnmounted)||W)&&Ee(()=>{le&&Te(le,d,u),W&&Ue(u,null,d,"unmounted")},m)},mt=u=>{const{type:d,el:m,anchor:b,transition:E}=u;if(d===Re){rn(m,b);return}if(d===Ut){k(u);return}const R=()=>{r(m),E&&!E.persisted&&E.afterLeave&&E.afterLeave()};if(u.shapeFlag&1&&E&&!E.persisted){const{leave:M,delayLeave:w}=E,A=()=>M(m,R);w?w(u.el,R,A):A()}else R()},rn=(u,d)=>{let m;for(;u!==d;)m=p(u),r(u),u=m;r(d)},v=(u,d,m)=>{const{bum:b,scope:E,update:R,subTree:M,um:w}=u;b&&kn(b),E.stop(),R&&(R.active=!1,ve(M,u,d,m)),w&&Ee(w,d),Ee(()=>{u.isUnmounted=!0},d),d&&d.pendingBranch&&!d.isUnmounted&&u.asyncDep&&!u.asyncResolved&&u.suspenseId===d.pendingId&&(d.deps--,d.deps===0&&d.resolve())},I=(u,d,m,b=!1,E=!1,R=0)=>{for(let M=R;M u.shapeFlag&6?O(u.component.subTree):u.shapeFlag&128?u.suspense.next():p(u.anchor||u.el),H=(u,d,m)=>{u==null?d._vnode&&ve(d._vnode,null,null,!0):T(d._vnode||null,u,d,null,null,null,m),Ws(),En(),d._vnode=u},te={p:T,um:ve,m:Ne,r:mt,mt:L,mc:S,pc:re,pbc:K,n:O,o:e};let fe,Y;return t&&([fe,Y]=t(te)),{render:H,hydrate:fe,createApp:Nl(H,fe)}}function ct({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function Ri(e,t,n=!1){const s=e.children,r=t.children;if(U(s)&&U(r))for(let i=0;i >1,e[n[l]]0&&(t[s]=n[i-1]),n[i]=s)}}for(i=n.length,o=n[i-1];i-- >0;)n[i]=o,o=t[o];return n}const Hl=e=>e.__isTeleport,Re=Symbol(void 0),Tt=Symbol(void 0),Me=Symbol(void 0),Ut=Symbol(void 0),Kt=[];let ke=null;function jl(e=!1){Kt.push(ke=e?null:[])}function Bl(){Kt.pop(),ke=Kt[Kt.length-1]||null}let Zt=1;function er(e){Zt+=e}function Pi(e){return e.dynamicChildren=Zt>0?ke||Et:null,Bl(),Zt>0&&ke&&ke.push(e),e}function Ku(e,t,n,s,r,i){return Pi(Ai(e,t,n,s,r,i,!0))}function Dl(e,t,n,s,r){return Pi(de(e,t,n,s,r,!0))}function ss(e){return e?e.__v_isVNode===!0:!1}function dt(e,t){return e.type===t.type&&e.key===t.key}const Nn="__vInternal",Ti=({key:e})=>e??null,_n=({ref:e,ref_key:t,ref_for:n})=>e!=null?pe(e)||me(e)||V(e)?{i:Oe,r:e,k:t,f:!!n}:e:null;function Ai(e,t=null,n=null,s=0,r=null,i=e===Re?0:1,o=!1,l=!1){const c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Ti(t),ref:t&&_n(t),scopeId:oi,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:i,patchFlag:s,dynamicProps:r,dynamicChildren:null,appContext:null,ctx:Oe};return l?(As(c,n),i&128&&e.normalize(c)):n&&(c.shapeFlag|=pe(n)?8:16),Zt>0&&!o&&ke&&(c.patchFlag>0||i&6)&&c.patchFlag!==32&&ke.push(c),c}const de=Ul;function Ul(e,t=null,n=null,s=0,r=null,i=!1){if((!e||e===bl)&&(e=Me),ss(e)){const l=ot(e,t,!0);return n&&As(l,n),Zt>0&&!i&&ke&&(l.shapeFlag&6?ke[ke.indexOf(e)]=l:ke.push(l)),l.patchFlag|=-2,l}if(Gl(e)&&(e=e.__vccOpts),t){t=Kl(t);let{class:l,style:c}=t;l&&!pe(l)&&(t.class=fs(l)),ce(c)&&(Qr(c)&&!U(c)&&(c=ge({},c)),t.style=us(c))}const o=pe(e)?1:ll(e)?128:Hl(e)?64:ce(e)?4:V(e)?2:0;return Ai(e,t,n,s,r,o,i,!0)}function Kl(e){return e?Qr(e)||Nn in e?ge({},e):e:null}function ot(e,t,n=!1){const{props:s,ref:r,patchFlag:i,children:o}=e,l=t?Wl(s||{},t):s;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&Ti(l),ref:t&&t.ref?n&&r?U(r)?r.concat(_n(t)):[r,_n(t)]:_n(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:o,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Re?i===-1?16:i|16:i,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&ot(e.ssContent),ssFallback:e.ssFallback&&ot(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Oi(e=" ",t=0){return de(Tt,null,e,t)}function Wu(e,t){const n=de(Ut,null,e);return n.staticCount=t,n}function qu(e="",t=!1){return t?(jl(),Dl(Me,null,e)):de(Me,null,e)}function Le(e){return e==null||typeof e=="boolean"?de(Me):U(e)?de(Re,null,e.slice()):typeof e=="object"?tt(e):de(Tt,null,String(e))}function tt(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:ot(e)}function As(e,t){let n=0;const{shapeFlag:s}=e;if(t==null)t=null;else if(U(t))n=16;else if(typeof t=="object")if(s&65){const r=t.default;r&&(r._c&&(r._d=!1),As(e,r()),r._c&&(r._d=!0));return}else{n=32;const r=t._;!r&&!(Nn in t)?t._ctx=Oe:r===3&&Oe&&(Oe.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else V(t)?(t={default:t,_ctx:Oe},n=32):(t=String(t),s&64?(n=16,t=[Oi(t)]):n=8);e.children=t,e.shapeFlag|=n}function Wl(...e){const t={};for(let n=0;n ae||Oe,At=e=>{ae=e,e.scope.on()},gt=()=>{ae&&ae.scope.off(),ae=null};function Mi(e){return e.vnode.shapeFlag&4}let Ot=!1;function Ql(e,t=!1){Ot=t;const{props:n,children:s}=e.vnode,r=Mi(e);Tl(e,n,r,t),Sl(e,s);const i=r?Yl(e,t):void 0;return Ot=!1,i}function Yl(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=Yr(new Proxy(e.ctx,El));const{setup:s}=n;if(s){const r=e.setupContext=s.length>1?Xl(e):null;At(e),Nt();const i=rt(s,e,0,[e.props,r]);if(Ft(),gt(),Fr(i)){if(i.then(gt,gt),t)return i.then(o=>{tr(e,o,t)}).catch(o=>{nn(o,e,0)});e.asyncDep=i}else tr(e,i,t)}else Ii(e,t)}function tr(e,t,n){V(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:ce(t)&&(e.setupState=Gr(t)),Ii(e,n)}let nr;function Ii(e,t,n){const s=e.type;if(!e.render){if(!t&&nr&&!s.render){const r=s.template||Ps(e).template;if(r){const{isCustomElement:i,compilerOptions:o}=e.appContext.config,{delimiters:l,compilerOptions:c}=s,a=ge(ge({isCustomElement:i,delimiters:l},o),c);s.render=nr(r,a)}}e.render=s.render||He}At(e),Nt(),Cl(e),Ft(),gt()}function Jl(e){return new Proxy(e.attrs,{get(t,n){return Ce(e,"get","$attrs"),t[n]}})}function Xl(e){const t=s=>{e.exposed=s||{}};let n;return{get attrs(){return n||(n=Jl(e))},slots:e.slots,emit:e.emit,expose:t}}function Os(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Gr(Yr(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Dt)return Dt[n](e)},has(t,n){return n in t||n in Dt}}))}function Zl(e,t=!0){return V(e)?e.displayName||e.name:e.name||t&&e.__name}function Gl(e){return V(e)&&"__vccOpts"in e}const Ae=(e,t)=>Yo(e,t,Ot);function Ss(e,t,n){const s=arguments.length;return s===2?ce(t)&&!U(t)?ss(t)?de(e,null,[t]):de(e,t):de(e,null,t):(s>3?n=Array.prototype.slice.call(arguments,2):s===3&&ss(n)&&(n=[n]),de(e,t,n))}const ec=Symbol(""),tc=()=>je(ec),nc="3.2.47",sc="http://www.w3.org/2000/svg",ht=typeof document<"u"?document:null,sr=ht&&ht.createElement("template"),rc={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,s)=>{const r=t?ht.createElementNS(sc,e):ht.createElement(e,n?{is:n}:void 0);return e==="select"&&s&&s.multiple!=null&&r.setAttribute("multiple",s.multiple),r},createText:e=>ht.createTextNode(e),createComment:e=>ht.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>ht.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,s,r,i){const o=n?n.previousSibling:t.lastChild;if(r&&(r===i||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===i||!(r=r.nextSibling)););else{sr.innerHTML=s?``:e;const l=sr.content;if(s){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function ic(e,t,n){const s=e._vtc;s&&(t=(t?[t,...s]:[...s]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function oc(e,t,n){const s=e.style,r=pe(n);if(n&&!r){if(t&&!pe(t))for(const i in t)n[i]==null&&rs(s,i,"");for(const i in n)rs(s,i,n[i])}else{const i=s.display;r?t!==n&&(s.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(s.display=i)}}const rr=/\s*!important$/;function rs(e,t,n){if(U(n))n.forEach(s=>rs(e,t,s));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const s=lc(e,t);rr.test(n)?e.setProperty(It(s),n.replace(rr,""),"important"):e[s]=n}}const ir=["Webkit","Moz","ms"],Un={};function lc(e,t){const n=Un[t];if(n)return n;let s=We(t);if(s!=="filter"&&s in e)return Un[t]=s;s=An(s);for(let r=0;r Kn||(pc.then(()=>Kn=0),Kn=Date.now());function mc(e,t){const n=s=>{if(!s._vts)s._vts=Date.now();else if(s._vts<=n.attached)return;Se(_c(s,n.value),t,5,[s])};return n.value=e,n.attached=gc(),n}function _c(e,t){if(U(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(s=>r=>!r._stopped&&s&&s(r))}else return t}const cr=/^on[a-z]/,yc=(e,t,n,s,r=!1,i,o,l,c)=>{t==="class"?ic(e,s,r):t==="style"?oc(e,n,s):en(t)?as(t)||dc(e,t,n,s,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):bc(e,t,s,r))?uc(e,t,s,i,o,l,c):(t==="true-value"?e._trueValue=s:t==="false-value"&&(e._falseValue=s),cc(e,t,s,r))};function bc(e,t,n,s){return s?!!(t==="innerHTML"||t==="textContent"||t in e&&cr.test(t)&&V(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||cr.test(t)&&pe(n)?!1:t in e}const Ze="transition",$t="animation",Ni=(e,{slots:t})=>Ss(fi,Li(e),t);Ni.displayName="Transition";const Fi={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},vc=Ni.props=ge({},fi.props,Fi),ut=(e,t=[])=>{U(e)?e.forEach(n=>n(...t)):e&&e(...t)},ur=e=>e?U(e)?e.some(t=>t.length>1):e.length>1:!1;function Li(e){const t={};for(const N in e)N in Fi||(t[N]=e[N]);if(e.css===!1)return t;const{name:n="v",type:s,duration:r,enterFromClass:i=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=i,appearActiveClass:a=o,appearToClass:f=l,leaveFromClass:h=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:_=`${n}-leave-to`}=e,C=Ec(r),T=C&&C[0],$=C&&C[1],{onBeforeEnter:g,onEnter:y,onEnterCancelled:P,onLeave:k,onLeaveCancelled:D,onBeforeAppear:J=g,onAppear:z=y,onAppearCancelled:S=P}=t,q=(N,Q,L)=>{et(N,Q?f:l),et(N,Q?a:o),L&&L()},K=(N,Q)=>{N._isLeaving=!1,et(N,h),et(N,_),et(N,p),Q&&Q()},Z=N=>(Q,L)=>{const _e=N?z:y,ee=()=>q(Q,N,L);ut(_e,[Q,ee]),fr(()=>{et(Q,N?c:i),Ve(Q,N?f:l),ur(_e)||ar(Q,s,T,ee)})};return ge(t,{onBeforeEnter(N){ut(g,[N]),Ve(N,i),Ve(N,o)},onBeforeAppear(N){ut(J,[N]),Ve(N,c),Ve(N,a)},onEnter:Z(!1),onAppear:Z(!0),onLeave(N,Q){N._isLeaving=!0;const L=()=>K(N,Q);Ve(N,h),ki(),Ve(N,p),fr(()=>{N._isLeaving&&(et(N,h),Ve(N,_),ur(k)||ar(N,s,$,L))}),ut(k,[N,L])},onEnterCancelled(N){q(N,!1),ut(P,[N])},onAppearCancelled(N){q(N,!0),ut(S,[N])},onLeaveCancelled(N){K(N),ut(D,[N])}})}function Ec(e){if(e==null)return null;if(ce(e))return[Wn(e.enter),Wn(e.leave)];{const t=Wn(e);return[t,t]}}function Wn(e){return fo(e)}function Ve(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vtc||(e._vtc=new Set)).add(t)}function et(e,t){t.split(/\s+/).forEach(s=>s&&e.classList.remove(s));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function fr(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Cc=0;function ar(e,t,n,s){const r=e._endId=++Cc,i=()=>{r===e._endId&&s()};if(n)return setTimeout(i,n);const{type:o,timeout:l,propCount:c}=$i(e,t);if(!o)return s();const a=o+"end";let f=0;const h=()=>{e.removeEventListener(a,p),i()},p=_=>{_.target===e&&++f>=c&&h()};setTimeout(()=>{f (n[C]||"").split(", "),r=s(`${Ze}Delay`),i=s(`${Ze}Duration`),o=dr(r,i),l=s(`${$t}Delay`),c=s(`${$t}Duration`),a=dr(l,c);let f=null,h=0,p=0;t===Ze?o>0&&(f=Ze,h=o,p=i.length):t===$t?a>0&&(f=$t,h=a,p=c.length):(h=Math.max(o,a),f=h>0?o>a?Ze:$t:null,p=f?f===Ze?i.length:c.length:0);const _=f===Ze&&/\b(transform|all)(,|$)/.test(s(`${Ze}Property`).toString());return{type:f,timeout:h,propCount:p,hasTransform:_}}function dr(e,t){for(;e.length hr(n)+hr(e[s])))}function hr(e){return Number(e.slice(0,-1).replace(",","."))*1e3}function ki(){return document.body.offsetHeight}const Hi=new WeakMap,ji=new WeakMap,Bi={name:"TransitionGroup",props:ge({},vc,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=Si(),s=ui();let r,i;return pi(()=>{if(!r.length)return;const o=e.moveClass||`${e.name||"v"}-move`;if(!Tc(r[0].el,n.vnode.el,o))return;r.forEach(wc),r.forEach(Rc);const l=r.filter(Pc);ki(),l.forEach(c=>{const a=c.el,f=a.style;Ve(a,o),f.transform=f.webkitTransform=f.transitionDuration="";const h=a._moveCb=p=>{p&&p.target!==a||(!p||/transform$/.test(p.propertyName))&&(a.removeEventListener("transitionend",h),a._moveCb=null,et(a,o))};a.addEventListener("transitionend",h)})}),()=>{const o=G(e),l=Li(o);let c=o.tag||Re;r=i,i=t.default?ws(t.default()):[];for(let a=0;a delete e.mode;Bi.props;const Vu=Bi;function wc(e){const t=e.el;t._moveCb&&t._moveCb(),t._enterCb&&t._enterCb()}function Rc(e){ji.set(e,e.el.getBoundingClientRect())}function Pc(e){const t=Hi.get(e),n=ji.get(e),s=t.left-n.left,r=t.top-n.top;if(s||r){const i=e.el.style;return i.transform=i.webkitTransform=`translate(${s}px,${r}px)`,i.transitionDuration="0s",e}}function Tc(e,t,n){const s=e.cloneNode();e._vtc&&e._vtc.forEach(o=>{o.split(/\s+/).forEach(l=>l&&s.classList.remove(l))}),n.split(/\s+/).forEach(o=>o&&s.classList.add(o)),s.style.display="none";const r=t.nodeType===1?t:t.parentNode;r.appendChild(s);const{hasTransform:i}=$i(s);return r.removeChild(s),i}const Ac=ge({patchProp:yc},rc);let qn,pr=!1;function Oc(){return qn=pr?qn:Ll(Ac),pr=!0,qn}const zu=(...e)=>{const t=Oc().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=Sc(s);if(r)return n(r,!0,r instanceof SVGElement)},t};function Sc(e){return pe(e)?document.querySelector(e):e}var Mc=([e,t,n])=>e==="meta"&&t.name?`${e}.${t.name}`:["title","base"].includes(e)?e:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,t,n]),Qu=e=>{const t=new Set,n=[];return e.forEach(s=>{const r=Mc(s);t.has(r)||(t.add(r),n.push(s))}),n},Yu=e=>/(\.html|\/)$/.test(e)?e:e+"/",Ic=e=>e.startsWith("ftp://"),Nc=e=>/^(https?:)?\/\//.test(e),Fc=/.md((\?|#).*)?$/,Ju=(e,t="/")=>!!(Nc(e)||Ic(e)||e.startsWith("/")&&!e.startsWith(t)&&!Fc.test(e)),Xu=e=>/^mailto:/.test(e),Zu=e=>/^tel:/.test(e),Gu=e=>Object.prototype.toString.call(e)==="[object Object]",ef=e=>e.replace(/\/$/,""),tf=e=>e.replace(/^\//,""),nf=(e,t)=>{const n=Object.keys(e).sort((s,r)=>{const i=r.split("/").length-s.split("/").length;return i!==0?i:r.length-s.length});for(const s of n)if(t.startsWith(s))return s;return"/"},sf=(e,t="/")=>e.replace(/^(https?:)?\/\/[^/]*/,"").replace(new RegExp(`^${t}`),"/");/*! + * vue-router v4.1.6 + * (c) 2022 Eduardo San Martin Morote + * @license MIT + */const bt=typeof window<"u";function Lc(e){return e.__esModule||e[Symbol.toStringTag]==="Module"}const se=Object.assign;function Vn(e,t){const n={};for(const s in t){const r=t[s];n[s]=Be(r)?r.map(e):e(r)}return n}const Wt=()=>{},Be=Array.isArray,$c=/\/$/,kc=e=>e.replace($c,"");function zn(e,t,n="/"){let s,r={},i="",o="";const l=t.indexOf("#");let c=t.indexOf("?");return l =0&&(c=-1),c>-1&&(s=t.slice(0,c),i=t.slice(c+1,l>-1?l:t.length),r=e(i)),l>-1&&(s=s||t.slice(0,l),o=t.slice(l,t.length)),s=Dc(s??t,n),{fullPath:s+(i&&"?")+i+o,path:s,query:r,hash:o}}function Hc(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function gr(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function jc(e,t,n){const s=t.matched.length-1,r=n.matched.length-1;return s>-1&&s===r&&St(t.matched[s],n.matched[r])&&Di(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function St(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Di(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!Bc(e[n],t[n]))return!1;return!0}function Bc(e,t){return Be(e)?mr(e,t):Be(t)?mr(t,e):e===t}function mr(e,t){return Be(t)?e.length===t.length&&e.every((n,s)=>n===t[s]):e.length===1&&e[0]===t}function Dc(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),s=e.split("/");let r=n.length-1,i,o;for(i=0;i 1&&r--;else break;return n.slice(0,r).join("/")+"/"+s.slice(i-(i===s.length?1:0)).join("/")}var Gt;(function(e){e.pop="pop",e.push="push"})(Gt||(Gt={}));var qt;(function(e){e.back="back",e.forward="forward",e.unknown=""})(qt||(qt={}));function Uc(e){if(!e)if(bt){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),kc(e)}const Kc=/^[^#]+#/;function Wc(e,t){return e.replace(Kc,"#")+t}function qc(e,t){const n=document.documentElement.getBoundingClientRect(),s=e.getBoundingClientRect();return{behavior:t.behavior,left:s.left-n.left-(t.left||0),top:s.top-n.top-(t.top||0)}}const Fn=()=>({left:window.pageXOffset,top:window.pageYOffset});function Vc(e){let t;if("el"in e){const n=e.el,s=typeof n=="string"&&n.startsWith("#"),r=typeof n=="string"?s?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!r)return;t=qc(r,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.pageXOffset,t.top!=null?t.top:window.pageYOffset)}function _r(e,t){return(history.state?history.state.position-t:-1)+e}const is=new Map;function zc(e,t){is.set(e,t)}function Qc(e){const t=is.get(e);return is.delete(e),t}let Yc=()=>location.protocol+"//"+location.host;function Ui(e,t){const{pathname:n,search:s,hash:r}=t,i=e.indexOf("#");if(i>-1){let l=r.includes(e.slice(i))?e.slice(i).length:1,c=r.slice(l);return c[0]!=="/"&&(c="/"+c),gr(c,"")}return gr(n,e)+s+r}function Jc(e,t,n,s){let r=[],i=[],o=null;const l=({state:p})=>{const _=Ui(e,location),C=n.value,T=t.value;let $=0;if(p){if(n.value=_,t.value=p,o&&o===C){o=null;return}$=T?p.position-T.position:0}else s(_);r.forEach(g=>{g(n.value,C,{delta:$,type:Gt.pop,direction:$?$>0?qt.forward:qt.back:qt.unknown})})};function c(){o=n.value}function a(p){r.push(p);const _=()=>{const C=r.indexOf(p);C>-1&&r.splice(C,1)};return i.push(_),_}function f(){const{history:p}=window;p.state&&p.replaceState(se({},p.state,{scroll:Fn()}),"")}function h(){for(const p of i)p();i=[],window.removeEventListener("popstate",l),window.removeEventListener("beforeunload",f)}return window.addEventListener("popstate",l),window.addEventListener("beforeunload",f),{pauseListeners:c,listen:a,destroy:h}}function yr(e,t,n,s=!1,r=!1){return{back:e,current:t,forward:n,replaced:s,position:window.history.length,scroll:r?Fn():null}}function Xc(e){const{history:t,location:n}=window,s={value:Ui(e,n)},r={value:t.state};r.value||i(s.value,{back:null,current:s.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(c,a,f){const h=e.indexOf("#"),p=h>-1?(n.host&&document.querySelector("base")?e:e.slice(h))+c:Yc()+e+c;try{t[f?"replaceState":"pushState"](a,"",p),r.value=a}catch(_){console.error(_),n[f?"replace":"assign"](p)}}function o(c,a){const f=se({},t.state,yr(r.value.back,c,r.value.forward,!0),a,{position:r.value.position});i(c,f,!0),s.value=c}function l(c,a){const f=se({},r.value,t.state,{forward:c,scroll:Fn()});i(f.current,f,!0);const h=se({},yr(s.value,c,null),{position:f.position+1},a);i(c,h,!1),s.value=c}return{location:s,state:r,push:l,replace:o}}function rf(e){e=Uc(e);const t=Xc(e),n=Jc(e,t.state,t.location,t.replace);function s(i,o=!0){o||n.pauseListeners(),history.go(i)}const r=se({location:"",base:e,go:s,createHref:Wc.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>t.state.value}),r}function Zc(e){return typeof e=="string"||e&&typeof e=="object"}function Ki(e){return typeof e=="string"||typeof e=="symbol"}const Ge={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},Wi=Symbol("");var br;(function(e){e[e.aborted=4]="aborted",e[e.cancelled=8]="cancelled",e[e.duplicated=16]="duplicated"})(br||(br={}));function Mt(e,t){return se(new Error,{type:e,[Wi]:!0},t)}function qe(e,t){return e instanceof Error&&Wi in e&&(t==null||!!(e.type&t))}const vr="[^/]+?",Gc={sensitive:!1,strict:!1,start:!0,end:!0},eu=/[.+*?^${}()[\]/\\]/g;function tu(e,t){const n=se({},Gc,t),s=[];let r=n.start?"^":"";const i=[];for(const a of e){const f=a.length?[]:[90];n.strict&&!a.length&&(r+="/");for(let h=0;h t.length?t.length===1&&t[0]===40+40?1:-1:0}function su(e,t){let n=0;const s=e.score,r=t.score;for(;n 0&&t[t.length-1]<0}const ru={type:0,value:""},iu=/[a-zA-Z0-9_]/;function ou(e){if(!e)return[[]];if(e==="/")return[[ru]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(_){throw new Error(`ERR (${n})/"${a}": ${_}`)}let n=0,s=n;const r=[];let i;function o(){i&&r.push(i),i=[]}let l=0,c,a="",f="";function h(){a&&(n===0?i.push({type:0,value:a}):n===1||n===2||n===3?(i.length>1&&(c==="*"||c==="+")&&t(`A repeatable param (${a}) must be alone in its segment. eg: '/:ids+.`),i.push({type:1,value:a,regexp:f,repeatable:c==="*"||c==="+",optional:c==="*"||c==="?"})):t("Invalid state to consume buffer"),a="")}function p(){a+=c}for(;l {o(y)}:Wt}function o(f){if(Ki(f)){const h=s.get(f);h&&(s.delete(f),n.splice(n.indexOf(h),1),h.children.forEach(o),h.alias.forEach(o))}else{const h=n.indexOf(f);h>-1&&(n.splice(h,1),f.record.name&&s.delete(f.record.name),f.children.forEach(o),f.alias.forEach(o))}}function l(){return n}function c(f){let h=0;for(;h =0&&(f.record.path!==n[h].record.path||!qi(f,n[h]));)h++;n.splice(h,0,f),f.record.name&&!xr(f)&&s.set(f.record.name,f)}function a(f,h){let p,_={},C,T;if("name"in f&&f.name){if(p=s.get(f.name),!p)throw Mt(1,{location:f});T=p.record.name,_=se(Cr(h.params,p.keys.filter(y=>!y.optional).map(y=>y.name)),f.params&&Cr(f.params,p.keys.map(y=>y.name))),C=p.stringify(_)}else if("path"in f)C=f.path,p=n.find(y=>y.re.test(C)),p&&(_=p.parse(C),T=p.record.name);else{if(p=h.name?s.get(h.name):n.find(y=>y.re.test(h.path)),!p)throw Mt(1,{location:f,currentLocation:h});T=p.record.name,_=se({},h.params,f.params),C=p.stringify(_)}const $=[];let g=p;for(;g;)$.unshift(g.record),g=g.parent;return{name:T,path:C,params:_,matched:$,meta:au($)}}return e.forEach(f=>i(f)),{addRoute:i,resolve:a,removeRoute:o,getRoutes:l,getRecordMatcher:r}}function Cr(e,t){const n={};for(const s of t)s in e&&(n[s]=e[s]);return n}function uu(e){return{path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:void 0,beforeEnter:e.beforeEnter,props:fu(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}}}function fu(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const s in e.components)t[s]=typeof n=="boolean"?n:n[s];return t}function xr(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function au(e){return e.reduce((t,n)=>se(t,n.meta),{})}function wr(e,t){const n={};for(const s in e)n[s]=s in t?t[s]:e[s];return n}function qi(e,t){return t.children.some(n=>n===e||qi(e,n))}const Vi=/#/g,du=/&/g,hu=/\//g,pu=/=/g,gu=/\?/g,zi=/\+/g,mu=/%5B/g,_u=/%5D/g,Qi=/%5E/g,yu=/%60/g,Yi=/%7B/g,bu=/%7C/g,Ji=/%7D/g,vu=/%20/g;function Ms(e){return encodeURI(""+e).replace(bu,"|").replace(mu,"[").replace(_u,"]")}function Eu(e){return Ms(e).replace(Yi,"{").replace(Ji,"}").replace(Qi,"^")}function os(e){return Ms(e).replace(zi,"%2B").replace(vu,"+").replace(Vi,"%23").replace(du,"%26").replace(yu,"`").replace(Yi,"{").replace(Ji,"}").replace(Qi,"^")}function Cu(e){return os(e).replace(pu,"%3D")}function xu(e){return Ms(e).replace(Vi,"%23").replace(gu,"%3F")}function wu(e){return e==null?"":xu(e).replace(hu,"%2F")}function Rn(e){try{return decodeURIComponent(""+e)}catch{}return""+e}function Ru(e){const t={};if(e===""||e==="?")return t;const s=(e[0]==="?"?e.slice(1):e).split("&");for(let r=0;r i&&os(i)):[s&&os(s)]).forEach(i=>{i!==void 0&&(t+=(t.length?"&":"")+n,i!=null&&(t+="="+i))})}return t}function Pu(e){const t={};for(const n in e){const s=e[n];s!==void 0&&(t[n]=Be(s)?s.map(r=>r==null?null:""+r):s==null?s:""+s)}return t}const Tu=Symbol(""),Pr=Symbol(""),Ln=Symbol(""),Is=Symbol(""),ls=Symbol("");function kt(){let e=[];function t(s){return e.push(s),()=>{const r=e.indexOf(s);r>-1&&e.splice(r,1)}}function n(){e=[]}return{add:t,list:()=>e,reset:n}}function nt(e,t,n,s,r){const i=s&&(s.enterCallbacks[r]=s.enterCallbacks[r]||[]);return()=>new Promise((o,l)=>{const c=h=>{h===!1?l(Mt(4,{from:n,to:t})):h instanceof Error?l(h):Zc(h)?l(Mt(2,{from:t,to:h})):(i&&s.enterCallbacks[r]===i&&typeof h=="function"&&i.push(h),o())},a=e.call(s&&s.instances[r],t,n,c);let f=Promise.resolve(a);e.length<3&&(f=f.then(c)),f.catch(h=>l(h))})}function Qn(e,t,n,s){const r=[];for(const i of e)for(const o in i.components){let l=i.components[o];if(!(t!=="beforeRouteEnter"&&!i.instances[o]))if(Au(l)){const a=(l.__vccOpts||l)[t];a&&r.push(nt(a,n,s,i,o))}else{let c=l();r.push(()=>c.then(a=>{if(!a)return Promise.reject(new Error(`Couldn't resolve component "${o}" at "${i.path}"`));const f=Lc(a)?a.default:a;i.components[o]=f;const p=(f.__vccOpts||f)[t];return p&&nt(p,n,s,i,o)()}))}}return r}function Au(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function Tr(e){const t=je(Ln),n=je(Is),s=Ae(()=>t.resolve(wt(e.to))),r=Ae(()=>{const{matched:c}=s.value,{length:a}=c,f=c[a-1],h=n.matched;if(!f||!h.length)return-1;const p=h.findIndex(St.bind(null,f));if(p>-1)return p;const _=Ar(c[a-2]);return a>1&&Ar(f)===_&&h[h.length-1].path!==_?h.findIndex(St.bind(null,c[a-2])):p}),i=Ae(()=>r.value>-1&&Iu(n.params,s.value.params)),o=Ae(()=>r.value>-1&&r.value===n.matched.length-1&&Di(n.params,s.value.params));function l(c={}){return Mu(c)?t[wt(e.replace)?"replace":"push"](wt(e.to)).catch(Wt):Promise.resolve()}return{route:s,href:Ae(()=>s.value.href),isActive:i,isExactActive:o,navigate:l}}const Ou=Rs({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},useLink:Tr,setup(e,{slots:t}){const n=tn(Tr(e)),{options:s}=je(Ln),r=Ae(()=>({[Or(e.activeClass,s.linkActiveClass,"router-link-active")]:n.isActive,[Or(e.exactActiveClass,s.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive}));return()=>{const i=t.default&&t.default(n);return e.custom?i:Ss("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:r.value},i)}}}),Su=Ou;function Mu(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function Iu(e,t){for(const n in t){const s=t[n],r=e[n];if(typeof s=="string"){if(s!==r)return!1}else if(!Be(r)||r.length!==s.length||s.some((i,o)=>i!==r[o]))return!1}return!0}function Ar(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Or=(e,t,n)=>e??t??n,Nu=Rs({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){const s=je(ls),r=Ae(()=>e.route||s.value),i=je(Pr,0),o=Ae(()=>{let a=wt(i);const{matched:f}=r.value;let h;for(;(h=f[a])&&!h.components;)a++;return a}),l=Ae(()=>r.value.matched[o.value]);gn(Pr,Ae(()=>o.value+1)),gn(Tu,l),gn(ls,r);const c=pn();return mn(()=>[c.value,l.value,e.name],([a,f,h],[p,_,C])=>{f&&(f.instances[h]=a,_&&_!==f&&a&&a===p&&(f.leaveGuards.size||(f.leaveGuards=_.leaveGuards),f.updateGuards.size||(f.updateGuards=_.updateGuards))),a&&f&&(!_||!St(f,_)||!p)&&(f.enterCallbacks[h]||[]).forEach(T=>T(a))},{flush:"post"}),()=>{const a=r.value,f=e.name,h=l.value,p=h&&h.components[f];if(!p)return Sr(n.default,{Component:p,route:a});const _=h.props[f],C=_?_===!0?a.params:typeof _=="function"?_(a):_:null,$=Ss(p,se({},C,t,{onVnodeUnmounted:g=>{g.component.isUnmounted&&(h.instances[f]=null)},ref:c}));return Sr(n.default,{Component:$,route:a})||$}}});function Sr(e,t){if(!e)return null;const n=e(t);return n.length===1?n[0]:n}const Fu=Nu;function of(e){const t=cu(e.routes,e),n=e.parseQuery||Ru,s=e.stringifyQuery||Rr,r=e.history,i=kt(),o=kt(),l=kt(),c=Wo(Ge);let a=Ge;bt&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const f=Vn.bind(null,v=>""+v),h=Vn.bind(null,wu),p=Vn.bind(null,Rn);function _(v,I){let O,H;return Ki(v)?(O=t.getRecordMatcher(v),H=I):H=v,t.addRoute(H,O)}function C(v){const I=t.getRecordMatcher(v);I&&t.removeRoute(I)}function T(){return t.getRoutes().map(v=>v.record)}function $(v){return!!t.getRecordMatcher(v)}function g(v,I){if(I=se({},I||c.value),typeof v=="string"){const u=zn(n,v,I.path),d=t.resolve({path:u.path},I),m=r.createHref(u.fullPath);return se(u,d,{params:p(d.params),hash:Rn(u.hash),redirectedFrom:void 0,href:m})}let O;if("path"in v)O=se({},v,{path:zn(n,v.path,I.path).path});else{const u=se({},v.params);for(const d in u)u[d]==null&&delete u[d];O=se({},v,{params:h(v.params)}),I.params=h(I.params)}const H=t.resolve(O,I),te=v.hash||"";H.params=f(p(H.params));const fe=Hc(s,se({},v,{hash:Eu(te),path:H.path})),Y=r.createHref(fe);return se({fullPath:fe,hash:te,query:s===Rr?Pu(v.query):v.query||{}},H,{redirectedFrom:void 0,href:Y})}function y(v){return typeof v=="string"?zn(n,v,c.value.path):se({},v)}function P(v,I){if(a!==v)return Mt(8,{from:I,to:v})}function k(v){return z(v)}function D(v){return k(se(y(v),{replace:!0}))}function J(v){const I=v.matched[v.matched.length-1];if(I&&I.redirect){const{redirect:O}=I;let H=typeof O=="function"?O(v):O;return typeof H=="string"&&(H=H.includes("?")||H.includes("#")?H=y(H):{path:H},H.params={}),se({query:v.query,hash:v.hash,params:"path"in H?{}:v.params},H)}}function z(v,I){const O=a=g(v),H=c.value,te=v.state,fe=v.force,Y=v.replace===!0,u=J(O);if(u)return z(se(y(u),{state:typeof u=="object"?se({},te,u.state):te,force:fe,replace:Y}),I||O);const d=O;d.redirectedFrom=I;let m;return!fe&&jc(s,H,O)&&(m=Mt(16,{to:d,from:H}),lt(H,H,!0,!1)),(m?Promise.resolve(m):q(d,H)).catch(b=>qe(b)?qe(b,2)?b:Ie(b):oe(b,d,H)).then(b=>{if(b){if(qe(b,2))return z(se({replace:Y},y(b.to),{state:typeof b.to=="object"?se({},te,b.to.state):te,force:fe}),I||d)}else b=Z(d,H,!0,Y,te);return K(d,H,b),b})}function S(v,I){const O=P(v,I);return O?Promise.reject(O):Promise.resolve()}function q(v,I){let O;const[H,te,fe]=Lu(v,I);O=Qn(H.reverse(),"beforeRouteLeave",v,I);for(const u of H)u.leaveGuards.forEach(d=>{O.push(nt(d,v,I))});const Y=S.bind(null,v,I);return O.push(Y),yt(O).then(()=>{O=[];for(const u of i.list())O.push(nt(u,v,I));return O.push(Y),yt(O)}).then(()=>{O=Qn(te,"beforeRouteUpdate",v,I);for(const u of te)u.updateGuards.forEach(d=>{O.push(nt(d,v,I))});return O.push(Y),yt(O)}).then(()=>{O=[];for(const u of v.matched)if(u.beforeEnter&&!I.matched.includes(u))if(Be(u.beforeEnter))for(const d of u.beforeEnter)O.push(nt(d,v,I));else O.push(nt(u.beforeEnter,v,I));return O.push(Y),yt(O)}).then(()=>(v.matched.forEach(u=>u.enterCallbacks={}),O=Qn(fe,"beforeRouteEnter",v,I),O.push(Y),yt(O))).then(()=>{O=[];for(const u of o.list())O.push(nt(u,v,I));return O.push(Y),yt(O)}).catch(u=>qe(u,8)?u:Promise.reject(u))}function K(v,I,O){for(const H of l.list())H(v,I,O)}function Z(v,I,O,H,te){const fe=P(v,I);if(fe)return fe;const Y=I===Ge,u=bt?history.state:{};O&&(H||Y?r.replace(v.fullPath,se({scroll:Y&&u&&u.scroll},te)):r.push(v.fullPath,te)),c.value=v,lt(v,I,O,Y),Ie()}let N;function Q(){N||(N=r.listen((v,I,O)=>{if(!rn.listening)return;const H=g(v),te=J(H);if(te){z(se(te,{replace:!0}),H).catch(Wt);return}a=H;const fe=c.value;bt&&zc(_r(fe.fullPath,O.delta),Fn()),q(H,fe).catch(Y=>qe(Y,12)?Y:qe(Y,2)?(z(Y.to,H).then(u=>{qe(u,20)&&!O.delta&&O.type===Gt.pop&&r.go(-1,!1)}).catch(Wt),Promise.reject()):(O.delta&&r.go(-O.delta,!1),oe(Y,H,fe))).then(Y=>{Y=Y||Z(H,fe,!1),Y&&(O.delta&&!qe(Y,8)?r.go(-O.delta,!1):O.type===Gt.pop&&qe(Y,20)&&r.go(-1,!1)),K(H,fe,Y)}).catch(Wt)}))}let L=kt(),_e=kt(),ee;function oe(v,I,O){Ie(v);const H=_e.list();return H.length?H.forEach(te=>te(v,I,O)):console.error(v),Promise.reject(v)}function re(){return ee&&c.value!==Ge?Promise.resolve():new Promise((v,I)=>{L.add([v,I])})}function Ie(v){return ee||(ee=!v,Q(),L.list().forEach(([I,O])=>v?O(v):I()),L.reset()),v}function lt(v,I,O,H){const{scrollBehavior:te}=e;if(!bt||!te)return Promise.resolve();const fe=!O&&Qc(_r(v.fullPath,0))||(H||!O)&&history.state&&history.state.scroll||null;return ni().then(()=>te(v,I,fe)).then(Y=>Y&&Vc(Y)).catch(Y=>oe(Y,v,I))}const Ne=v=>r.go(v);let ve;const mt=new Set,rn={currentRoute:c,listening:!0,addRoute:_,removeRoute:C,hasRoute:$,getRoutes:T,resolve:g,options:e,push:k,replace:D,go:Ne,back:()=>Ne(-1),forward:()=>Ne(1),beforeEach:i.add,beforeResolve:o.add,afterEach:l.add,onError:_e.add,isReady:re,install(v){const I=this;v.component("RouterLink",Su),v.component("RouterView",Fu),v.config.globalProperties.$router=I,Object.defineProperty(v.config.globalProperties,"$route",{enumerable:!0,get:()=>wt(c)}),bt&&!ve&&c.value===Ge&&(ve=!0,k(r.location).catch(te=>{}));const O={};for(const te in Ge)O[te]=Ae(()=>c.value[te]);v.provide(Ln,I),v.provide(Is,tn(O)),v.provide(ls,c);const H=v.unmount;mt.add(v),v.unmount=function(){mt.delete(v),mt.size<1&&(a=Ge,N&&N(),N=null,c.value=Ge,ve=!1,ee=!1),H()}}};return rn}function yt(e){return e.reduce((t,n)=>t.then(()=>n()),Promise.resolve())}function Lu(e,t){const n=[],s=[],r=[],i=Math.max(t.matched.length,e.matched.length);for(let o=0;oSt(a,l))?s.push(l):n.push(l));const c=e.matched[o];c&&(t.matched.find(a=>St(a,c))||r.push(c))}return[n,s,r]}function lf(){return je(Ln)}function cf(){return je(Is)}const uf=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n};export{Ai as $,ju as A,lf as B,gi as C,Du as D,Xu as E,Hu as F,Zu as G,Ju as H,Yu as I,Gu as J,gn as K,Vu as L,ef as M,Tr as N,sf as O,of as P,zu as Q,Su as R,Ge as S,Ni as T,rf as U,Fu as V,jl as W,Ku as X,de as Y,nl as Z,uf as _,zr as a,Oi as a0,Wu as a1,qu as a2,Re as a3,Uu as a4,$u as a5,tn as b,Rs as c,Bu as d,U as e,Qu as f,nf as g,Ae as h,pe as i,Ss as j,Nc as k,tf as l,je as m,Si as n,hi as o,We as p,An as q,pn as r,wt as s,ni as t,cf as u,mi as v,mn as w,go as x,ku as y,Wo as z}; diff --git a/assets/frontmatter.html-397e5aab.js b/assets/frontmatter.html-397e5aab.js new file mode 100644 index 00000000..6367fcb0 --- /dev/null +++ b/assets/frontmatter.html-397e5aab.js @@ -0,0 +1,30 @@ +import{_ as c,W as u,X as d,Y as t,$ as n,a0 as a,Z as s,a1 as o,D as l}from"./framework-46b0e263.js";const r={},m=n("h1",{id:"frontmatter",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),a(" Frontmatter")],-1),k=n("h2",{id:"date",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#date","aria-hidden":"true"},"#"),a(" date")],-1),h=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),_=n("p",null,"详情:",-1),v=n("p",null,"页面的创建日期。",-1),g=n("code",null,"yyyy-MM-dd",-1),f={href:"https://yaml.org/type/timestamp.html",target:"_blank",rel:"noopener noreferrer"},b=n("p",null,"参考:",-1),y=n("h2",{id:"description",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#description","aria-hidden":"true"},"#"),a(" description")],-1),x=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),P=n("li",null,[n("p",null,"详情:"),n("p",null,"页面的描述。"),n("p",null,[a("它将会覆盖站点配置中的 "),n("code",null,"description"),a(" 配置项。")])],-1),w=n("p",null,"参考:",-1),q=o(` # head
类型:
HeadConfig[]
详情:
页面
<head>
标签内添加的额外标签。示例:
--- +head: + - - meta + - name: foo + content: yaml 数组语法 + - [meta, { name: bar, content: 方括号语法 }] +--- +
渲染为:
`,5),M=n("h2",{id:"lang",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#lang","aria-hidden":"true"},"#"),a(" lang")],-1),z=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),F=n("li",null,[n("p",null,"详情:"),n("p",null,"页面的语言。"),n("p",null,[a("它将会覆盖站点配置中的 "),n("code",null,"lang"),a(" 配置项")])],-1),N=n("p",null,"参考:",-1),C=o(`<head> + <meta name="foo" content="yaml 数组语法" /> + <meta name="bar" content="方括号语法" /> +</head> +
# layout
类型:
string
详情:
页面的布局。
布局是由主题提供的。如果你不指定该 Frontmatter ,则会使用默认布局。你应该参考主题自身的文档来了解其提供了哪些布局。
如果主题布局无法满足你的需求,你可以使用自定义布局组件。
示例:
在
.vuepress/client.ts
文件中注册一个布局组件:import { defineClientConfig } from "@vuepress/client"; +import CustomLayout from "./CustomLayout.vue"; + +export default defineClientConfig({ + layouts: { + CustomLayout, + }, +}); +
在 Frontmatter 中设置自定义布局:
--- +layout: CustomLayout +--- +
# permalink
`,7),L=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),A=n("li",null,[n("p",null,"详情:"),n("p",null,"页面的永久链接。"),n("p",null,"它将会覆盖根据文件路径来决定的默认路由路径。")],-1),I=n("p",null,"参考:",-1),B=n("li",null,[n("a",{href:"#permalinkpattern"},"Frontmatter > permalinkPattern")],-1),E=o(`# permalinkPattern
类型:
string | null
详情:
为页面生成永久链接的 Pattern 。
它将会覆盖站点配置中的
permalinkPattern
配置项。如果 Frontmatter 中设置了
permalink
,那么这个字段则不会生效。使用:
Pattern 描述 :year
创建日期的 年 部分 :month
创建日期的 月 部分 :day
创建日期的 日 部分 :slug
页面文件名的 Slug :raw
原始路由路径
:year
,:month
和:day
Pattern 根据如下优先级进行解析:
- Frontmatter 中的
date
字段。- 符合
yyyy-MM-dd-foobar.md
或yyyy-MM-foobar.md
日期格式的文件名。- 符合
yyyy/MM/dd/foobar.md
或yyyy/MM/foobar.md
日期格式的目录名。- 默认值
0000-00-00
。示例 1 :
页面文件名是
foo-bar.md
。页面 Frontmatter 是:
--- +date: 2021-01-03 +permalinkPattern: :year/:month/:day/:slug.html +--- +
那么页面的永久链接将会是
2021/01/03/foo-bar.html
。
示例 2 :
页面文件名是
2021-01-03-bar-baz.md
。页面 Frontmatter 是:
--- +permalinkPattern: :year/:month/:day/:slug.html +--- +
那么页面的永久链接将会是
`,7),V=n("li",null,[n("a",{href:"#date"},"Frontmatter > date")],-1),R=n("li",null,[n("a",{href:"#permalink"},"Frontmatter > permalink")],-1),T=n("h2",{id:"routemeta",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#routemeta","aria-hidden":"true"},"#"),a(" routeMeta")],-1),S=n("li",null,[n("p",null,[a("类型: "),n("code",null,"Record2021/01/03/bar-baz.html
。")])],-1),Y=n("li",null,[n("p",null,"详情:"),n("p",null,"附加到页面路由的自定义数据。")],-1),D=n("p",null,"参考:",-1),H=n("h2",{id:"title",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#title","aria-hidden":"true"},"#"),a(" title")],-1),W=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),X=n("li",null,[n("p",null,"详情:"),n("p",null,"页面的标题。"),n("p",null,[a("如果你不在 Frontmatter 中设置 "),n("code",null,"title"),a(" ,那么页面中第一个一级标题(即 "),n("code",null,"# title"),a(")的内容会被当作标题使用。")])],-1),Z=n("p",null,"参考:",-1);function $(j,G){const p=l("NpmBadge"),i=l("ExternalLinkIcon"),e=l("RouterLink");return u(),d("div",null,[m,t(p,{package:"@vuepress/client"}),t(p,{package:"@vuepress/markdown"}),k,n("ul",null,[h,n("li",null,[_,v,n("p",null,[a("应按照 "),g,a(" 的格式来指定日期,或者遵循 "),n("a",f,[a("YAML Timestamp Type"),t(i)]),a(" 。")])]),n("li",null,[b,n("ul",null,[n("li",null,[t(e,{to:"/zh/reference/node-api.html#date"},{default:s(()=>[a("Node API > Page 属性 > date")]),_:1})])])])]),y,n("ul",null,[x,P,n("li",null,[w,n("ul",null,[n("li",null,[t(e,{to:"/zh/reference/config.html#description"},{default:s(()=>[a("配置 > description")]),_:1})])])])]),q,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[n("li",null,[t(e,{to:"/zh/reference/config.html#head"},{default:s(()=>[a("配置 > head")]),_:1})])])])]),M,n("ul",null,[z,F,n("li",null,[N,n("ul",null,[n("li",null,[t(e,{to:"/zh/reference/config.html#lang"},{default:s(()=>[a("配置 > lang")]),_:1})]),n("li",null,[t(e,{to:"/zh/reference/node-api.html#lang"},{default:s(()=>[a("Node API > Page 属性 > lang")]),_:1})])])])]),C,n("ul",null,[L,A,n("li",null,[I,n("ul",null,[B,n("li",null,[t(e,{to:"/zh/guide/page.html#%E8%B7%AF%E7%94%B1"},{default:s(()=>[a("指南 > 页面 > 路由")]),_:1})]),n("li",null,[t(e,{to:"/zh/reference/node-api.html#permalink"},{default:s(()=>[a("Node API > Page 属性 > permalink")]),_:1})])])])]),E,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[n("li",null,[t(e,{to:"/zh/reference/config.html#permalinkpattern"},{default:s(()=>[a("配置 > permalinkPattern")]),_:1})]),V,R,n("li",null,[t(e,{to:"/zh/reference/node-api.html#permalink"},{default:s(()=>[a("Node API > Page 属性 > permalink")]),_:1})])])])]),T,n("ul",null,[S,Y,n("li",null,[D,n("ul",null,[n("li",null,[t(e,{to:"/zh/reference/node-api.html#routeMeta"},{default:s(()=>[a("Node API > Page 属性 > routeMeta")]),_:1})])])])]),H,n("ul",null,[W,X,n("li",null,[Z,n("ul",null,[n("li",null,[t(e,{to:"/zh/reference/node-api.html#title"},{default:s(()=>[a("Node API > Page 属性 > title")]),_:1})])])])])])}const K=c(r,[["render",$],["__file","frontmatter.html.vue"]]);export{K as default}; diff --git a/assets/frontmatter.html-457ea87f.js b/assets/frontmatter.html-457ea87f.js new file mode 100644 index 00000000..7ae0f1f5 --- /dev/null +++ b/assets/frontmatter.html-457ea87f.js @@ -0,0 +1,60 @@ +import{_ as c,W as d,X as p,Y as a,$ as n,a0 as e,Z as l,a1 as t,D as i}from"./framework-46b0e263.js";const r={},h=n("h1",{id:"frontmatter",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),e(" Frontmatter")],-1),m=n("h2",{id:"所有页面",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#所有页面","aria-hidden":"true"},"#"),e(" 所有页面")],-1),k=n("p",null,"本章节中的 Frontmatter 会在所有类型的页面中生效。",-1),v=n("h3",{id:"externallinkicon",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#externallinkicon","aria-hidden":"true"},"#"),e(" externalLinkIcon")],-1),_=n("li",null,[n("p",null,[e("类型: "),n("code",null,"boolean")])],-1),b=n("p",null,"详情:",-1),g=n("p",null,"参考:",-1),f=n("h3",{id:"navbar",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#navbar","aria-hidden":"true"},"#"),e(" navbar")],-1),x=n("li",null,[n("p",null,[e("类型: "),n("code",null,"boolean")])],-1),y=n("li",null,[n("p",null,"详情:"),n("p",null,"是否在当前页面展示导航栏。"),n("p",null,"如果你在主题配置中禁用了导航栏,那么该 Frontmatter 将不会生效。")],-1),L=n("p",null,"参考:",-1),w=t(` # pageClass
类型:
string
详情:
为当前页面添加额外的类名。
示例:
--- +pageClass: custom-page-class +--- +
然后你可以在
.vuepress/styles/index.scss
文件中为这个页面添加自定义样式:`,5),z=t(`.theme-container.custom-page-class { + /* 页面样式 */ +} +
# 首页
本章节中的 Frontmatter 只会在首页中生效。
# home
类型:
boolean
详情:
设定该页面是首页还是普通页面。
如果你不设置该 Frontmatter 或将其设为
false
,则该页面会是一个 普通页面示例:
--- +home: true +--- +
# heroImage
`,5),N=t(`类型:
string
详情:
首页图片的 URL 。
`,3),B=n("p",null,"参考:",-1),E=n("h3",{id:"heroimagedark",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#heroimagedark","aria-hidden":"true"},"#"),e(" heroImageDark")],-1),F=n("li",null,[n("p",null,[e("类型: "),n("code",null,"string")])],-1),A=n("li",null,[n("p",null,"详情:"),n("p",null,"在夜间模式中使用的首页图片的 URL 。"),n("p",null,"如果你想在夜间模式中使用不同的首页图片,就可以使用该配置项。")],-1),I=n("p",null,"参考:",-1),S=n("li",null,[n("a",{href:"#heroimage"},"默认主题 > Frontmatter > heroImage")],-1),V=t(' 示例:
--- +# Public 文件路径 +heroImage: /images/hero.png +# URL +heroImage: https://vuejs.org/images/logo.png +--- +
# heroAlt
类型:
string
详情:
首页图片的
alt
属性。如果不设置,则默认使用 heroText 。
# heroHeight
',3),C=n("li",null,[n("p",null,[e("类型: "),n("code",null,"number")])],-1),P=n("li",null,[n("p",null,[e("默认值: "),n("code",null,"280")])],-1),T=n("p",null,"详情:",-1),H=n("p",null,[e("首页图片 "),n("code",null,""),e(" 标签的 "),n("code",null,"height"),e(" 属性。")],-1),M=n("p",null,"当你的首页图片高度小于默认值时,你可能需要减小该属性。",-1),R={href:"https://web.dev/cls/",target:"_blank",rel:"noopener noreferrer"},U=n("h3",{id:"herotext",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#herotext","aria-hidden":"true"},"#"),e(" heroText")],-1),D=n("li",null,[n("p",null,[e("类型: "),n("code",null,"string | null")])],-1),q=n("p",null,"详情:",-1),j=n("p",null,"首页的大标题。",-1),G=n("p",null,[e("设置为 "),n("code",null,"null"),e(" 来禁用首页大标题。")],-1),O=n("h3",{id:"tagline",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#tagline","aria-hidden":"true"},"#"),e(" tagline")],-1),W=n("li",null,[n("p",null,[e("类型: "),n("code",null,"string | null")])],-1),X=n("p",null,"详情:",-1),Y=n("p",null,"首页的标语。",-1),Z=n("p",null,[e("设置为 "),n("code",null,"null"),e(" 来禁用首页标语。")],-1),$=t(`
# actions
- 类型:
Array<{ + text: string; + link: string; + type?: "primary" | "secondary"; +}>; +
详情:
配置首页按钮。
示例:
--- +actions: + - text: 快速上手 + link: /zh/guide/getting-started.html + type: primary + - text: 项目简介 + link: /guide/ + type: secondary +--- +
# features
- 类型:
Array<{ + title: string; + details: string; +}>; +
详情:
配置首页特性列表。
示例:
--- +features: + - title: 简洁至上 + details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。 + - title: Vue 驱动 + details: 享受 Vue 的开发体验,可以在 Markdown 中使用 Vue 组件,又可以使用 Vue 来开发自定义主题。 + - title: 高性能 + details: VuePress 会为每个页面预渲染生成静态的 HTML,同时,每个页面被加载的时候,将作为 SPA 运行。 +--- +
# footer
类型:
string
详情:
首页的页脚。
# footerHtml
类型:
boolean
详情:
是否允许页脚中使用 HTML 。
如果设置为
true
,那么 footer 会被作为 HTML 代码处理。# 普通页面
本章节中的 Frontmatter 只会在普通页面中生效。
# editLink
`,17),J=n("li",null,[n("p",null,[e("类型: "),n("code",null,"boolean")])],-1),K=n("li",null,[n("p",null,"详情:"),n("p",null,[e("是否在本页面中启用 "),n("em",null,"编辑此页"),e(" 链接。")])],-1),Q=n("p",null,"参考:",-1),nn=n("h3",{id:"editlinkpattern",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#editlinkpattern","aria-hidden":"true"},"#"),e(" editLinkPattern")],-1),en=n("li",null,[n("p",null,[e("类型: "),n("code",null,"string")])],-1),an=n("li",null,[n("p",null,"详情:"),n("p",null,[e("本页面中 "),n("em",null,"编辑此页"),e(" 链接的 Pattern 。")])],-1),sn=n("p",null,"参考:",-1),ln=n("h3",{id:"lastupdated",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#lastupdated","aria-hidden":"true"},"#"),e(" lastUpdated")],-1),tn=n("li",null,[n("p",null,[e("类型: "),n("code",null,"boolean")])],-1),on=n("li",null,[n("p",null,"详情:"),n("p",null,[e("是否在本页面中启用 "),n("em",null,"最近更新时间戳"),e(" 。")])],-1),un=n("p",null,"参考:",-1),cn=n("h3",{id:"contributors",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#contributors","aria-hidden":"true"},"#"),e(" contributors")],-1),dn=n("li",null,[n("p",null,[e("类型: "),n("code",null,"boolean")])],-1),pn=n("li",null,[n("p",null,"详情:"),n("p",null,[e("是否在本页面中启用 "),n("em",null,"贡献者列表"),e(" 。")])],-1),rn=n("p",null,"参考:",-1),hn=n("h3",{id:"sidebar",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#sidebar","aria-hidden":"true"},"#"),e(" sidebar")],-1),mn=n("li",null,[n("p",null,[e("类型: "),n("code",null,"false | 'auto' | SidebarConfigArray | SidebarConfigObject")])],-1),kn=n("li",null,[n("p",null,"详情:"),n("p",null,"配置本页面的侧边栏。")],-1),vn=n("p",null,"参考:",-1),_n=n("h3",{id:"sidebardepth",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#sidebardepth","aria-hidden":"true"},"#"),e(" sidebarDepth")],-1),bn=n("li",null,[n("p",null,[e("类型: "),n("code",null,"number")])],-1),gn=n("li",null,[n("p",null,"详情:"),n("p",null,"配置本页面的侧边栏深度。")],-1),fn=n("p",null,"参考:",-1),xn=t(`# prev
类型:
NavLink | string
详情:
上一个页面的链接。
如果你不设置该 Frontmatter ,该链接会自动根据侧边栏配置进行推断。
为了手动配置上一页面的链接,你可以将其设置为一个
NavLink
对象或者一个字符串:
NavLink
对象应该有一个text
字段和一个link
字段。- 字符串应为目标页面文件的路径。它将会被转换为
NavLink
对象,将页面标题作为text
,将页面路由路径作为link
。示例:
--- +# NavLink +prev: + text: Get Started + link: /guide/getting-started.html + +# NavLink - 外部 URL +prev: + text: GitHub + link: https://github.com + +# 字符串 - 页面文件路径 +prev: /guide/getting-started.md + +# 字符串 - 页面文件相对路径 +prev: ../../guide/getting-started.md +--- +
# next
`,5);function yn(Ln,wn){const o=i("NpmBadge"),s=i("RouterLink"),u=i("ExternalLinkIcon");return d(),p("div",null,[h,a(o,{package:"@vuepress/theme-default"}),m,k,v,n("ul",null,[_,n("li",null,[b,n("p",null,[e("由"),a(s,{to:"/zh/reference/plugin/external-link-icon.html#externallinkicon"},{default:l(()=>[e("@vuepress/plugin-external-link-icon")]),_:1}),e(" 提供。")])]),n("li",null,[g,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#themeplugins-externallinkicon"},{default:l(()=>[e("默认主题 > 配置 > themePlugins.externalLinkIcon")]),_:1})])])])]),f,n("ul",null,[x,y,n("li",null,[L,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#navbar"},{default:l(()=>[e("默认主题 > 配置 > navbar")]),_:1})])])])]),w,n("ul",null,[n("li",null,[e("参考: "),n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/styles.html#style-%E6%96%87%E4%BB%B6"},{default:l(()=>[e("默认主题 > 样式 > Style 文件")]),_:1})])])])]),z,n("ul",null,[N,n("li",null,[B,n("ul",null,[n("li",null,[a(s,{to:"/zh/guide/assets.html#public-%E6%96%87%E4%BB%B6"},{default:l(()=>[e("指南 > 静态资源 > Public 文件")]),_:1})])])])]),E,n("ul",null,[F,A,n("li",null,[I,n("ul",null,[S,n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#colormode"},{default:l(()=>[e("默认主题 > 配置 > colorMode")]),_:1})])])])]),V,n("ul",null,[C,P,n("li",null,[T,H,M,n("p",null,[e("需要注意的是,首页图片的高度同样受到了 CSS 的约束。设置这个属性主要是为了减少由加载首页图片引起的 "),n("a",R,[e("累积布局偏移 (CLS)"),a(u)]),e(" 。")])])]),U,n("ul",null,[D,n("li",null,[q,j,n("p",null,[e("如果不设置,则默认使用站点 "),a(s,{to:"/zh/reference/config.html#title"},{default:l(()=>[e("title")]),_:1}),e(" 。")]),G])]),O,n("ul",null,[W,n("li",null,[X,Y,n("p",null,[e("如果不设置,则默认使用站点 "),a(s,{to:"/zh/reference/config.html#description"},{default:l(()=>[e("description")]),_:1}),e(" 。")]),Z])]),$,n("ul",null,[J,K,n("li",null,[Q,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#editlink"},{default:l(()=>[e("默认主题 > 配置 > editLink")]),_:1})])])])]),nn,n("ul",null,[en,an,n("li",null,[sn,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#editlinkpattern"},{default:l(()=>[e("默认主题 > 配置 > editLinkPattern")]),_:1})])])])]),ln,n("ul",null,[tn,on,n("li",null,[un,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#lastupdated"},{default:l(()=>[e("默认主题 > 配置 > lastUpdated")]),_:1})])])])]),cn,n("ul",null,[dn,pn,n("li",null,[rn,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#contributors"},{default:l(()=>[e("默认主题 > 配置 > contributors")]),_:1})])])])]),hn,n("ul",null,[mn,kn,n("li",null,[vn,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#sidebar"},{default:l(()=>[e("默认主题 > 配置 > sidebar")]),_:1})])])])]),_n,n("ul",null,[bn,gn,n("li",null,[fn,n("ul",null,[n("li",null,[a(s,{to:"/zh/reference/default-theme/config.html#sidebardepth"},{default:l(()=>[e("默认主题 > 配置 > sidebarDepth")]),_:1})])])])]),xn])}const Nn=c(r,[["render",yn],["__file","frontmatter.html.vue"]]);export{Nn as default}; diff --git a/assets/frontmatter.html-5c8a8e5d.js b/assets/frontmatter.html-5c8a8e5d.js new file mode 100644 index 00000000..415baf83 --- /dev/null +++ b/assets/frontmatter.html-5c8a8e5d.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3590f0ec","path":"/reference/frontmatter.html","title":"Frontmatter","lang":"en-US","frontmatter":{"icon":"fa-solid:bars","description":"date Type: string; Details:; Created date for the page. You should specify the date in the form of yyyy-MM-dd, or follow the YAML Timestamp Type (https://yaml.org/type/timestamp...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/frontmatter.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/frontmatter.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Frontmatter"}],["meta",{"property":"og:description","content":"date Type: string; Details:; Created date for the page. You should specify the date in the form of yyyy-MM-dd, or follow the YAML Timestamp Type (https://yaml.org/type/timestamp..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Frontmatter\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"date","slug":"date","link":"#date","children":[]},{"level":2,"title":"description","slug":"description","link":"#description","children":[]},{"level":2,"title":"head","slug":"head","link":"#head","children":[]},{"level":2,"title":"lang","slug":"lang","link":"#lang","children":[]},{"level":2,"title":"layout","slug":"layout","link":"#layout","children":[]},{"level":2,"title":"permalink","slug":"permalink","link":"#permalink","children":[]},{"level":2,"title":"permalinkPattern","slug":"permalinkpattern","link":"#permalinkpattern","children":[]},{"level":2,"title":"routeMeta","slug":"routemeta","link":"#routemeta","children":[]},{"level":2,"title":"title","slug":"title","link":"#title","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.96,"words":588},"filePathRelative":"reference/frontmatter.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/frontmatter.html-5f732d4f.js b/assets/frontmatter.html-5f732d4f.js new file mode 100644 index 00000000..5a9c455b --- /dev/null +++ b/assets/frontmatter.html-5f732d4f.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-a566dc26","path":"/zh/reference/default-theme/frontmatter.html","title":"Frontmatter","lang":"zh-CN","frontmatter":{"icon":"fa-solid:bars","description":"所有页面 本章节中的 Frontmatter 会在所有类型的页面中生效。 externalLinkIcon 类型: boolean; 详情:; 由@vuepress/plugin-external-link-icon (../plugin/external-link-icon.md#externallinkicon) 提供。 参考:; 默认主题 > 配...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/default-theme/frontmatter.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/default-theme/frontmatter.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Frontmatter"}],["meta",{"property":"og:description","content":"所有页面 本章节中的 Frontmatter 会在所有类型的页面中生效。 externalLinkIcon 类型: boolean; 详情:; 由@vuepress/plugin-external-link-icon (../plugin/external-link-icon.md#externallinkicon) 提供。 参考:; 默认主题 > 配..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Frontmatter\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"所有页面","slug":"所有页面","link":"#所有页面","children":[{"level":3,"title":"externalLinkIcon","slug":"externallinkicon","link":"#externallinkicon","children":[]},{"level":3,"title":"navbar","slug":"navbar","link":"#navbar","children":[]},{"level":3,"title":"pageClass","slug":"pageclass","link":"#pageclass","children":[]}]},{"level":2,"title":"首页","slug":"首页","link":"#首页","children":[{"level":3,"title":"home","slug":"home","link":"#home","children":[]},{"level":3,"title":"heroImage","slug":"heroimage","link":"#heroimage","children":[]},{"level":3,"title":"heroImageDark","slug":"heroimagedark","link":"#heroimagedark","children":[]},{"level":3,"title":"heroAlt","slug":"heroalt","link":"#heroalt","children":[]},{"level":3,"title":"heroHeight","slug":"heroheight","link":"#heroheight","children":[]},{"level":3,"title":"heroText","slug":"herotext","link":"#herotext","children":[]},{"level":3,"title":"tagline","slug":"tagline","link":"#tagline","children":[]},{"level":3,"title":"actions","slug":"actions","link":"#actions","children":[]},{"level":3,"title":"features","slug":"features","link":"#features","children":[]},{"level":3,"title":"footer","slug":"footer","link":"#footer","children":[]},{"level":3,"title":"footerHtml","slug":"footerhtml","link":"#footerhtml","children":[]}]},{"level":2,"title":"普通页面","slug":"普通页面","link":"#普通页面","children":[{"level":3,"title":"editLink","slug":"editlink","link":"#editlink","children":[]},{"level":3,"title":"editLinkPattern","slug":"editlinkpattern","link":"#editlinkpattern","children":[]},{"level":3,"title":"lastUpdated","slug":"lastupdated","link":"#lastupdated","children":[]},{"level":3,"title":"contributors","slug":"contributors","link":"#contributors","children":[]},{"level":3,"title":"sidebar","slug":"sidebar","link":"#sidebar","children":[]},{"level":3,"title":"sidebarDepth","slug":"sidebardepth","link":"#sidebardepth","children":[]},{"level":3,"title":"prev","slug":"prev","link":"#prev","children":[]},{"level":3,"title":"next","slug":"next","link":"#next","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":4.18,"words":1254},"filePathRelative":"zh/reference/default-theme/frontmatter.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/frontmatter.html-60124b9c.js b/assets/frontmatter.html-60124b9c.js new file mode 100644 index 00000000..f34b291d --- /dev/null +++ b/assets/frontmatter.html-60124b9c.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-e5e26a84","path":"/reference/default-theme/frontmatter.html","title":"Frontmatter","lang":"en-US","frontmatter":{"icon":"fa-solid:bars","description":"All Pages Frontmatter in this section will take effect in all types of pages. externalLinkIcon Type: boolean; Details:; Provided by @vuepress/plugin-external-link-icon (../plugi...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/default-theme/frontmatter.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/default-theme/frontmatter.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Frontmatter"}],["meta",{"property":"og:description","content":"All Pages Frontmatter in this section will take effect in all types of pages. externalLinkIcon Type: boolean; Details:; Provided by @vuepress/plugin-external-link-icon (../plugi..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Frontmatter\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"All Pages","slug":"all-pages","link":"#all-pages","children":[{"level":3,"title":"externalLinkIcon","slug":"externallinkicon","link":"#externallinkicon","children":[]},{"level":3,"title":"navbar","slug":"navbar","link":"#navbar","children":[]},{"level":3,"title":"pageClass","slug":"pageclass","link":"#pageclass","children":[]}]},{"level":2,"title":"Home Page","slug":"home-page","link":"#home-page","children":[{"level":3,"title":"home","slug":"home","link":"#home","children":[]},{"level":3,"title":"heroImage","slug":"heroimage","link":"#heroimage","children":[]},{"level":3,"title":"heroImageDark","slug":"heroimagedark","link":"#heroimagedark","children":[]},{"level":3,"title":"heroAlt","slug":"heroalt","link":"#heroalt","children":[]},{"level":3,"title":"heroHeight","slug":"heroheight","link":"#heroheight","children":[]},{"level":3,"title":"heroText","slug":"herotext","link":"#herotext","children":[]},{"level":3,"title":"tagline","slug":"tagline","link":"#tagline","children":[]},{"level":3,"title":"actions","slug":"actions","link":"#actions","children":[]},{"level":3,"title":"features","slug":"features","link":"#features","children":[]},{"level":3,"title":"footer","slug":"footer","link":"#footer","children":[]},{"level":3,"title":"footerHtml","slug":"footerhtml","link":"#footerhtml","children":[]}]},{"level":2,"title":"Normal Page","slug":"normal-page","link":"#normal-page","children":[{"level":3,"title":"editLink","slug":"editlink","link":"#editlink","children":[]},{"level":3,"title":"editLinkPattern","slug":"editlinkpattern","link":"#editlinkpattern","children":[]},{"level":3,"title":"lastUpdated","slug":"lastupdated","link":"#lastupdated","children":[]},{"level":3,"title":"contributors","slug":"contributors","link":"#contributors","children":[]},{"level":3,"title":"sidebar","slug":"sidebar","link":"#sidebar","children":[]},{"level":3,"title":"sidebarDepth","slug":"sidebardepth","link":"#sidebardepth","children":[]},{"level":3,"title":"prev","slug":"prev","link":"#prev","children":[]},{"level":3,"title":"next","slug":"next","link":"#next","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.91,"words":874},"filePathRelative":"reference/default-theme/frontmatter.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/frontmatter.html-9281febe.js b/assets/frontmatter.html-9281febe.js new file mode 100644 index 00000000..07856d27 --- /dev/null +++ b/assets/frontmatter.html-9281febe.js @@ -0,0 +1,30 @@ +import{_ as u,W as c,X as d,Y as e,$ as n,a0 as a,Z as s,a1 as o,D as l}from"./framework-46b0e263.js";const r={},m=n("h1",{id:"frontmatter",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),a(" Frontmatter")],-1),h=n("h2",{id:"date",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#date","aria-hidden":"true"},"#"),a(" date")],-1),k=n("li",null,[n("p",null,[a("Type: "),n("code",null,"string")])],-1),f=n("p",null,"Details:",-1),g=n("p",null,"Created date for the page.",-1),y=n("code",null,"yyyy-MM-dd",-1),v={href:"https://yaml.org/type/timestamp.html",target:"_blank",rel:"noopener noreferrer"},_=n("p",null,"Also see:",-1),b=n("h2",{id:"description",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#description","aria-hidden":"true"},"#"),a(" description")],-1),x=n("li",null,[n("p",null,[a("Type: "),n("code",null,"string")])],-1),w=n("li",null,[n("p",null,"Details:"),n("p",null,"Description for the page."),n("p",null,[a("This will override the "),n("code",null,"description"),a(" option in your site config.")])],-1),P=n("p",null,"Also see:",-1),T=o(`
类型:
NavLink | string
详情:
下一个页面的链接。
如果你不设置该 Frontmatter ,该链接会自动根据侧边栏配置进行推断。
类型和 prev Frontmatter 相同。
# head
Type:
HeadConfig[]
Details:
Extra tags in
<head>
tag for the page.Example:
--- +head: + - - meta + - name: foo + content: yaml array syntax + - [meta, { name: bar, content: square brackets syntax }] +--- +
Rendered as:
`,5),q=n("h2",{id:"lang",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#lang","aria-hidden":"true"},"#"),a(" lang")],-1),C=n("li",null,[n("p",null,[a("Type: "),n("code",null,"string")])],-1),A=n("li",null,[n("p",null,"Details:"),n("p",null,"Language for the page."),n("p",null,[a("This will override the "),n("code",null,"lang"),a(" option in your site config.")])],-1),M=n("p",null,"Also see:",-1),D=o(`<head> + <meta name="foo" content="yaml array syntax" /> + <meta name="bar" content="square brackets syntax" /> +</head> +
# layout
Type:
string
Details:
Layout for the page.
Layouts are provided by theme. If you don't specify this frontmatter, the default layout will be used. You should refer to the theme's own documentation to find what layouts it provides.
If the theme layouts cannot meet your needs, you can use a custom layout component.
Example:
Register a layout component in
.vuepress/client.ts
file:import { defineClientConfig } from "@vuepress/client"; +import CustomLayout from "./CustomLayout.vue"; + +export default defineClientConfig({ + layouts: { + CustomLayout, + }, +}); +
Set custom layout in frontmatter:
--- +layout: CustomLayout +--- +
# permalink
`,7),L=n("li",null,[n("p",null,[a("Type: "),n("code",null,"string")])],-1),N=n("li",null,[n("p",null,"Details:"),n("p",null,"Permalink for the page."),n("p",null,"This will override the default route path that determined by the file path of the page.")],-1),I=n("p",null,"Also see:",-1),E=n("li",null,[n("a",{href:"#permalinkpattern"},"Frontmatter > permalinkPattern")],-1),R=o(`# permalinkPattern
Type:
string | null
Details:
Pattern to generate permalink for the page.
This will override the
permalinkPattern
option in your site config.This won't take effect if the
permalink
frontmatter has been set.Usage:
Pattern Description :year
Year part of created date :month
Month part of created date :day
Day part of created date :slug
Slug of page filename :raw
Raw route path The
:year
,:month
and:day
patterns are resolved according to the following priority:
- The
date
frontmatter.- The filename that matches the date pattern
yyyy-MM-dd-foobar.md
oryyyy-MM-foobar.md
.- The dirname that matches the date pattern
yyyy/MM/dd/foobar.md
oryyyy/MM/foobar.md
.- Fallback to
0000-00-00
.Example 1:
The page filename is
foo-bar.md
.The page frontmatter is:
--- +date: 2021-01-03 +permalinkPattern: :year/:month/:day/:slug.html +--- +
Then the permalink of the page would be
2021/01/03/foo-bar.html
.
Example 2:
The page filename is
2021-01-03-bar-baz.md
.The page frontmatter is:
--- +permalinkPattern: :year/:month/:day/:slug.html +--- +
Then the permalink of the page would be
`,7),B=n("li",null,[n("a",{href:"#date"},"Frontmatter > date")],-1),F=n("li",null,[n("a",{href:"#permalink"},"Frontmatter > permalink")],-1),Y=n("h2",{id:"routemeta",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#routemeta","aria-hidden":"true"},"#"),a(" routeMeta")],-1),V=n("li",null,[n("p",null,[a("Type: "),n("code",null,"Record2021/01/03/bar-baz.html
.")])],-1),S=n("li",null,[n("p",null,"Details:"),n("p",null,"Custom data to be attached to the page route.")],-1),z=n("p",null,"Also see:",-1),G=n("h2",{id:"title",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#title","aria-hidden":"true"},"#"),a(" title")],-1),H=n("li",null,[n("p",null,[a("Type: "),n("code",null,"string")])],-1),U=n("li",null,[n("p",null,"Details:"),n("p",null,"Title for the page."),n("p",null,[a("If you don't specify "),n("code",null,"title"),a(" in frontmatter, content of the first level-one header (i.e. "),n("code",null,"# title"),a(") will be used as the title.")])],-1),W=n("p",null,"Also see:",-1);function X(Z,$){const i=l("NpmBadge"),p=l("ExternalLinkIcon"),t=l("RouterLink");return c(),d("div",null,[m,e(i,{package:"@vuepress/client"}),e(i,{package:"@vuepress/markdown"}),h,n("ul",null,[k,n("li",null,[f,g,n("p",null,[a("You should specify the date in the form of "),y,a(", or follow the "),n("a",v,[a("YAML Timestamp Type"),e(p)]),a(".")])]),n("li",null,[_,n("ul",null,[n("li",null,[e(t,{to:"/reference/node-api.html#date"},{default:s(()=>[a("Node API > Page Properties > date")]),_:1})])])])]),b,n("ul",null,[x,w,n("li",null,[P,n("ul",null,[n("li",null,[e(t,{to:"/reference/config.html#description"},{default:s(()=>[a("Config > description")]),_:1})])])])]),T,n("ul",null,[n("li",null,[a("Also see: "),n("ul",null,[n("li",null,[e(t,{to:"/reference/config.html#head"},{default:s(()=>[a("Config > head")]),_:1})])])])]),q,n("ul",null,[C,A,n("li",null,[M,n("ul",null,[n("li",null,[e(t,{to:"/reference/config.html#lang"},{default:s(()=>[a("Config > lang")]),_:1})]),n("li",null,[e(t,{to:"/reference/node-api.html#lang"},{default:s(()=>[a("Node API > Page Properties > lang")]),_:1})])])])]),D,n("ul",null,[L,N,n("li",null,[I,n("ul",null,[E,n("li",null,[e(t,{to:"/guide/page.html#routing"},{default:s(()=>[a("Guide > Page > Routing")]),_:1})]),n("li",null,[e(t,{to:"/reference/node-api.html#permalink"},{default:s(()=>[a("Node API > Page Properties > permalink")]),_:1})])])])]),R,n("ul",null,[n("li",null,[a("Also see: "),n("ul",null,[n("li",null,[e(t,{to:"/reference/config.html#permalinkpattern"},{default:s(()=>[a("Config > permalinkPattern")]),_:1})]),B,F,n("li",null,[e(t,{to:"/reference/node-api.html#permalink"},{default:s(()=>[a("Node API > Page Properties > permalink")]),_:1})])])])]),Y,n("ul",null,[V,S,n("li",null,[z,n("ul",null,[n("li",null,[e(t,{to:"/reference/node-api.html#routeMeta"},{default:s(()=>[a("Node API > Page Properties > routeMeta")]),_:1})])])])]),G,n("ul",null,[H,U,n("li",null,[W,n("ul",null,[n("li",null,[e(t,{to:"/reference/node-api.html#title"},{default:s(()=>[a("Node API > Page Properties > title")]),_:1})])])])])])}const J=u(r,[["render",X],["__file","frontmatter.html.vue"]]);export{J as default}; diff --git a/assets/frontmatter.html-96a3ef5a.js b/assets/frontmatter.html-96a3ef5a.js new file mode 100644 index 00000000..5ad49dd7 --- /dev/null +++ b/assets/frontmatter.html-96a3ef5a.js @@ -0,0 +1,60 @@ +import{_ as u,W as r,X as c,Y as a,$ as e,a0 as n,Z as t,a1 as l,D as i}from"./framework-46b0e263.js";const d={},h=e("h1",{id:"frontmatter",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),n(" Frontmatter")],-1),m=e("h2",{id:"all-pages",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#all-pages","aria-hidden":"true"},"#"),n(" All Pages")],-1),k=e("p",null,"Frontmatter in this section will take effect in all types of pages.",-1),f=e("h3",{id:"externallinkicon",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#externallinkicon","aria-hidden":"true"},"#"),n(" externalLinkIcon")],-1),g=e("li",null,[e("p",null,[n("Type: "),e("code",null,"boolean")])],-1),v=e("p",null,"Details:",-1),b=e("p",null,"Also see:",-1),_=e("h3",{id:"navbar",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#navbar","aria-hidden":"true"},"#"),n(" navbar")],-1),y=e("li",null,[e("p",null,[n("Type: "),e("code",null,"boolean")])],-1),x=e("li",null,[e("p",null,"Details:"),e("p",null,"Show navbar on this page or not."),e("p",null,"If you disable navbar in theme config, this frontmatter will not take effect.")],-1),T=e("p",null,"Also see:",-1),D=l(` # pageClass
Type:
string
Details:
Add extra class name to this page.
Example:
--- +pageClass: custom-page-class +--- +
Then you can customize styles of this page in
.vuepress/styles/index.scss
file:`,5),w=l(`.theme-container.custom-page-class { + /* page styles */ +} +
# Home Page
Frontmatter in this section will only take effect in home pages.
# home
Type:
boolean
Details:
Specify whether the page is homepage or a normal page.
If you don't set this frontmatter or set it to
false
, the page would be a normal page.Example:
--- +home: true +--- +
# heroImage
Type:
string
Details:
Specify the url of the hero image.
Example:
`,8),S=e("h3",{id:"heroimagedark",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#heroimagedark","aria-hidden":"true"},"#"),n(" heroImageDark")],-1),A=e("li",null,[e("p",null,[n("Type: "),e("code",null,"string")])],-1),C=e("li",null,[e("p",null,"Details:"),e("p",null,"Specify the url of hero image to be used in dark mode."),e("p",null,"You can make use of this option if you want to use different heroImage config in dark mode.")],-1),L=e("p",null,"Also see:",-1),I=e("li",null,[e("a",{href:"#heroimage"},"Default Theme > Frontmatter > heroImage")],-1),N=l('--- +# public file path +heroImage: /images/hero.png +# url +heroImage: https://vuejs.org/images/logo.png +--- +
# heroAlt
Type:
string
Details:
Specify the
alt
attribute of the hero image.This will fallback to the heroText.
# heroHeight
',3),E=e("li",null,[e("p",null,[n("Type: "),e("code",null,"number")])],-1),P=e("li",null,[e("p",null,[n("Default: "),e("code",null,"280")])],-1),V=e("p",null,"Details:",-1),F=e("p",null,[n("Specify the "),e("code",null,"height"),n(" attribute of the hero "),e("code",null,""),n(" tag.")],-1),j=e("p",null,"You may need to reduce this value if the height of your hero image is less than the default value.",-1),H={href:"https://web.dev/cls/",target:"_blank",rel:"noopener noreferrer"},B=e("h3",{id:"herotext",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#herotext","aria-hidden":"true"},"#"),n(" heroText")],-1),M=e("li",null,[e("p",null,[n("Type: "),e("code",null,"string | null")])],-1),q=e("p",null,"Details:",-1),G=e("p",null,"Specify the the hero text.",-1),R=e("p",null,[n("Set to "),e("code",null,"null"),n(" to disable hero text.")],-1),Y=e("h3",{id:"tagline",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#tagline","aria-hidden":"true"},"#"),n(" tagline")],-1),U=e("li",null,[e("p",null,[n("Type: "),e("code",null,"string | null")])],-1),z=e("p",null,"Details:",-1),O=e("p",null,"Specify the the tagline.",-1),W=e("p",null,[n("Set to "),e("code",null,"null"),n(" to disable tagline.")],-1),X=l(`
# actions
- Type:
Array<{ + text: string; + link: string; + type?: "primary" | "secondary"; +}>; +
Details:
Configuration of the action buttons.
Example:
--- +actions: + - text: Get Started + link: /guide/getting-started.html + type: primary + - text: Introduction + link: /guide/ + type: secondary +--- +
# features
- Type:
Array<{ + title: string; + details: string; +}>; +
Details:
Configuration of the features list.
Example:
--- +features: + - title: Simplicity First + details: Minimal setup with markdown-centered project structure helps you focus on writing. + - title: Vue-Powered + details: Enjoy the dev experience of Vue, use Vue components in markdown, and develop custom themes with Vue. + - title: Performant + details: VuePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded. +--- +
# footer
Type:
string
Details:
Specify the content of the footer.
# footerHtml
Type:
boolean
Details:
Allow HTML in footer or not.
If you set it to
true
, the footer will be treated as HTML code.# Normal Page
Frontmatter in this section will only take effect in normal pages.
# editLink
`,17),Z=e("li",null,[e("p",null,[n("Type: "),e("code",null,"boolean")])],-1),$=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Enable the "),e("em",null,"edit this page"),n(" link in this page or not.")])],-1),J=e("p",null,"Also see:",-1),K=e("h3",{id:"editlinkpattern",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#editlinkpattern","aria-hidden":"true"},"#"),n(" editLinkPattern")],-1),Q=e("li",null,[e("p",null,[n("Type: "),e("code",null,"string")])],-1),ee=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Specify the pattern of the "),e("em",null,"edit this page"),n(" link of this page.")])],-1),ne=e("p",null,"Also see:",-1),ae=e("h3",{id:"lastupdated",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#lastupdated","aria-hidden":"true"},"#"),n(" lastUpdated")],-1),se=e("li",null,[e("p",null,[n("Type: "),e("code",null,"boolean")])],-1),te=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Enable the "),e("em",null,"last updated timestamp"),n(" in this page or not.")])],-1),le=e("p",null,"Also see:",-1),ie=e("h3",{id:"contributors",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contributors","aria-hidden":"true"},"#"),n(" contributors")],-1),oe=e("li",null,[e("p",null,[n("Type: "),e("code",null,"boolean")])],-1),pe=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Enable the "),e("em",null,"contributors list"),n(" in this page or not.")])],-1),ue=e("p",null,"Also see:",-1),re=e("h3",{id:"sidebar",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#sidebar","aria-hidden":"true"},"#"),n(" sidebar")],-1),ce=e("li",null,[e("p",null,[n("Type: "),e("code",null,"false | 'auto' | SidebarConfigArray | SidebarConfigObject")])],-1),de=e("li",null,[e("p",null,"Details:"),e("p",null,"Configure the sidebar of this page.")],-1),he=e("p",null,"Also see:",-1),me=e("h3",{id:"sidebardepth",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#sidebardepth","aria-hidden":"true"},"#"),n(" sidebarDepth")],-1),ke=e("li",null,[e("p",null,[n("Type: "),e("code",null,"number")])],-1),fe=e("li",null,[e("p",null,"Details:"),e("p",null,"Configure the sidebar depth of this page.")],-1),ge=e("p",null,"Also see:",-1),ve=l(`# prev
Type:
NavLink | string
Details:
Specify the link of the previous page.
If you don't set this frontmatter, the link will be inferred from the sidebar config.
To configure the prev link manually, you can set this frontmatter to a
NavLink
object or a string:
- A
NavLink
object should have atext
field and alink
field.- A string should be the path to the target page file. It will be converted to a
NavLink
object, whosetext
is the page title, andlink
is the page route path.Example:
--- +# NavLink +prev: + text: Get Started + link: /guide/getting-started.html + +# NavLink - external url +prev: + text: GitHub + link: https://github.com + +# string - page file path +prev: /guide/getting-started.md + +# string - page file relative path +prev: ../../guide/getting-started.md +--- +
# next
`,5);function be(_e,ye){const o=i("NpmBadge"),s=i("RouterLink"),p=i("ExternalLinkIcon");return r(),c("div",null,[h,a(o,{package:"@vuepress/theme-default"}),m,k,f,e("ul",null,[g,e("li",null,[v,e("p",null,[n("Provided by "),a(s,{to:"/reference/plugin/external-link-icon.html#externallinkicon"},{default:t(()=>[n("@vuepress/plugin-external-link-icon")]),_:1}),n(".")])]),e("li",null,[b,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#themeplugins-externallinkicon"},{default:t(()=>[n("Default Theme > Config Reference > themePlugins.externalLinkIcon")]),_:1})])])])]),_,e("ul",null,[y,x,e("li",null,[T,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#navbar"},{default:t(()=>[n("Default Theme > Config > navbar")]),_:1})])])])]),D,e("ul",null,[e("li",null,[n("Also see: "),e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/styles.html#style-file"},{default:t(()=>[n("Default Theme > Styles > Style File")]),_:1})])])])]),w,e("ul",null,[e("li",null,[n("Also see: "),e("ul",null,[e("li",null,[a(s,{to:"/guide/assets.html#public-files"},{default:t(()=>[n("Guide > Assets > Public Files")]),_:1})])])])]),S,e("ul",null,[A,C,e("li",null,[L,e("ul",null,[I,e("li",null,[a(s,{to:"/reference/default-theme/config.html#colormode"},{default:t(()=>[n("Default Theme > Config > colorMode")]),_:1})])])])]),N,e("ul",null,[E,P,e("li",null,[V,F,j,e("p",null,[n("Notice that the height is also constrained by CSS. This attribute is to reduce "),e("a",H,[n("Cumulative Layout Shift (CLS)"),a(p)]),n(" that caused by the loading of the hero image.")])])]),B,e("ul",null,[M,e("li",null,[q,G,e("p",null,[n("This will fallback to the site "),a(s,{to:"/reference/config.html#title"},{default:t(()=>[n("title")]),_:1}),n(".")]),R])]),Y,e("ul",null,[U,e("li",null,[z,O,e("p",null,[n("This will fallback to the site "),a(s,{to:"/reference/config.html#description"},{default:t(()=>[n("description")]),_:1}),n(".")]),W])]),X,e("ul",null,[Z,$,e("li",null,[J,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#editlink"},{default:t(()=>[n("Default Theme > Config > editLink")]),_:1})])])])]),K,e("ul",null,[Q,ee,e("li",null,[ne,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#editlinkpattern"},{default:t(()=>[n("Default Theme > Config > editLinkPattern")]),_:1})])])])]),ae,e("ul",null,[se,te,e("li",null,[le,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#lastupdated"},{default:t(()=>[n("Default Theme > Config > lastUpdated")]),_:1})])])])]),ie,e("ul",null,[oe,pe,e("li",null,[ue,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#contributors"},{default:t(()=>[n("Default Theme > Config > contributors")]),_:1})])])])]),re,e("ul",null,[ce,de,e("li",null,[he,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#sidebar"},{default:t(()=>[n("Default Theme > Config > sidebar")]),_:1})])])])]),me,e("ul",null,[ke,fe,e("li",null,[ge,e("ul",null,[e("li",null,[a(s,{to:"/reference/default-theme/config.html#sidebardepth"},{default:t(()=>[n("Default Theme > Config > sidebarDepth")]),_:1})])])])]),ve])}const Te=u(d,[["render",be],["__file","frontmatter.html.vue"]]);export{Te as default}; diff --git a/assets/frontmatter.html-bdbde184.js b/assets/frontmatter.html-bdbde184.js new file mode 100644 index 00000000..820a449b --- /dev/null +++ b/assets/frontmatter.html-bdbde184.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-d147334a","path":"/zh/reference/frontmatter.html","title":"Frontmatter","lang":"zh-CN","frontmatter":{"icon":"fa-solid:bars","description":"date 类型: string; 详情:; 页面的创建日期。 应按照 yyyy-MM-dd 的格式来指定日期,或者遵循 YAML Timestamp Type (https://yaml.org/type/timestamp.html) 。 参考:; Node API > Page 属性 > date (./node-api.md#date); des...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/frontmatter.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/frontmatter.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Frontmatter"}],["meta",{"property":"og:description","content":"date 类型: string; 详情:; 页面的创建日期。 应按照 yyyy-MM-dd 的格式来指定日期,或者遵循 YAML Timestamp Type (https://yaml.org/type/timestamp.html) 。 参考:; Node API > Page 属性 > date (./node-api.md#date); des..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Frontmatter\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"date","slug":"date","link":"#date","children":[]},{"level":2,"title":"description","slug":"description","link":"#description","children":[]},{"level":2,"title":"head","slug":"head","link":"#head","children":[]},{"level":2,"title":"lang","slug":"lang","link":"#lang","children":[]},{"level":2,"title":"layout","slug":"layout","link":"#layout","children":[]},{"level":2,"title":"permalink","slug":"permalink","link":"#permalink","children":[]},{"level":2,"title":"permalinkPattern","slug":"permalinkpattern","link":"#permalinkpattern","children":[]},{"level":2,"title":"routeMeta","slug":"routemeta","link":"#routemeta","children":[]},{"level":2,"title":"title","slug":"title","link":"#title","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.56,"words":767},"filePathRelative":"zh/reference/frontmatter.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/getting-started.html-218659cd.js b/assets/getting-started.html-218659cd.js new file mode 100644 index 00000000..f0e0c393 --- /dev/null +++ b/assets/getting-started.html-218659cd.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-fb0f0066","path":"/guide/getting-started.html","title":"Getting Started","lang":"en-US","frontmatter":{"icon":"fa6-solid:lightbulb","description":"VuePress v2 is currently in beta stage. It's ready to be used for building your site, but the config and API are not stable enough, which is likely to have breaking changes betw...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/getting-started.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/getting-started.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Getting Started"}],["meta",{"property":"og:description","content":"VuePress v2 is currently in beta stage. It's ready to be used for building your site, but the config and API are not stable enough, which is likely to have breaking changes betw..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Getting Started\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Prerequisites","slug":"prerequisites","link":"#prerequisites","children":[]},{"level":2,"title":"Manual Installation","slug":"manual-installation","link":"#manual-installation","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.32,"words":397},"filePathRelative":"guide/getting-started.md","localizedDate":"February 22, 2023","autoDesc":true}`);export{e as data}; diff --git a/assets/getting-started.html-7cb9cdb6.js b/assets/getting-started.html-7cb9cdb6.js new file mode 100644 index 00000000..3166e81f --- /dev/null +++ b/assets/getting-started.html-7cb9cdb6.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-37781588","path":"/zh/guide/getting-started.html","title":"快速上手","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:lightbulb","description":"VuePress v2 目前仍处于 beta 阶段。你已经可以用它来构建你的站点,但是它的配置和 API 还不够稳定,很可能会在 Minor 版本中发生 Breaking Changes 。因此,在每次更新 beta 版本之后,请一定要仔细阅读 更新日志 (https://github.com/vuepress/vuepress-next/blob/m...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/getting-started.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/getting-started.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"快速上手"}],["meta",{"property":"og:description","content":"VuePress v2 目前仍处于 beta 阶段。你已经可以用它来构建你的站点,但是它的配置和 API 还不够稳定,很可能会在 Minor 版本中发生 Breaking Changes 。因此,在每次更新 beta 版本之后,请一定要仔细阅读 更新日志 (https://github.com/vuepress/vuepress-next/blob/m..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"快速上手\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"依赖环境","slug":"依赖环境","link":"#依赖环境","children":[]},{"level":2,"title":"手动安装","slug":"手动安装","link":"#手动安装","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.75,"words":524},"filePathRelative":"zh/guide/getting-started.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/getting-started.html-82d2dd43.js b/assets/getting-started.html-82d2dd43.js new file mode 100644 index 00000000..8fb6de56 --- /dev/null +++ b/assets/getting-started.html-82d2dd43.js @@ -0,0 +1,26 @@ +import{_ as p,W as h,X as v,$ as e,a0 as n,Y as s,Z as a,a1 as d,D as c}from"./framework-46b0e263.js";const g={},b=e("h1",{id:"getting-started",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#getting-started","aria-hidden":"true"},"#"),n(" Getting Started")],-1),m={class:"hint-container warning"},_=e("p",{class:"hint-container-title"},"Note",-1),k=e("code",null,"beta",-1),f={href:"https://github.com/vuepress/vuepress-next/blob/main/CHANGELOG.md",target:"_blank",rel:"noopener noreferrer"},y=e("h2",{id:"prerequisites",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#prerequisites","aria-hidden":"true"},"#"),n(" Prerequisites")],-1),x={href:"https://nodejs.org/",target:"_blank",rel:"noopener noreferrer"},P={href:"https://classic.yarnpkg.com/en/",target:"_blank",rel:"noopener noreferrer"},A={class:"hint-container tip"},N=e("p",{class:"hint-container-title"},"Tips",-1),q={href:"https://pnpm.io/",target:"_blank",rel:"noopener noreferrer"},S=e("code",null,"vue",-1),w=e("code",null,"@vuepress/client",-1),V=e("code",null,"pnpm add -D vue @vuepress/client@next",-1),j={href:"https://yarnpkg.com/",target:"_blank",rel:"noopener noreferrer"},I=e("code",null,"nodeLinker: 'node-modules'",-1),M={href:"https://yarnpkg.com/configuration/yarnrc#nodeLinker",target:"_blank",rel:"noopener noreferrer"},C=e("code",null,".yarnrc.yml",-1),L=d(`
Type:
NavLink | string
Details:
Specify the link of the next page.
If you don't set this frontmatter, the link will be inferred from the sidebar config.
The type is the same as prev frontmatter.
# Manual Installation
This section will help you build a basic VuePress documentation site from ground up. If you already have an existing project and would like to keep documentation inside the project, start from Step 3.
- Step 1: Create and change into a new directory
mkdir vuepress-starter +cd vuepress-starter +
`,5),D=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"git"),n(` init +`),e("span",{class:"token function"},"pnpm"),n(` init +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),E=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"git"),n(` init +`),e("span",{class:"token function"},"yarn"),n(` init +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),R=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"git"),n(` init +`),e("span",{class:"token function"},"npm"),n(` init +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),T=e("ul",null,[e("li",null,[e("strong",null,"Step 3"),n(": Install VuePress locally")])],-1),Y=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"pnpm"),n(),e("span",{class:"token function"},"add"),n(),e("span",{class:"token parameter variable"},"-D"),n(` vuepress@next @vuepress/client@next vue +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),B=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"yarn"),n(),e("span",{class:"token function"},"add"),n(),e("span",{class:"token parameter variable"},"-D"),n(` vuepress@next +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),W=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"npm"),n(),e("span",{class:"token function"},"install"),n(),e("span",{class:"token parameter variable"},"-D"),n(` vuepress@next +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),G=e("strong",null,"Step 4",-1),H={href:"https://classic.yarnpkg.com/en/docs/package-json#toc-scripts",target:"_blank",rel:"noopener noreferrer"},O=e("code",null,"package.json",-1),z=d(`
- Step 2: Initialize your project
{ + "scripts": { + "docs:dev": "vuepress dev docs", + "docs:build": "vuepress build docs" + } +} +
- Step 5: Add the default temp and cache directory to
.gitignore
fileecho 'node_modules' >> .gitignore +echo '.temp' >> .gitignore +echo '.cache' >> .gitignore +
- Step 6: Create your first document
mkdir docs +echo '# Hello VuePress' > docs/README.md +
`,6),X=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"pnpm"),n(` docs:dev +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),Z=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"yarn"),n(` docs:dev +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),$=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"npm"),n(` run docs:dev +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),F={href:"http://localhost:8080",target:"_blank",rel:"noopener noreferrer"};function J(K,Q){const t=c("ExternalLinkIcon"),r=c("CodeTabs"),u=c("RouterLink");return h(),v("div",null,[b,e("div",m,[_,e("p",null,[n("VuePress v2 is currently in "),k,n(" stage. It's ready to be used for building your site, but the config and API are not stable enough, which is likely to have breaking changes between minor releases. So make sure to read the "),e("a",f,[n("changelog"),s(t)]),n(" carefully each time you upgrade a beta version.")])]),y,e("ul",null,[e("li",null,[e("a",x,[n("Node.js v14.18.0+"),s(t)])]),e("li",null,[e("a",P,[n("Yarn v1 classic"),s(t)]),n(" (Optional)")])]),e("div",A,[N,e("ul",null,[e("li",null,[n("With "),e("a",q,[n("pnpm"),s(t)]),n(", you may need to install "),S,n(" and "),w,n(" as peer-dependencies, i.e. "),V,n(".")]),e("li",null,[n("With "),e("a",j,[n("yarn 2"),s(t)]),n(", you need to set "),I,n(" in your "),e("a",M,[C,s(t)]),n(" file.")])])]),L,s(r,{id:"58",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:a(({title:i,value:l,isActive:o})=>[D]),tab1:a(({title:i,value:l,isActive:o})=>[E]),tab2:a(({title:i,value:l,isActive:o})=>[R]),_:1}),T,s(r,{id:"76",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:a(({title:i,value:l,isActive:o})=>[Y]),tab1:a(({title:i,value:l,isActive:o})=>[B]),tab2:a(({title:i,value:l,isActive:o})=>[W]),_:1}),e("ul",null,[e("li",null,[G,n(": Add some "),e("a",H,[n("scripts"),s(t)]),n(" to "),O])]),z,s(r,{id:"118",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:a(({title:i,value:l,isActive:o})=>[X]),tab1:a(({title:i,value:l,isActive:o})=>[Z]),tab2:a(({title:i,value:l,isActive:o})=>[$]),_:1}),e("p",null,[n("VuePress will start a hot-reloading development server at "),e("a",F,[n("http://localhost:8080"),s(t)]),n(". When you modify your markdown files, the content in the browser will be auto updated.")]),e("p",null,[n("By now, you should have a basic but functional VuePress documentation site. Next, learn about the basics of "),s(u,{to:"/guide/configuration.html"},{default:a(()=>[n("configuration")]),_:1}),n(" in VuePress.")])])}const ee=p(g,[["render",J],["__file","getting-started.html.vue"]]);export{ee as default}; diff --git a/assets/getting-started.html-b0306b71.js b/assets/getting-started.html-b0306b71.js new file mode 100644 index 00000000..8187e8c6 --- /dev/null +++ b/assets/getting-started.html-b0306b71.js @@ -0,0 +1,26 @@ +import{_ as p,W as h,X as v,$ as e,a0 as s,Y as n,Z as a,a1 as d,D as c}from"./framework-46b0e263.js";const b={},g=e("h1",{id:"快速上手",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#快速上手","aria-hidden":"true"},"#"),s(" 快速上手")],-1),m={class:"hint-container warning"},_=e("p",{class:"hint-container-title"},"注意",-1),k=e("code",null,"beta",-1),f={href:"https://github.com/vuepress/vuepress-next/blob/main/CHANGELOG.md",target:"_blank",rel:"noopener noreferrer"},x=e("h2",{id:"依赖环境",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#依赖环境","aria-hidden":"true"},"#"),s(" 依赖环境")],-1),P={href:"https://nodejs.org/",target:"_blank",rel:"noopener noreferrer"},A={href:"https://classic.yarnpkg.com/zh-Hans/",target:"_blank",rel:"noopener noreferrer"},N={class:"hint-container tip"},y=e("p",{class:"hint-container-title"},"提示",-1),V={href:"https://pnpm.io/zh/",target:"_blank",rel:"noopener noreferrer"},q=e("code",null,"vue",-1),M=e("code",null,"@vuepress/client",-1),j=e("code",null,"pnpm add -D vue @vuepress/client@next",-1),L={href:"https://yarnpkg.com/",target:"_blank",rel:"noopener noreferrer"},C={href:"https://yarnpkg.com/configuration/yarnrc#nodeLinker",target:"_blank",rel:"noopener noreferrer"},D=e("code",null,".yarnrc.yml",-1),E=e("code",null,"nodeLinker: 'node-modules'",-1),R=d(`
- Step 7: Serve the documentation site in the local server
# 手动安装
这一章节会帮助你从头搭建一个简单的 VuePress 文档网站。如果你想在一个现有项目中使用 VuePress 管理文档,从步骤 3 开始。
- 步骤 1: 创建并进入一个新目录
mkdir vuepress-starter +cd vuepress-starter +
`,5),Y=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"git"),s(` init +`),e("span",{class:"token function"},"pnpm"),s(` init +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),z=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"git"),s(` init +`),e("span",{class:"token function"},"yarn"),s(` init +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),B=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"git"),s(` init +`),e("span",{class:"token function"},"npm"),s(` init +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),H=e("ul",null,[e("li",null,[e("strong",null,"步骤 3"),s(": 将 VuePress 安装为本地依赖")])],-1),w=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"pnpm"),s(),e("span",{class:"token function"},"add"),s(),e("span",{class:"token parameter variable"},"-D"),s(` vuepress@next @vuepress/client@next vue +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),I=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"yarn"),s(),e("span",{class:"token function"},"add"),s(),e("span",{class:"token parameter variable"},"-D"),s(` vuepress@next +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),T=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"npm"),s(),e("span",{class:"token function"},"install"),s(),e("span",{class:"token parameter variable"},"-D"),s(` vuepress@next +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),G=e("strong",null,"步骤 4",-1),S=e("code",null,"package.json",-1),O={href:"https://classic.yarnpkg.com/zh-Hans/docs/package-json#toc-scripts",target:"_blank",rel:"noopener noreferrer"},W=d(`
- 步骤 2: 初始化项目
{ + "scripts": { + "docs:dev": "vuepress dev docs", + "docs:build": "vuepress build docs" + } +} +
- 步骤 5: 将默认的临时目录和缓存目录添加到
.gitignore
文件中echo 'node_modules' >> .gitignore +echo '.temp' >> .gitignore +echo '.cache' >> .gitignore +
- 步骤 6: 创建你的第一篇文档
mkdir docs +echo '# Hello VuePress' > docs/README.md +
`,6),X=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"pnpm"),s(` docs:dev +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),Z=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"yarn"),s(` docs:dev +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),$=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"npm"),s(` run docs:dev +`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),F={href:"http://localhost:8080",target:"_blank",rel:"noopener noreferrer"};function J(K,Q){const t=c("ExternalLinkIcon"),r=c("CodeTabs"),u=c("RouterLink");return h(),v("div",null,[g,e("div",m,[_,e("p",null,[s("VuePress v2 目前仍处于 "),k,s(" 阶段。你已经可以用它来构建你的站点,但是它的配置和 API 还不够稳定,很可能会在 Minor 版本中发生 Breaking Changes 。因此,在每次更新 beta 版本之后,请一定要仔细阅读 "),e("a",f,[s("更新日志"),n(t)]),s("。")])]),x,e("ul",null,[e("li",null,[e("a",P,[s("Node.js v14.18.0+"),n(t)])]),e("li",null,[e("a",A,[s("Yarn v1 classic"),n(t)]),s(" (可选)")])]),e("div",N,[y,e("ul",null,[e("li",null,[s("使用 "),e("a",V,[s("pnpm"),n(t)]),s(" 时,你可能需要安装 "),q,s(" 和 "),M,s(" 作为 peer-dependencies ,即 "),j,s(" 。")]),e("li",null,[s("使用 "),e("a",L,[s("yarn 2"),n(t)]),s(" 时,你需要在 "),e("a",C,[D,n(t)]),s(" 文件中设置 "),E,s(" 。")])])]),R,n(r,{id:"58",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:a(({title:l,value:i,isActive:o})=>[Y]),tab1:a(({title:l,value:i,isActive:o})=>[z]),tab2:a(({title:l,value:i,isActive:o})=>[B]),_:1}),H,n(r,{id:"76",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:a(({title:l,value:i,isActive:o})=>[w]),tab1:a(({title:l,value:i,isActive:o})=>[I]),tab2:a(({title:l,value:i,isActive:o})=>[T]),_:1}),e("ul",null,[e("li",null,[G,s(": 在 "),S,s(" 中添加一些 "),e("a",O,[s("scripts"),n(t)])])]),W,n(r,{id:"118",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:a(({title:l,value:i,isActive:o})=>[X]),tab1:a(({title:l,value:i,isActive:o})=>[Z]),tab2:a(({title:l,value:i,isActive:o})=>[$]),_:1}),e("p",null,[s("VuePress 会在 "),e("a",F,[s("http://localhost:8080"),n(t)]),s(" 启动一个热重载的开发服务器。当你修改你的 Markdown 文件时,浏览器中的内容也会自动更新。")]),e("p",null,[s("现在,你应该已经有了一个简单可用的 VuePress 文档网站。接下来,了解一下 VuePress "),n(u,{to:"/zh/guide/configuration.html"},{default:a(()=>[s("配置")]),_:1}),s(" 相关的内容。")])])}const ee=p(b,[["render",J],["__file","getting-started.html.vue"]]);export{ee as default}; diff --git a/assets/git.html-33f0c5bb.js b/assets/git.html-33f0c5bb.js new file mode 100644 index 00000000..67f3e5b3 --- /dev/null +++ b/assets/git.html-33f0c5bb.js @@ -0,0 +1,30 @@ +import{_ as c,W as r,X as d,Y as e,$ as a,a0 as n,Z as o,a1 as p,D as s}from"./framework-46b0e263.js";const u={},h=a("h1",{id:"git",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#git","aria-hidden":"true"},"#"),n(" git")],-1),m=a("p",null,"This plugin will collect git information of your pages, including the created and updated time, the contributors, etc.",-1),g=p(`
- 步骤 7: 在本地启动服务器来开发你的文档网站
This plugin is mainly used to develop themes. You won't need to use it directly in most cases.
# Usage
npm i -D @vuepress/plugin-git@next +
import { gitPlugin } from "@vuepress/plugin-git"; + +export default { + plugins: [ + gitPlugin({ + // options + }), + ], +}; +
# Git Repository
`,5),k={href:"https://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository",target:"_blank",rel:"noopener noreferrer"},v={href:"https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt",target:"_blank",rel:"noopener noreferrer"},b=p(`Note
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
Default:
true
Details:
Whether to collect page contributors or not.
# Frontmatter
# gitInclude
Type:
string[]
Details:
An array of relative paths to be included when calculating page data.
Example:
--- +gitInclude: + - relative/path/to/file1 + - relative/path/to/file2 +--- +
# 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:
import { usePageData } from "@vuepress/client"; +import type { GitPluginPageData } from "@vuepress/plugin-git"; + +export default { + setup() { + const page = usePageData<GitPluginPageData>(); + 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.
# 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.
# git.contributors
- Type:
GitContributor[]
interface GitContributor { + name: string; + email: string; + commits: number; +} +
`,24);function f(y,x){const l=s("NpmBadge"),t=s("RouterLink"),i=s("ExternalLinkIcon");return r(),d("div",null,[h,e(l,{package:"@vuepress/plugin-git"}),m,a("p",null,[n("The "),e(t,{to:"/reference/default-theme/config.html#lastupdated"},{default:o(()=>[n("lastUpdated")]),_:1}),n(" and "),e(t,{to:"/reference/default-theme/config.html#contributors"},{default:o(()=>[n("contributors")]),_:1}),n(" of default theme is powered by this plugin.")]),g,a("p",null,[n("This plugin requires your project to be inside a "),a("a",k,[n("Git Repository"),e(i)]),n(", so that it can collect information from the commit history.")]),a("p",null,[n("You should ensure all commits are available when building your site. For example, CI workflows usually clone your repository with "),a("a",v,[n("--depth 1"),e(i)]),n(" to avoid fetching all commits, so you should disable the behavior to make this plugin work properly in CI.")]),b])}const _=c(u,[["render",f],["__file","git.html.vue"]]);export{_ as default}; diff --git a/assets/git.html-3f427683.js b/assets/git.html-3f427683.js new file mode 100644 index 00000000..705c52ab --- /dev/null +++ b/assets/git.html-3f427683.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0f9e4c06","path":"/reference/plugin/git.html","title":"git","lang":"en-US","frontmatter":{"description":"This plugin will collect git information of your pages, including the created and updated time, the contributors, etc. The lastUpdated (../default-theme/config.md#lastupdated) a...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/git.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/git.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"git"}],["meta",{"property":"og:description","content":"This plugin will collect git information of your pages, including the created and updated time, the contributors, etc. The lastUpdated (../default-theme/config.md#lastupdated) a..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"git\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Git Repository","slug":"git-repository","link":"#git-repository","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"createdTime","slug":"createdtime","link":"#createdtime","children":[]},{"level":3,"title":"updatedTime","slug":"updatedtime","link":"#updatedtime","children":[]},{"level":3,"title":"contributors","slug":"contributors","link":"#contributors","children":[]}]},{"level":2,"title":"Frontmatter","slug":"frontmatter","link":"#frontmatter","children":[{"level":3,"title":"gitInclude","slug":"gitinclude","link":"#gitinclude","children":[]}]},{"level":2,"title":"Page Data","slug":"page-data","link":"#page-data","children":[{"level":3,"title":"git.createdTime","slug":"git-createdtime","link":"#git-createdtime","children":[]},{"level":3,"title":"git.updatedTime","slug":"git-updatedtime","link":"#git-updatedtime","children":[]},{"level":3,"title":"git.contributors","slug":"git-contributors","link":"#git-contributors","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.45,"words":436},"filePathRelative":"reference/plugin/git.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/git.html-e47476ae.js b/assets/git.html-e47476ae.js new file mode 100644 index 00000000..fd41727f --- /dev/null +++ b/assets/git.html-e47476ae.js @@ -0,0 +1,30 @@ +import{_ as l,W as r,X as d,Y as s,$ as a,a0 as n,Z as p,a1 as o,D as e}from"./framework-46b0e263.js";const u={},h=a("h1",{id:"git",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#git","aria-hidden":"true"},"#"),n(" git")],-1),k=a("p",null,"该插件会收集你的页面的 Git 信息,包括创建和更新时间、贡献者等。",-1),m=o(`
Details:
The contributors information of the page.
This attribute would also include contributors to the files listed in gitInclude.
该插件主要用于开发主题,大部分情况下你不需要直接使用它。
# 使用方法
npm i -D @vuepress/plugin-git@next +
import { gitPlugin } from "@vuepress/plugin-git"; + +export default { + plugins: [ + gitPlugin({ + // 配置项 + }), + ], +}; +
# Git 仓库
`,5),g={href:"https://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository",target:"_blank",rel:"noopener noreferrer"},v={href:"https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt",target:"_blank",rel:"noopener noreferrer"},b=o(`注意
该插件会显著降低准备数据的速度,特别是在你的页面数量很多的时候。你可以考虑在
dev
模式下禁用该插件来获取更好的开发体验。# 配置项
# createdTime
类型:
boolean
默认值:
true
详情:
是否收集页面的创建时间。
# updatedTime
类型:
boolean
默认值:
true
详情:
是否收集页面的更新时间。
# contributors
类型:
boolean
默认值:
true
详情:
是否收集页面的贡献者。
# Frontmatter
# gitInclude
类型:
string[]
详情:
文件相对路径组成的数组,该数组中的文件会在计算页面数据时被包含在内。
示例:
--- +gitInclude: + - relative/path/to/file1 + - relative/path/to/file2 +--- +
# 页面数据
该插件会向页面数据中添加一个
git
字段。在使用该插件后,可以在页面数据中获取该插件收集到的 Git 信息:
import { usePageData } from "@vuepress/client"; +import type { GitPluginPageData } from "@vuepress/plugin-git"; + +export default { + setup() { + const page = usePageData<GitPluginPageData>(); + console.log(page.value.git); + }, +}; +
# git.createdTime
类型:
number
详情:
页面第一次提交的 Unix 毫秒时间戳。
该属性将取当前页面及 gitInclude 中所列文件的第一次提交的时间戳的最小值。
# git.updatedTime
类型:
number
详情:
页面最后一次提交的 Unix 毫秒时间戳。
该属性将取当前页面及 gitInclude 中所列文件的最后一次提交的时间戳的最大值。
# git.contributors
- 类型:
GitContributor[]
interface GitContributor { + name: string; + email: string; + commits: number; +} +
`,24);function f(_,x){const c=e("NpmBadge"),t=e("RouterLink"),i=e("ExternalLinkIcon");return r(),d("div",null,[h,s(c,{package:"@vuepress/plugin-git"}),k,a("p",null,[n("默认主题的 "),s(t,{to:"/zh/reference/default-theme/config.html#lastupdated"},{default:p(()=>[n("lastUpdated")]),_:1}),n(" 和 "),s(t,{to:"/zh/reference/default-theme/config.html#contributors"},{default:p(()=>[n("contributors")]),_:1}),n(" 就是由该插件支持的。")]),m,a("p",null,[n("该插件要求你的项目在 "),a("a",g,[n("Git 仓库"),s(i)]),n(" 下,这样它才能从提交历史记录中收集信息。")]),a("p",null,[n("在构建站点时,你应该确保所有的提交记录是可以获取到的。举例来说, CI 工作流通常会在克隆你的仓库时添加 "),a("a",v,[n("--depth 1"),s(i)]),n(" 参数来避免拉取全部的提交记录,因此你需要禁用这个功能,以便该插件在 CI 可以中正常使用。")]),b])}const w=l(u,[["render",f],["__file","git.html.vue"]]);export{w as default}; diff --git a/assets/git.html-fe8105d2.js b/assets/git.html-fe8105d2.js new file mode 100644 index 00000000..6f4d7a5d --- /dev/null +++ b/assets/git.html-fe8105d2.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-d2322692","path":"/zh/reference/plugin/git.html","title":"git","lang":"zh-CN","frontmatter":{"description":"该插件会收集你的页面的 Git 信息,包括创建和更新时间、贡献者等。 默认主题的 lastUpdated (../default-theme/config.md#lastupdated) 和 contributors (../default-theme/config.md#contributors) 就是由该插件支持的。 该插件主要用于开发主题,大部分...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/git.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/git.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"git"}],["meta",{"property":"og:description","content":"该插件会收集你的页面的 Git 信息,包括创建和更新时间、贡献者等。 默认主题的 lastUpdated (../default-theme/config.md#lastupdated) 和 contributors (../default-theme/config.md#contributors) 就是由该插件支持的。 该插件主要用于开发主题,大部分..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"git\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"Git 仓库","slug":"git-仓库","link":"#git-仓库","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"createdTime","slug":"createdtime","link":"#createdtime","children":[]},{"level":3,"title":"updatedTime","slug":"updatedtime","link":"#updatedtime","children":[]},{"level":3,"title":"contributors","slug":"contributors","link":"#contributors","children":[]}]},{"level":2,"title":"Frontmatter","slug":"frontmatter","link":"#frontmatter","children":[{"level":3,"title":"gitInclude","slug":"gitinclude","link":"#gitinclude","children":[]}]},{"level":2,"title":"页面数据","slug":"页面数据","link":"#页面数据","children":[{"level":3,"title":"git.createdTime","slug":"git-createdtime","link":"#git-createdtime","children":[]},{"level":3,"title":"git.updatedTime","slug":"git-updatedtime","link":"#git-updatedtime","children":[]},{"level":3,"title":"git.contributors","slug":"git-contributors","link":"#git-contributors","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.14,"words":643},"filePathRelative":"zh/reference/plugin/git.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/google-analytics.html-6e744845.js b/assets/google-analytics.html-6e744845.js new file mode 100644 index 00000000..af64d201 --- /dev/null +++ b/assets/google-analytics.html-6e744845.js @@ -0,0 +1,26 @@ +import{_ as i,W as c,X as p,Y as a,$ as n,a0 as s,a1 as t,D as o}from"./framework-46b0e263.js";const r={},u=n("h1",{id:"google-analytics",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#google-analytics","aria-hidden":"true"},"#"),s(" google-analytics")],-1),d={href:"https://analytics.google.com/",target:"_blank",rel:"noopener noreferrer"},g={href:"https://developers.google.com/analytics/devguides/collection/gtagjs",target:"_blank",rel:"noopener noreferrer"},h={href:"https://support.google.com/analytics/answer/10089681",target:"_blank",rel:"noopener noreferrer"},k=t(`
详情:
页面的贡献者信息。
该属性将会包含 gitInclude 所列文件的贡献者。
# 使用方法
npm i -D @vuepress/plugin-google-analytics@next +
import { googleAnalyticsPlugin } from "@vuepress/plugin-google-analytics"; + +export default { + plugins: [ + googleAnalyticsPlugin({ + // 配置项 + }), + ], +}; +
# 上报事件
`,4),v={href:"https://support.google.com/analytics/answer/9234069",target:"_blank",rel:"noopener noreferrer"},_=n("code",null,"page_view",-1),m=n("code",null,"first_visit",-1),b=n("p",null,[s("因此,如果你只是想收集站点的一些基础数据,你只需要正确设置 "),n("a",{href:"#id"},"Measurement ID"),s(" ,不需要再额外做其他事情。")],-1),y=n("code",null,"gtag()",-1),f=n("code",null,"window",-1),X={href:"https://developers.google.com/analytics/devguides/collection/ga4/events",target:"_blank",rel:"noopener noreferrer"},x=n("h2",{id:"配置项",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#配置项","aria-hidden":"true"},"#"),s(" 配置项")],-1),w=n("h3",{id:"id",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#id","aria-hidden":"true"},"#"),s(" id")],-1),A=n("li",null,[n("p",null,[s("类型: "),n("code",null,"string")])],-1),D=n("p",null,"详情:",-1),G=n("p",null,[s("Google Analytics 4 的 Measurement ID ,应以 "),n("code",null,"'G-'"),s(" 开头。")],-1),I={href:"https://support.google.com/analytics/answer/9539598",target:"_blank",rel:"noopener noreferrer"},V=n("li",null,[n("p",null,"示例:")],-1),q=t(`export default { + plugins: [ + googleAnalyticsPlugin({ + id: "G-XXXXXXXXXX", + }), + ], +}; +
# debug
`,2),N=n("li",null,[n("p",null,[s("类型: "),n("code",null,"boolean")])],-1),B=n("p",null,"详情:",-1),P=n("code",null,"true",-1),M={href:"https://support.google.com/analytics/answer/7201382",target:"_blank",rel:"noopener noreferrer"},E=n("li",null,[n("p",null,"示例:")],-1),j=t(``,1);function L(T,U){const l=o("NpmBadge"),e=o("ExternalLinkIcon");return c(),p("div",null,[u,a(l,{package:"@vuepress/plugin-google-analytics"}),n("p",null,[s("将 "),n("a",d,[s("Google Analytics"),a(e)]),s(" 集成到 VuePress 中。")]),n("p",null,[s("该插件会通过引入 "),n("a",g,[s("gtag.js"),a(e)]),s(" 来启用 "),n("a",h,[s("Google Analytics 4"),a(e)]),s(" 。")]),k,n("p",null,[s("Google Analytics 会 "),n("a",v,[s("自动收集部分事件"),a(e)]),s(" ,比如 "),_,s(", "),m,s(" 等。")]),b,n("p",null,[s("在引入该插件之后,一个全局的 "),y,s(" 函数会被挂载到 "),f,s(" 对象上,你可以使用它进行 "),n("a",X,[s("自定义事件的上报"),a(e)]),s(" 。")]),x,w,n("ul",null,[A,n("li",null,[D,G,n("p",null,[s("你可以通过 "),n("a",I,[s("这里"),a(e)]),s(' 的指引来找到你的 Measurement ID 。注意区分 Google Analytics 4 的 Measurement ID (即 "G-" 开头的 ID) 和 Universal Analytics 的 Tracking ID (即 "UA-" 开头的 ID)。')])]),V]),q,n("ul",null,[N,n("li",null,[B,n("p",null,[s("设置为 "),P,s(" 可以向 DebugView 发送事件。"),n("a",M,[s("了解更多关于 DebugView 的信息"),a(e)]),s(" 。")])]),E]),j])}const S=i(r,[["render",L],["__file","google-analytics.html.vue"]]);export{S as default}; diff --git a/assets/google-analytics.html-86042f8e.js b/assets/google-analytics.html-86042f8e.js new file mode 100644 index 00000000..ea9f9df4 --- /dev/null +++ b/assets/google-analytics.html-86042f8e.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-07ca2692","path":"/zh/reference/plugin/google-analytics.html","title":"google-analytics","lang":"zh-CN","frontmatter":{"description":"将 Google Analytics (https://analytics.google.com/) 集成到 VuePress 中。 该插件会通过引入 gtag.js (https://developers.google.com/analytics/devguides/collection/gtagjs) 来启用 Google Analytics 4 ...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/google-analytics.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/google-analytics.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"google-analytics"}],["meta",{"property":"og:description","content":"将 Google Analytics (https://analytics.google.com/) 集成到 VuePress 中。 该插件会通过引入 gtag.js (https://developers.google.com/analytics/devguides/collection/gtagjs) 来启用 Google Analytics 4 ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"google-analytics\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"上报事件","slug":"上报事件","link":"#上报事件","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"id","slug":"id","link":"#id","children":[]},{"level":3,"title":"debug","slug":"debug","link":"#debug","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.07,"words":320},"filePathRelative":"zh/reference/plugin/google-analytics.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/google-analytics.html-bb077b11.js b/assets/google-analytics.html-bb077b11.js new file mode 100644 index 00000000..c3f815d2 --- /dev/null +++ b/assets/google-analytics.html-bb077b11.js @@ -0,0 +1,26 @@ +import{_ as i,W as c,X as p,Y as e,$ as n,a0 as s,a1 as t,D as o}from"./framework-46b0e263.js";const r={},u=n("h1",{id:"google-analytics",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#google-analytics","aria-hidden":"true"},"#"),s(" google-analytics")],-1),d={href:"https://analytics.google.com/",target:"_blank",rel:"noopener noreferrer"},g={href:"https://developers.google.com/analytics/devguides/collection/gtagjs",target:"_blank",rel:"noopener noreferrer"},h={href:"https://support.google.com/analytics/answer/10089681",target:"_blank",rel:"noopener noreferrer"},v=t(`export default { + plugins: [ + googleAnalyticsPlugin({ + id: "G-XXXXXXXXXX", + debug: true, + }), + ], +}; +
# Usage
npm i -D @vuepress/plugin-google-analytics@next +
import { googleAnalyticsPlugin } from "@vuepress/plugin-google-analytics"; + +export default { + plugins: [ + googleAnalyticsPlugin({ + // options + }), + ], +}; +
# Reporting Events
`,4),k={href:"https://support.google.com/analytics/answer/9234069",target:"_blank",rel:"noopener noreferrer"},_=n("code",null,"page_view",-1),m=n("code",null,"first_visit",-1),b=n("p",null,[s("So if you only want to collect some basic data of your site, you don't need to do anything else except setting the "),n("a",{href:"#id"},"Measurement ID"),s(" correctly.")],-1),y=n("code",null,"gtag()",-1),f=n("code",null,"window",-1),w={href:"https://developers.google.com/analytics/devguides/collection/ga4/events",target:"_blank",rel:"noopener noreferrer"},x=n("h2",{id:"options",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#options","aria-hidden":"true"},"#"),s(" Options")],-1),X=n("h3",{id:"id",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#id","aria-hidden":"true"},"#"),s(" id")],-1),A=n("li",null,[n("p",null,[s("Type: "),n("code",null,"string")])],-1),D=n("p",null,"Details:",-1),I=n("p",null,[s("The Measurement ID of Google Analytics 4, which should start with "),n("code",null,"'G-'"),s(".")],-1),G={href:"https://support.google.com/analytics/answer/9539598",target:"_blank",rel:"noopener noreferrer"},N=n("li",null,[n("p",null,"Example:")],-1),V=t(`export default { + plugins: [ + googleAnalyticsPlugin({ + id: "G-XXXXXXXXXX", + }), + ], +}; +
# debug
`,2),q=n("li",null,[n("p",null,[s("Type: "),n("code",null,"boolean")])],-1),E=n("p",null,"Details:",-1),T=n("code",null,"true",-1),B={href:"https://support.google.com/analytics/answer/7201382",target:"_blank",rel:"noopener noreferrer"},P=n("li",null,[n("p",null,"Example:")],-1),M=t(``,1);function S(j,U){const l=o("NpmBadge"),a=o("ExternalLinkIcon");return c(),p("div",null,[u,e(l,{package:"@vuepress/plugin-google-analytics"}),n("p",null,[s("Integrate "),n("a",d,[s("Google Analytics"),e(a)]),s(" into VuePress.")]),n("p",null,[s("This plugin will import "),n("a",g,[s("gtag.js"),e(a)]),s(" for "),n("a",h,[s("Google Analytics 4"),e(a)]),s(".")]),v,n("p",null,[s("Google Analytics will "),n("a",k,[s("automatically collect some events"),e(a)]),s(", such as "),_,s(", "),m,s(", etc.")]),b,n("p",null,[s("After using this plugin, the global "),y,s(" function is available on the "),f,s(" object, and you can use it for "),n("a",w,[s("custom events reporting"),e(a)]),s(".")]),x,X,n("ul",null,[A,n("li",null,[D,I,n("p",null,[s("You can follow the instructions "),n("a",G,[s("here"),e(a)]),s(' to find your Measurement ID. Notice the difference between Google Analytics 4 Measurement ID (i.e. "G-" ID) and Universal Analytics Tracking ID (i.e. "UA-" ID).')])]),N]),V,n("ul",null,[q,n("li",null,[E,n("p",null,[s("Set to "),T,s(" to enable sending events to DebugView. "),n("a",B,[s("See more information on DebugView"),e(a)]),s(".")])]),P]),M])}const Y=i(r,[["render",S],["__file","google-analytics.html.vue"]]);export{Y as default}; diff --git a/assets/google-analytics.html-fe5b25b3.js b/assets/google-analytics.html-fe5b25b3.js new file mode 100644 index 00000000..43e37564 --- /dev/null +++ b/assets/google-analytics.html-fe5b25b3.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-b3f1b470","path":"/reference/plugin/google-analytics.html","title":"google-analytics","lang":"en-US","frontmatter":{"description":"Integrate Google Analytics (https://analytics.google.com/) into VuePress. This plugin will import gtag.js (https://developers.google.com/analytics/devguides/collection/gtagjs) f...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/google-analytics.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/google-analytics.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"google-analytics"}],["meta",{"property":"og:description","content":"Integrate Google Analytics (https://analytics.google.com/) into VuePress. This plugin will import gtag.js (https://developers.google.com/analytics/devguides/collection/gtagjs) f..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"google-analytics\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Reporting Events","slug":"reporting-events","link":"#reporting-events","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"id","slug":"id","link":"#id","children":[]},{"level":3,"title":"debug","slug":"debug","link":"#debug","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.82,"words":247},"filePathRelative":"reference/plugin/google-analytics.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/hero-8a9eb0cf.js b/assets/hero-8a9eb0cf.js new file mode 100644 index 00000000..d90d6d57 --- /dev/null +++ b/assets/hero-8a9eb0cf.js @@ -0,0 +1 @@ +const o="/images/hero.png";export{o as _}; diff --git a/assets/i18n.html-979c3eb8.js b/assets/i18n.html-979c3eb8.js new file mode 100644 index 00000000..dd046dee --- /dev/null +++ b/assets/i18n.html-979c3eb8.js @@ -0,0 +1,41 @@ +import{_ as i,W as p,X as l,$ as s,a0 as n,Y as e,Z as t,a1 as o,D as c}from"./framework-46b0e263.js";const u={},r=o(`export default { + plugins: [ + googleAnalyticsPlugin({ + id: "G-XXXXXXXXXX", + debug: true, + }), + ], +}; +
# I18n
# Site I18n Config
To take advantage of multi-language support in VuePress, you first need to use the following file and directory structure:
`,4),d=s("code",null,"locales",-1),v=o(`docs +├─ README.md +├─ foo.md +├─ nested +│ └─ README.md +└─ zh + ├─ README.md + ├─ foo.md + └─ nested + └─ README.md +
export default { + locales: { + // The key is the path for the locale to be nested under. + // As a special case, the default locale can use '/' as its path. + "/": { + lang: "en-US", + title: "VuePress", + description: "Vue-powered Static Site Generator", + }, + "/zh/": { + lang: "zh-CN", + title: "VuePress", + description: "Vue 驱动的静态网站生成器", + }, + }, +}; +
If a locale does not have a
`,2),m={class:"hint-container tip"},k=s("p",{class:"hint-container-title"},"Tips",-1),h=o(`lang
,title
,description
orhead
, VuePress will fallback to the root-level values. You can omit the root level config as long as they are provided in each locale.# Theme I18n Config
VuePress does not restrict how themes provide multi-language support, so each theme may have different way to handle i18n, and some themes may not provide multi-language support at all. You'd better refer to the theme documentation for detailed guide.
If you are using default theme, the multi-language support is the same as above:
`,4),g={class:"hint-container tip"},f=s("p",{class:"hint-container-title"},"Tips",-1);function b(_,y){const a=c("RouterLink");return p(),l("div",null,[r,s("p",null,[n("Then, specify the "),d,n(" option in your "),e(a,{to:"/guide/configuration.html#config-file"},{default:t(()=>[n("config file")]),_:1}),n(":")]),v,s("div",m,[k,s("p",null,[n("Config reference: "),e(a,{to:"/reference/config.html#locales"},{default:t(()=>[n("locales")]),_:1})])]),h,s("div",g,[f,s("p",null,[n("Config reference: "),e(a,{to:"/reference/default-theme/config.html#locales"},{default:t(()=>[n("Default Theme > locales")]),_:1})])])])}const x=i(u,[["render",b],["__file","i18n.html.vue"]]);export{x as default}; diff --git a/assets/i18n.html-c6901264.js b/assets/i18n.html-c6901264.js new file mode 100644 index 00000000..c9dd3486 --- /dev/null +++ b/assets/i18n.html-c6901264.js @@ -0,0 +1,41 @@ +import{_ as p,W as i,X as c,$ as s,a0 as n,Y as e,Z as t,a1 as o,D as l}from"./framework-46b0e263.js";const u={},r=o(`import { defaultTheme } from "vuepress"; + +export default { + theme: defaultTheme({ + locales: { + "/": { + selectLanguageName: "English", + }, + "/zh/": { + selectLanguageName: "简体中文", + }, + }, + }), +}; +
# 多语言支持
# 站点多语言配置
要启用 VuePress 的多语言支持,首先需要使用如下的文件目录结构:
`,4),d=s("code",null,"locales",-1),v=o(`docs +├─ README.md +├─ foo.md +├─ nested +│ └─ README.md +└─ zh + ├─ README.md + ├─ foo.md + └─ nested + └─ README.md +
export default { + locales: { + // 键名是该语言所属的子路径 + // 作为特例,默认语言可以使用 '/' 作为其路径。 + "/": { + lang: "en-US", + title: "VuePress", + description: "Vue-powered Static Site Generator", + }, + "/zh/": { + lang: "zh-CN", + title: "VuePress", + description: "Vue 驱动的静态网站生成器", + }, + }, +}; +
如果一个语言没有声明
`,2),k={class:"hint-container tip"},m=s("p",{class:"hint-container-title"},"提示",-1),h=o(`lang
,title
,description
或者head
,VuePress 将会尝试使用顶层配置的对应值。如果每个语言都声明了这些值,那么顶层配置中的对应值可以被省略。# 主题多语言配置
VuePress 没有限制主题如何提供多语言支持,因此每个主题可能会有不同的多语言配置方式,而且部分主题可能不会提供多语言支持。建议你查看主题本身的文档来获取更详细的指引。
如果你使用的是默认主题,那么它提供多语言支持的方式和上述是一致的:
`,4),b={class:"hint-container tip"},g=s("p",{class:"hint-container-title"},"提示",-1);function _(f,q){const a=l("RouterLink");return i(),c("div",null,[r,s("p",null,[n("然后,在你的 "),e(a,{to:"/zh/guide/configuration.html#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"},{default:t(()=>[n("配置文件")]),_:1}),n(" 中设置 "),d,n(" 选项:")]),v,s("div",k,[m,s("p",null,[n("配置参考: "),e(a,{to:"/zh/reference/config.html#locales"},{default:t(()=>[n("locales")]),_:1})])]),h,s("div",b,[g,s("p",null,[n("配置参考: "),e(a,{to:"/zh/reference/default-theme/config.html#locales"},{default:t(()=>[n("默认主题 > locales")]),_:1})])])])}const x=p(u,[["render",_],["__file","i18n.html.vue"]]);export{x as default}; diff --git a/assets/i18n.html-cd078675.js b/assets/i18n.html-cd078675.js new file mode 100644 index 00000000..6d01f6fc --- /dev/null +++ b/assets/i18n.html-cd078675.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-acb10be2","path":"/guide/i18n.html","title":"I18n","lang":"en-US","frontmatter":{"icon":"fa6-solid:language","description":"Site I18n Config To take advantage of multi-language support in VuePress, you first need to use the following file and directory structure: Then, specify the locales option in y...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/i18n.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/i18n.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"I18n"}],["meta",{"property":"og:description","content":"Site I18n Config To take advantage of multi-language support in VuePress, you first need to use the following file and directory structure: Then, specify the locales option in y..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"I18n\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Site I18n Config","slug":"site-i18n-config","link":"#site-i18n-config","children":[]},{"level":2,"title":"Theme I18n Config","slug":"theme-i18n-config","link":"#theme-i18n-config","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.87,"words":260},"filePathRelative":"guide/i18n.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/i18n.html-d3e7282a.js b/assets/i18n.html-d3e7282a.js new file mode 100644 index 00000000..a2cdce46 --- /dev/null +++ b/assets/i18n.html-d3e7282a.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4b8f1400","path":"/zh/guide/i18n.html","title":"多语言支持","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:language","description":"站点多语言配置 要启用 VuePress 的多语言支持,首先需要使用如下的文件目录结构: 然后,在你的 配置文件 (./configuration.md#配置文件) 中设置 locales 选项: 如果一个语言没有声明 lang, title, description 或者 head ,VuePress 将会尝试使用顶层配置的对应值。如果每个语言都声明...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/i18n.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/i18n.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"多语言支持"}],["meta",{"property":"og:description","content":"站点多语言配置 要启用 VuePress 的多语言支持,首先需要使用如下的文件目录结构: 然后,在你的 配置文件 (./configuration.md#配置文件) 中设置 locales 选项: 如果一个语言没有声明 lang, title, description 或者 head ,VuePress 将会尝试使用顶层配置的对应值。如果每个语言都声明..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"多语言支持\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"站点多语言配置","slug":"站点多语言配置","link":"#站点多语言配置","children":[]},{"level":2,"title":"主题多语言配置","slug":"主题多语言配置","link":"#主题多语言配置","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.22,"words":367},"filePathRelative":"zh/guide/i18n.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/index.html-01e674f5.js b/assets/index.html-01e674f5.js new file mode 100644 index 00000000..d70d3c4a --- /dev/null +++ b/assets/index.html-01e674f5.js @@ -0,0 +1 @@ +import{_ as e,W as o,X as a,a1 as t}from"./framework-46b0e263.js";const r={},n=t('import { defaultTheme } from "vuepress"; + +export default { + theme: defaultTheme({ + locales: { + "/": { + selectLanguageName: "English", + }, + "/zh/": { + selectLanguageName: "简体中文", + }, + }, + }), +}; +
# 介绍
# Cookbook 的目的是什么?
- 我们在 指南 中介绍了基本概念,但你可能不知道怎么才能了解得更深入。
- 我们在 参考 中列出了 API ,但你可能不知道如何充分利用它们。
于是就有了 Cookbook 。
每个案例都会针对某个特定的方面,通过提供更详细的示例来向你展示 VuePress 的用法和其他可能性。
',5),s=[n];function c(i,d){return o(),a("div",null,s)}const l=e(r,[["render",c],["__file","index.html.vue"]]);export{l as default}; diff --git a/assets/index.html-1c40c637.js b/assets/index.html-1c40c637.js new file mode 100644 index 00000000..772f7885 --- /dev/null +++ b/assets/index.html-1c40c637.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-43e2b7cf","path":"/reference/default-theme/","title":"Default Theme","lang":"en-US","frontmatter":{"title":"Default Theme","article":false,"feed":false,"sitemap":false,"description":"","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/default-theme/"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/default-theme/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Default Theme"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Default Theme\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-1fc2b45e.js b/assets/index.html-1fc2b45e.js new file mode 100644 index 00000000..cead33c5 --- /dev/null +++ b/assets/index.html-1fc2b45e.js @@ -0,0 +1,38 @@ +import{_ as c,W as r,X as o,Y as d,Z as e,$ as s,a0 as n,D as u}from"./framework-46b0e263.js";const m={},p=s("h3",{id:"as-easy-as-1-2-3",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#as-easy-as-1-2-3","aria-hidden":"true"},"#"),n(" As Easy as 1, 2, 3")],-1),v=s("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[s("pre",{class:"language-bash"},[s("code",null,[s("span",{class:"token comment"},"# install in your project"),n(` +`),s("span",{class:"token function"},"pnpm"),n(),s("span",{class:"token function"},"add"),n(),s("span",{class:"token parameter variable"},"-D"),n(` vuepress@next @vuepress/client@next vue + +`),s("span",{class:"token comment"},"# create a markdown file"),n(` +`),s("span",{class:"token builtin class-name"},"echo"),n(),s("span",{class:"token string"},"'# Hello VuePress'"),n(),s("span",{class:"token operator"},">"),n(` README.md + +`),s("span",{class:"token comment"},"# start writing"),n(` +`),s("span",{class:"token function"},"pnpm"),n(` vuepress dev + +`),s("span",{class:"token comment"},"# build to static files"),n(` +`),s("span",{class:"token function"},"pnpm"),n(` vuepress build +`)])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),b=s("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[s("pre",{class:"language-bash"},[s("code",null,[s("span",{class:"token comment"},"# install in your project"),n(` +`),s("span",{class:"token function"},"yarn"),n(),s("span",{class:"token function"},"add"),n(),s("span",{class:"token parameter variable"},"-D"),n(` vuepress@next + +`),s("span",{class:"token comment"},"# create a markdown file"),n(` +`),s("span",{class:"token builtin class-name"},"echo"),n(),s("span",{class:"token string"},"'# Hello VuePress'"),n(),s("span",{class:"token operator"},">"),n(` README.md + +`),s("span",{class:"token comment"},"# start writing"),n(` +`),s("span",{class:"token function"},"yarn"),n(` vuepress dev + +`),s("span",{class:"token comment"},"# build to static files"),n(` +`),s("span",{class:"token function"},"yarn"),n(` vuepress build +`)])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),k=s("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[s("pre",{class:"language-bash"},[s("code",null,[s("span",{class:"token comment"},"# install in your project"),n(` +`),s("span",{class:"token function"},"npm"),n(),s("span",{class:"token function"},"install"),n(),s("span",{class:"token parameter variable"},"-D"),n(` vuepress@next + +`),s("span",{class:"token comment"},"# create a markdown file"),n(` + +`),s("span",{class:"token builtin class-name"},"echo"),n(),s("span",{class:"token string"},"'# Hello VuePress'"),n(),s("span",{class:"token operator"},">"),n(` README.md + +`),s("span",{class:"token comment"},"# start writing"),n(` + +npx vuepress dev + +`),s("span",{class:"token comment"},"# build to static files"),n(` + +npx vuepress build + +`)])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1);function h(f,_){const t=u("CodeTabs");return r(),o("div",null,[p,d(t,{id:"3",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:e(({title:a,value:l,isActive:i})=>[v]),tab1:e(({title:a,value:l,isActive:i})=>[b]),tab2:e(({title:a,value:l,isActive:i})=>[k]),_:1})])}const x=c(m,[["render",h],["__file","index.html.vue"]]);export{x as default}; diff --git a/assets/index.html-2130e344.js b/assets/index.html-2130e344.js new file mode 100644 index 00000000..4faf065b --- /dev/null +++ b/assets/index.html-2130e344.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-16d7d7b6","path":"/zh/advanced/","title":"Advanced","lang":"en-US","frontmatter":{"title":"Advanced","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Advanced"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Advanced\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-2f61641e.js b/assets/index.html-2f61641e.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-2f61641e.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-3a17c39d.js b/assets/index.html-3a17c39d.js new file mode 100644 index 00000000..9a1e3fee --- /dev/null +++ b/assets/index.html-3a17c39d.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-70e5a528","path":"/zh/reference/","title":"Reference","lang":"en-US","frontmatter":{"title":"Reference","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Reference"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Reference\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-3afbf148.js b/assets/index.html-3afbf148.js new file mode 100644 index 00000000..c99e3093 --- /dev/null +++ b/assets/index.html-3afbf148.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-03c9312a","path":"/advanced/cookbook/","title":"Introduction","lang":"en-US","frontmatter":{"icon":"fa6-solid:circle-info","description":"What's the Cookbook for? We are introducing essential concepts in the Guide, but you may not know how to dig deeper.; We are listing APIs in the Reference, but you may not know ...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/cookbook/"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/cookbook/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Introduction"}],["meta",{"property":"og:description","content":"What's the Cookbook for? We are introducing essential concepts in the Guide, but you may not know how to dig deeper.; We are listing APIs in the Reference, but you may not know ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Introduction\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"What's the Cookbook for?","slug":"what-s-the-cookbook-for","link":"#what-s-the-cookbook-for","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.25,"words":75},"filePathRelative":"advanced/cookbook/README.md","localizedDate":"February 22, 2023","autoDesc":true}`);export{e as data}; diff --git a/assets/index.html-48204d48.js b/assets/index.html-48204d48.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-48204d48.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-5b546a26.js b/assets/index.html-5b546a26.js new file mode 100644 index 00000000..3450b762 --- /dev/null +++ b/assets/index.html-5b546a26.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2d0ad528","path":"/zh/","title":"首页","lang":"zh-CN","frontmatter":{"home":true,"icon":"fa6-solid:house","title":"首页","heroImage":"/images/hero.png","actions":[{"text":"快速上手","link":"/zh/guide/getting-started.html","type":"primary"},{"text":"项目简介","link":"/zh/guide/","type":"secondary"}],"features":[{"title":"简洁至上","icon":"fa6-solid:star","details":"以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。"},{"title":"Vue 驱动","icon":"fa6-brands:vuejs","details":"享受 Vue 的开发体验,可以在 Markdown 中使用 Vue 组件,又可以使用 Vue 来开发自定义主题。"},{"title":"高性能","icon":"fa6-solid:bolt","details":"VuePress 会为每个页面预渲染生成静态的 HTML,同时,每个页面被加载的时候,将作为 SPA 运行。"},{"title":"主题","icon":"fa6-solid:palette","details":"提供了一个开箱即用的默认主题。你也可以挑选一个社区主题,或者创建一个你自己的主题。"},{"title":"插件","icon":"fa6-solid:plug","details":"灵活的插件API,使得插件可以为你的站点提供许多即插即用的功能。"},{"title":"打包工具","icon":"fa6-solid:boxes-packing","details":"默认的打包工具是 Vite ,也同样支持 Webpack 。选一个你喜欢的来使用吧!"}],"description":"像数 1, 2, 3 一样容易 ::: code-tabs#shell tab:active PNPM tab:active YARN tab:active NPM :::","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"首页"}],["meta",{"property":"og:description","content":"像数 1, 2, 3 一样容易 ::: code-tabs#shell tab:active PNPM tab:active YARN tab:active NPM :::"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"首页\\",\\"description\\":\\"像数 1, 2, 3 一样容易 ::: code-tabs#shell tab:active PNPM tab:active YARN tab:active NPM :::\\"}"]]},"headers":[{"level":3,"title":"像数 1, 2, 3 一样容易","slug":"像数-1-2-3-一样容易","link":"#像数-1-2-3-一样容易","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.4,"words":421},"filePathRelative":"zh/README.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/index.html-5e4b3f7a.js b/assets/index.html-5e4b3f7a.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-5e4b3f7a.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-62511030.js b/assets/index.html-62511030.js new file mode 100644 index 00000000..a6a99e25 --- /dev/null +++ b/assets/index.html-62511030.js @@ -0,0 +1 @@ +import{_ as r,W as a,X as i,$ as t,a0 as e,Y as n,a1 as s,D as d}from"./framework-46b0e263.js";const l={},c=t("h1",{id:"introduction",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#introduction","aria-hidden":"true"},"#"),e(" Introduction")],-1),h={href:"https://en.wikipedia.org/wiki/Markdown",target:"_blank",rel:"noopener noreferrer"},u=t("p",null,"The purpose of creating VuePress was to support the documentation of Vue.js and its sub-projects, but now it has been helping a large amount of users to build their documentation, blogs, and other static sites.",-1),p=t("h2",{id:"how-it-works",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#how-it-works","aria-hidden":"true"},"#"),e(" How It Works")],-1),f={href:"https://vuejs.org/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://router.vuejs.org",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},w=t("p",null,"During development, we start a normal dev-server, and serve the VuePress site as a normal SPA. If you’ve used Vue before, you will notice the familiar development experience when you are writing and developing with VuePress.",-1),b={href:"https://nuxtjs.org/",target:"_blank",rel:"noopener noreferrer"},_=t("code",null,"nuxt generate",-1),v={href:"https://www.gatsbyjs.org/",target:"_blank",rel:"noopener noreferrer"},y=s('# Why Not ...?
Nuxt
Nuxt is an outstanding Vue SSR framework, and it is capable of doing what VuePress does. But Nuxt is designed for building applications, while VuePress is more lightweight and focused on content-centric static sites.
VitePress
VitePress is the little brother of VuePress. It's also created and maintained by our Vue.js team. It's even more lightweight and faster than VuePress. However, as a tradeoff, it's more opinionated and less configurable. For example, it does not support plugins. But VitePress is powerful enough to make your content online if you don't need advanced customizations.
It might not be an appropriate comparison, but you can take VuePress and VitePress as Laravel and Lumen.
Docsify / Docute
Both are great projects and also Vue-powered. Except they are both fully runtime-driven and therefore not SEO-friendly. If you don’t care for SEO and don’t want to mess with installing dependencies, these are still great choices.
Hexo
Hexo has been serving the Vue 2.x docs well. The biggest problem is that its theming system is static and string-based - we want to take advantage of Vue for both the layout and the interactivity. Also, Hexo’s Markdown rendering isn’t the most flexible to configure.
',6);function k(V,x){const o=d("ExternalLinkIcon");return a(),i("div",null,[c,t("p",null,[e("VuePress is a markdown-centered static site generator. You can write your content (documentations, blogs, etc.) in "),t("a",h,[e("Markdown"),n(o)]),e(", then VuePress will help you to generate a static site to host them.")]),u,p,t("p",null,[e("A VuePress site is in fact a single-page application (SPA) powered by "),t("a",f,[e("Vue"),n(o)]),e(" and "),t("a",m,[e("Vue Router"),n(o)]),e(".")]),t("p",null,[e("Routes are generated according to the relative path of your markdown files. Each Markdown file is compiled into HTML with "),t("a",g,[e("markdown-it"),n(o)]),e(" and then processed as the template of a Vue component. This allows you to directly use Vue inside your Markdown files and is great when you need to embed dynamic content.")]),w,t("p",null,[e("During build, we create a server-rendered version of the VuePress site and render the corresponding HTML by virtually visiting each route. This approach is inspired by "),t("a",b,[e("Nuxt"),n(o)]),e("'s "),_,e(" command and other projects like "),t("a",v,[e("Gatsby"),n(o)]),e(".")]),y])}const j=r(l,[["render",k],["__file","index.html.vue"]]);export{j as default}; diff --git a/assets/index.html-78973204.js b/assets/index.html-78973204.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-78973204.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-7e872e5b.js b/assets/index.html-7e872e5b.js new file mode 100644 index 00000000..7f62b550 --- /dev/null +++ b/assets/index.html-7e872e5b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-47357bdb","path":"/zh/guide/","title":"介绍","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:circle-info","description":"VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 Markdown (https://zh.wikipedia.org/wiki/Markdown) 来书写内容(如文档、博客等),然后 VuePress 会帮助你生成一个静态网站来展示它们。 VuePress 诞生的初衷是为了支持 Vue.js 及其子项目的文档需求,但是...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"介绍"}],["meta",{"property":"og:description","content":"VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 Markdown (https://zh.wikipedia.org/wiki/Markdown) 来书写内容(如文档、博客等),然后 VuePress 会帮助你生成一个静态网站来展示它们。 VuePress 诞生的初衷是为了支持 Vue.js 及其子项目的文档需求,但是..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"介绍\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"它是如何工作的?","slug":"它是如何工作的","link":"#它是如何工作的","children":[]},{"level":2,"title":"为什么不是 ...?","slug":"为什么不是","link":"#为什么不是","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.81,"words":842},"filePathRelative":"zh/guide/README.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/index.html-80a01853.js b/assets/index.html-80a01853.js new file mode 100644 index 00000000..9553da34 --- /dev/null +++ b/assets/index.html-80a01853.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-fffb8e28","path":"/guide/","title":"Introduction","lang":"en-US","frontmatter":{"icon":"fa6-solid:circle-info","description":"VuePress is a markdown-centered static site generator. You can write your content (documentations, blogs, etc.) in Markdown (https://en.wikipedia.org/wiki/Markdown), then VuePre...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Introduction"}],["meta",{"property":"og:description","content":"VuePress is a markdown-centered static site generator. You can write your content (documentations, blogs, etc.) in Markdown (https://en.wikipedia.org/wiki/Markdown), then VuePre..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Introduction\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"How It Works","slug":"how-it-works","link":"#how-it-works","children":[]},{"level":2,"title":"Why Not ...?","slug":"why-not","link":"#why-not","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.77,"words":530},"filePathRelative":"guide/README.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/index.html-842ca072.js b/assets/index.html-842ca072.js new file mode 100644 index 00000000..2dc11258 --- /dev/null +++ b/assets/index.html-842ca072.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-d61a9282","path":"/reference/plugin/","title":"Plugin","lang":"en-US","frontmatter":{"title":"Plugin","article":false,"feed":false,"sitemap":false,"description":"","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Plugin"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Plugin\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-89525fb9.js b/assets/index.html-89525fb9.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-89525fb9.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-96c02e47.js b/assets/index.html-96c02e47.js new file mode 100644 index 00000000..eb601850 --- /dev/null +++ b/assets/index.html-96c02e47.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-22a2f9fd","path":"/reference/","title":"Reference","lang":"en-US","frontmatter":{"title":"Reference","article":false,"feed":false,"sitemap":false,"description":"","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Reference"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Reference\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-9ac61946.js b/assets/index.html-9ac61946.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-9ac61946.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-a69c820c.js b/assets/index.html-a69c820c.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-a69c820c.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-a809ce07.js b/assets/index.html-a809ce07.js new file mode 100644 index 00000000..bdb551d0 --- /dev/null +++ b/assets/index.html-a809ce07.js @@ -0,0 +1 @@ +import{_ as o,W as s,X as a,$ as t,a0 as e,Y as n,a1 as i,D as c}from"./framework-46b0e263.js";const d={},l=t("h1",{id:"介绍",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#介绍","aria-hidden":"true"},"#"),e(" 介绍")],-1),h={href:"https://zh.wikipedia.org/wiki/Markdown",target:"_blank",rel:"noopener noreferrer"},u=t("p",null,"VuePress 诞生的初衷是为了支持 Vue.js 及其子项目的文档需求,但是现在它已经在帮助大量用户构建他们的文档、博客和其他静态网站。",-1),p=t("h2",{id:"它是如何工作的",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#它是如何工作的","aria-hidden":"true"},"#"),e(" 它是如何工作的?")],-1),_={href:"https://vuejs.org/",target:"_blank",rel:"noopener noreferrer"},V={href:"https://router.vuejs.org",target:"_blank",rel:"noopener noreferrer"},k={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},f=t("p",null,"在开发过程中,我们启动一个常规的开发服务器 (dev-server) ,并将 VuePress 站点作为一个常规的 SPA。如果你以前使用过 Vue 的话,你在使用时会感受到非常熟悉的开发体验。",-1),x={href:"https://nuxtjs.org/",target:"_blank",rel:"noopener noreferrer"},v=t("code",null,"nuxt generate",-1),P={href:"https://www.gatsbyjs.org/",target:"_blank",rel:"noopener noreferrer"},w=i('GitBook
We’ve been using GitBook for most of our sub project docs. The primary problem with GitBook is that its development reload performance is intolerable with a large amount of files. The default theme also has a pretty limiting navigation structure, and the theming system is, again, not Vue based. The team behind GitBook is also more focused on turning it into a commercial product rather than an open-source tool.
# 为什么不是 ...?
Nuxt
Nuxt 是一套出色的 Vue SSR 框架, VuePress 能做的事情,Nuxt 实际上也同样能够胜任。但 Nuxt 是为构建应用程序而生的,而 VuePress 则更为轻量化并且专注在以内容为中心的静态网站上。
VitePress
VitePress 是 VuePress 的孪生兄弟,它同样由 Vue.js 团队创建和维护。 VitePress 甚至比 VuePress 要更轻更快,但它在灵活性和可配置性上作出了一些让步,比如它不支持插件系统。当然,如果你没有进阶的定制化需求, VitePress 已经足够支持你将你的内容部署到线上。
这个比喻可能不是很恰当,但是你可以把 VuePress 和 VitePress 的关系看作 Laravel 和 Lumen 。
Docsify / Docute
这两个项目同样都是基于 Vue,然而它们都是完全的运行时驱动,因此对 SEO 不够友好。如果你并不关注 SEO,同时也不想安装大量依赖,它们仍然是非常好的选择!
Hexo
Hexo 一直驱动着 Vue 2.x 的文档。Hexo 最大的问题在于他的主题系统太过于静态以及过度地依赖纯字符串,而我们十分希望能够好好地利用 Vue 来处理我们的布局和交互。同时,Hexo 在配置 Markdown 渲染方面的灵活性也不是最佳的。
',6);function g(m,b){const r=c("ExternalLinkIcon");return s(),a("div",null,[l,t("p",null,[e("VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 "),t("a",h,[e("Markdown"),n(r)]),e(" 来书写内容(如文档、博客等),然后 VuePress 会帮助你生成一个静态网站来展示它们。")]),u,p,t("p",null,[e("一个 VuePress 站点本质上是一个由 "),t("a",_,[e("Vue"),n(r)]),e(" 和 "),t("a",V,[e("Vue Router"),n(r)]),e(" 驱动的单页面应用 (SPA)。")]),t("p",null,[e("路由会根据你的 Markdown 文件的相对路径来自动生成。每个 Markdown 文件都通过 "),t("a",k,[e("markdown-it"),n(r)]),e(" 编译为 HTML ,然后将其作为 Vue 组件的模板。因此,你可以在 Markdown 文件中直接使用 Vue 语法,便于你嵌入一些动态内容。")]),f,t("p",null,[e("在构建过程中,我们会为 VuePress 站点创建一个服务端渲染 (SSR) 的版本,然后通过虚拟访问每一条路径来渲染对应的 HTML 。这种做法的灵感来源于 "),t("a",x,[e("Nuxt"),n(r)]),e(" 的 "),v,e(" 命令,以及其他的一些项目,比如 "),t("a",P,[e("Gatsby"),n(r)]),e("。")]),w])}const N=o(d,[["render",g],["__file","index.html.vue"]]);export{N as default}; diff --git a/assets/index.html-a8ad45ea.js b/assets/index.html-a8ad45ea.js new file mode 100644 index 00000000..b986b7da --- /dev/null +++ b/assets/index.html-a8ad45ea.js @@ -0,0 +1 @@ +import{_ as e,W as o,X as t,a1 as n}from"./framework-46b0e263.js";const i={},a=n('GitBook
过去我们的子项目文档一直都在使用 GitBook 。 GitBook 最大的问题在于当文件很多时,每次编辑后的重新加载时间长得令人无法忍受。它的默认主题导航结构也比较有限制性,并且,主题系统也不是 Vue 驱动的。GitBook 背后的团队如今也更专注于将其打造为一个商业产品而不是开源工具。
# Introduction
# What's the Cookbook for?
- We are introducing essential concepts in the Guide, but you may not know how to dig deeper.
- We are listing APIs in the Reference, but you may not know how to take full advantage of them.
So here comes the Cookbook.
Each recipe will focus on one specific aspect, providing more detailed examples to show you the usages and possibilities of VuePress.
',5),s=[a];function r(c,h){return o(),t("div",null,s)}const l=e(i,[["render",r],["__file","index.html.vue"]]);export{l as default}; diff --git a/assets/index.html-a94da676.js b/assets/index.html-a94da676.js new file mode 100644 index 00000000..36a934b3 --- /dev/null +++ b/assets/index.html-a94da676.js @@ -0,0 +1,34 @@ +import{_ as c,W as o,X as r,Y as d,Z as e,$ as n,a0 as s,D as m}from"./framework-46b0e263.js";const u={},p=n("h3",{id:"像数-1-2-3-一样容易",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#像数-1-2-3-一样容易","aria-hidden":"true"},"#"),s(" 像数 1, 2, 3 一样容易")],-1),v=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token comment"},"# 在你的项目中安装"),s(` +`),n("span",{class:"token function"},"pnpm"),s(),n("span",{class:"token function"},"add"),s(),n("span",{class:"token parameter variable"},"-D"),s(` vuepress@next @vuepress/client@next vue + +`),n("span",{class:"token comment"},"# 新建一个 markdown 文件"),s(` +`),n("span",{class:"token builtin class-name"},"echo"),s(),n("span",{class:"token string"},"'# Hello VuePress'"),s(),n("span",{class:"token operator"},">"),s(` README.md + +`),n("span",{class:"token comment"},"# 开始写作"),s(` +`),n("span",{class:"token function"},"pnpm"),s(` vuepress dev + +`),n("span",{class:"token comment"},"# 构建静态文件"),s(` +`),n("span",{class:"token function"},"pnpm"),s(` vuepress build +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),b=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token comment"},"# 在你的项目中安装"),s(` +`),n("span",{class:"token function"},"yarn"),s(),n("span",{class:"token function"},"add"),s(),n("span",{class:"token parameter variable"},"-D"),s(` vuepress@next + +`),n("span",{class:"token comment"},"# 新建一个 markdown 文件"),s(` +`),n("span",{class:"token builtin class-name"},"echo"),s(),n("span",{class:"token string"},"'# Hello VuePress'"),s(),n("span",{class:"token operator"},">"),s(` README.md + +`),n("span",{class:"token comment"},"# 开始写作"),s(` +`),n("span",{class:"token function"},"yarn"),s(` vuepress dev + +`),n("span",{class:"token comment"},"# 构建静态文件"),s(` +`),n("span",{class:"token function"},"yarn"),s(` vuepress build +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),k=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token comment"},"# 在你的项目中安装"),s(` +`),n("span",{class:"token function"},"npm"),s(),n("span",{class:"token function"},"install"),s(),n("span",{class:"token parameter variable"},"-D"),s(` vuepress@next + +`),n("span",{class:"token comment"},"# 新建一个 markdown 文件"),s(` +`),n("span",{class:"token builtin class-name"},"echo"),s(),n("span",{class:"token string"},"'# Hello VuePress'"),s(),n("span",{class:"token operator"},">"),s(` README.md + +`),n("span",{class:"token comment"},"# 开始写作"),s(` +npx vuepress dev + +`),n("span",{class:"token comment"},"# 构建静态文件"),s(` +npx vuepress build +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1);function h(_,f){const t=m("CodeTabs");return o(),r("div",null,[p,d(t,{id:"3",data:[{title:"PNPM"},{title:"YARN"},{title:"NPM"}],active:0,"tab-id":"shell"},{tab0:e(({title:a,value:l,isActive:i})=>[v]),tab1:e(({title:a,value:l,isActive:i})=>[b]),tab2:e(({title:a,value:l,isActive:i})=>[k]),_:1})])}const g=c(u,[["render",h],["__file","index.html.vue"]]);export{g as default}; diff --git a/assets/index.html-b5987a1c.js b/assets/index.html-b5987a1c.js new file mode 100644 index 00000000..07eedb3d --- /dev/null +++ b/assets/index.html-b5987a1c.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5b5b9870","path":"/zh/reference/plugin/","title":"Plugin","lang":"en-US","frontmatter":{"title":"Plugin","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Plugin"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Plugin\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-baec65eb.js b/assets/index.html-baec65eb.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-baec65eb.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-c8256226.js b/assets/index.html-c8256226.js new file mode 100644 index 00000000..23924e9d --- /dev/null +++ b/assets/index.html-c8256226.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0a7c8599","path":"/zh/advanced/cookbook/","title":"介绍","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:circle-info","description":"Cookbook 的目的是什么? 我们在 指南 中介绍了基本概念,但你可能不知道怎么才能了解得更深入。; 我们在 参考 中列出了 API ,但你可能不知道如何充分利用它们。; 于是就有了 Cookbook 。 每个案例都会针对某个特定的方面,通过提供更详细的示例来向你展示 VuePress 的用法和其他可能性。","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/advanced/cookbook/"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/cookbook/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"介绍"}],["meta",{"property":"og:description","content":"Cookbook 的目的是什么? 我们在 指南 中介绍了基本概念,但你可能不知道怎么才能了解得更深入。; 我们在 参考 中列出了 API ,但你可能不知道如何充分利用它们。; 于是就有了 Cookbook 。 每个案例都会针对某个特定的方面,通过提供更详细的示例来向你展示 VuePress 的用法和其他可能性。"}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"介绍\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Cookbook 的目的是什么?","slug":"cookbook-的目的是什么","link":"#cookbook-的目的是什么","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.38,"words":115},"filePathRelative":"zh/advanced/cookbook/README.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/index.html-ca328bf3.js b/assets/index.html-ca328bf3.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-ca328bf3.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-d2bb853d.js b/assets/index.html-d2bb853d.js new file mode 100644 index 00000000..7a2d7c0e --- /dev/null +++ b/assets/index.html-d2bb853d.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-31c4276b","path":"/zh/reference/bundler/","title":"Bundler","lang":"en-US","frontmatter":{"title":"Bundler","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/bundler/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Bundler"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Bundler\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-d88310ab.js b/assets/index.html-d88310ab.js new file mode 100644 index 00000000..468366a5 --- /dev/null +++ b/assets/index.html-d88310ab.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2b10d2fc","path":"/reference/bundler/","title":"Bundler","lang":"en-US","frontmatter":{"title":"Bundler","article":false,"feed":false,"sitemap":false,"description":"","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/bundler/"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/bundler/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Bundler"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Bundler\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-dc3052e6.js b/assets/index.html-dc3052e6.js new file mode 100644 index 00000000..cc05a189 --- /dev/null +++ b/assets/index.html-dc3052e6.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-98ca8604","path":"/zh/reference/default-theme/","title":"Default Theme","lang":"en-US","frontmatter":{"title":"Default Theme","article":false,"feed":false,"sitemap":false,"description":"","head":[["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/default-theme/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Default Theme"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Default Theme\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-ee294b98.js b/assets/index.html-ee294b98.js new file mode 100644 index 00000000..b7897107 --- /dev/null +++ b/assets/index.html-ee294b98.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-638c1d18","path":"/advanced/","title":"Advanced","lang":"en-US","frontmatter":{"title":"Advanced","article":false,"feed":false,"sitemap":false,"description":"","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Advanced"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Advanced\\"}"]]},"headers":[],"git":{},"readingTime":{"minutes":0.03,"words":9},"filePathRelative":null,"autoDesc":true}');export{e as data}; diff --git a/assets/index.html-f6507965.js b/assets/index.html-f6507965.js new file mode 100644 index 00000000..5aafd7d4 --- /dev/null +++ b/assets/index.html-f6507965.js @@ -0,0 +1 @@ +import{_,W as a,X as l,Y as o,Z as s,D as e}from"./framework-46b0e263.js";const r={};function i(m,p){const n=e("HopeIcon"),t=e("AutoCatalog");return a(),l("div",null,[o(t,null,{icon:s(({icon:c})=>[o(n,{icon:c},null,8,["icon"])]),_:1})])}const d=_(r,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-fb5c6011.js b/assets/index.html-fb5c6011.js new file mode 100644 index 00000000..8de30cae --- /dev/null +++ b/assets/index.html-fb5c6011.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-8daa1a0e","path":"/","title":"Home","lang":"en-US","frontmatter":{"home":true,"title":"Home","icon":"fa6-solid:house","heroImage":"/images/hero.png","actions":[{"text":"Get Started","link":"/guide/getting-started.html","type":"primary"},{"text":"Introduction","link":"/guide/","type":"secondary"}],"features":[{"title":"Simplicity First","icon":"fa6-solid:star","details":"Minimal setup with markdown-centered project structure helps you focus on writing."},{"title":"Vue-Powered","icon":"fa6-brands:vuejs","details":"Enjoy the dev experience of Vue, use Vue components in markdown, and develop custom themes with Vue."},{"title":"Performant","icon":"fa6-solid:bolt","details":"VuePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded."},{"title":"Themes","icon":"fa6-solid:palette","details":"Providing a default theme out of the box. You can also choose a community theme or create your own one."},{"title":"Plugins","icon":"fa6-solid:plug","details":"Flexible plugin API, allowing plugins to provide lots of plug-and-play features for your site."},{"title":"Bundlers","icon":"fa6-solid:boxes-packing","details":"Default bundler is Vite, while Webpack is also supported. Choose the one you like!"}],"description":"As Easy as 1, 2, 3 ::: code-tabs#shell tab:active PNPM tab YARN tab NPM :::","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/"}],["meta",{"property":"og:url","content":"https://vuejs.press/"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Home"}],["meta",{"property":"og:description","content":"As Easy as 1, 2, 3 ::: code-tabs#shell tab:active PNPM tab YARN tab NPM :::"}],["meta",{"property":"og:type","content":"website"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"WebPage\\",\\"name\\":\\"Home\\",\\"description\\":\\"As Easy as 1, 2, 3 ::: code-tabs#shell tab:active PNPM tab YARN tab NPM :::\\"}"]]},"headers":[{"level":3,"title":"As Easy as 1, 2, 3","slug":"as-easy-as-1-2-3","link":"#as-easy-as-1-2-3","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.94,"words":281},"filePathRelative":"README.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/making-a-theme-extendable.html-4a2e0dc4.js b/assets/making-a-theme-extendable.html-4a2e0dc4.js new file mode 100644 index 00000000..549ed2f0 --- /dev/null +++ b/assets/making-a-theme-extendable.html-4a2e0dc4.js @@ -0,0 +1,35 @@ +import{_ as p,W as o,X as c,$ as s,a0 as n,Y as t,Z as e,a1 as l,D as u}from"./framework-46b0e263.js";const i={},r=s("h1",{id:"开发一个可继承的主题",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#开发一个可继承的主题","aria-hidden":"true"},"#"),n(" 开发一个可继承的主题")],-1),k=s("p",null,"有时用户可能希望对一个主题进行一些小改动,但是又不想 Fork 并修改整个项目。",-1),d=l(`# 布局插槽
这种方式需要你来决定主题的哪些部分是可以被扩展的,它更适合用于一些常见的自定义需求,比如页眉或页脚。
你只需要在你的布局文件中提供 slots ,并告诉用户如何使用它们即可:
<template> + <div class="my-theme-layout"> + <slot name="page-header" /> + <Content /> + <slot name="page-footer" /> + </div> +</template> +
# 组件别名
这种方式需要你考虑清楚你的主题的哪些组件可以被替换,并且你需要将组件拆分到合适的粒度。
首先,为你主题的可替换组件设置
alias
别名:import type { Theme } from "@vuepress/core"; +import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export const fooTheme = (options): Theme => { + return { + name: "vuepress-theme-foo", + alias: { + // 为可替换的组件设置别名 + "@theme/Navbar.vue": path.resolve(__dirname, "components/Navbar.vue"), + "@theme/Sidebar.vue": path.resolve(__dirname, "components/Sidebar.vue"), + }, + }; +}; +
然后,在你的主题中通过别名来使用这些组件:
<script setup lang="ts"> +import Navbar from "@theme/Navbar.vue"; +import Sidebar from "@theme/Sidebar.vue"; +</script> + +<template> + <div class="my-theme-layout"> + <Navbar /> + <Sidebar /> + <Content /> + </div> +</template> +
这样,用户在继承或使用你的主题时,就可以通过覆盖
`,11);function v(m,g){const a=u("RouterLink");return o(),c("div",null,[r,k,s("p",null,[n("借助于 "),t(a,{to:"/zh/reference/theme-api.html"},{default:e(()=>[n("主题 API")]),_:1}),n(" ,你可以让用户继承你的主题,允许用户对你的主题进行改动。")]),s("p",null,[n("你肯定已经知道了如何 "),t(a,{to:"/zh/reference/default-theme/extending.html"},{default:e(()=>[n("继承默认主题")]),_:1}),n(" 。接下来我们将介绍如何让你的主题像默认主题一样被用户继承。")]),d])}const h=p(i,[["render",v],["__file","making-a-theme-extendable.html.vue"]]);export{h as default}; diff --git a/assets/making-a-theme-extendable.html-8d323011.js b/assets/making-a-theme-extendable.html-8d323011.js new file mode 100644 index 00000000..eb3fdbda --- /dev/null +++ b/assets/making-a-theme-extendable.html-8d323011.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-04c514ac","path":"/zh/advanced/cookbook/making-a-theme-extendable.html","title":"开发一个可继承的主题","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:clone","description":"有时用户可能希望对一个主题进行一些小改动,但是又不想 Fork 并修改整个项目。 借助于 主题 API (../../reference/theme-api.md) ,你可以让用户继承你的主题,允许用户对你的主题进行改动。 你肯定已经知道了如何 继承默认主题 (../../reference/default-theme/extending.md) 。接...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/advanced/cookbook/making-a-theme-extendable.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/cookbook/making-a-theme-extendable.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"开发一个可继承的主题"}],["meta",{"property":"og:description","content":"有时用户可能希望对一个主题进行一些小改动,但是又不想 Fork 并修改整个项目。 借助于 主题 API (../../reference/theme-api.md) ,你可以让用户继承你的主题,允许用户对你的主题进行改动。 你肯定已经知道了如何 继承默认主题 (../../reference/default-theme/extending.md) 。接..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"开发一个可继承的主题\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"布局插槽","slug":"布局插槽","link":"#布局插槽","children":[]},{"level":2,"title":"组件别名","slug":"组件别名","link":"#组件别名","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.41,"words":424},"filePathRelative":"zh/advanced/cookbook/making-a-theme-extendable.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/making-a-theme-extendable.html-9a9a0ccd.js b/assets/making-a-theme-extendable.html-9a9a0ccd.js new file mode 100644 index 00000000..929b2905 --- /dev/null +++ b/assets/making-a-theme-extendable.html-9a9a0ccd.js @@ -0,0 +1,35 @@ +import{_ as p,W as o,X as c,$ as s,a0 as n,Y as t,Z as e,a1 as l,D as u}from"./framework-46b0e263.js";const i={},r=s("h1",{id:"making-a-theme-extendable",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#making-a-theme-extendable","aria-hidden":"true"},"#"),n(" Making a Theme Extendable")],-1),k=s("p",null,"Sometimes users might want make some minor changes to a theme, but they don't want to fork and modify the entire project.",-1),d=l(`alias
来替换特定的组件了。# Layout Slots
This approach requires you to determine which parts of your theme could be extended. It is more suitable for those common customizations like page footer or header.
You just need to provide slots in your layouts, and tell users how to make use of them:
<template> + <div class="my-theme-layout"> + <slot name="page-header" /> + <Content /> + <slot name="page-footer" /> + </div> +</template> +
# Component Aliases
This approach requires you to consider which components of your theme should be replaceable, and you also need to split components into a suitable granularity.
First, set
alias
for replaceable components of you theme:import type { Theme } from "@vuepress/core"; +import { getDirname } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export const fooTheme = (options): Theme => { + return { + name: "vuepress-theme-foo", + alias: { + // set alias for replaceable components + "@theme/Navbar.vue": path.resolve(__dirname, "components/Navbar.vue"), + "@theme/Sidebar.vue": path.resolve(__dirname, "components/Sidebar.vue"), + }, + }; +}; +
Next, use those components via aliases in your theme:
<script setup lang="ts"> +import Navbar from "@theme/Navbar.vue"; +import Sidebar from "@theme/Sidebar.vue"; +</script> + +<template> + <div class="my-theme-layout"> + <Navbar /> + <Sidebar /> + <Content /> + </div> +</template> +
Then, users can replace specific components by overriding the
`,11);function m(v,g){const a=u("RouterLink");return o(),c("div",null,[r,k,s("p",null,[n("With the help of "),t(a,{to:"/reference/theme-api.html"},{default:e(()=>[n("Theme API")]),_:1}),n(", you can make your theme extendable, allowing users to make their own modifications easily.")]),s("p",null,[n("You must have known that how to "),t(a,{to:"/reference/default-theme/extending.html"},{default:e(()=>[n("extend default theme")]),_:1}),n(". Here we'll introduce how to make your own theme extendable like default theme.")]),d])}const b=p(i,[["render",m],["__file","making-a-theme-extendable.html.vue"]]);export{b as default}; diff --git a/assets/making-a-theme-extendable.html-f8f662ca.js b/assets/making-a-theme-extendable.html-f8f662ca.js new file mode 100644 index 00000000..54237581 --- /dev/null +++ b/assets/making-a-theme-extendable.html-f8f662ca.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-06adec7d","path":"/advanced/cookbook/making-a-theme-extendable.html","title":"Making a Theme Extendable","lang":"en-US","frontmatter":{"icon":"fa6-solid:clone","description":"Sometimes users might want make some minor changes to a theme, but they don't want to fork and modify the entire project. With the help of Theme API (../../reference/theme-api.m...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/cookbook/making-a-theme-extendable.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/cookbook/making-a-theme-extendable.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Making a Theme Extendable"}],["meta",{"property":"og:description","content":"Sometimes users might want make some minor changes to a theme, but they don't want to fork and modify the entire project. With the help of Theme API (../../reference/theme-api.m..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Making a Theme Extendable\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Layout Slots","slug":"layout-slots","link":"#layout-slots","children":[]},{"level":2,"title":"Component Aliases","slug":"component-aliases","link":"#component-aliases","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.96,"words":289},"filePathRelative":"advanced/cookbook/making-a-theme-extendable.md","localizedDate":"February 22, 2023","autoDesc":true}`);export{e as data}; diff --git a/assets/markdown-and-vue-sfc.html-0af2e2a9.js b/assets/markdown-and-vue-sfc.html-0af2e2a9.js new file mode 100644 index 00000000..a3ba567f --- /dev/null +++ b/assets/markdown-and-vue-sfc.html-0af2e2a9.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4e3c9b8c","path":"/advanced/cookbook/markdown-and-vue-sfc.html","title":"Markdown and Vue SFC","lang":"en-US","frontmatter":{"icon":"fa6-brands:vuejs","description":"Each Markdown file is first compiled into HTML, and then converted to a Vue SFC. In other words, you can write a Markdown file like a Vue SFC: Blocks and are treated as Vue SFC ...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/cookbook/markdown-and-vue-sfc.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/cookbook/markdown-and-vue-sfc.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Markdown and Vue SFC"}],["meta",{"property":"og:description","content":"Each Markdown file is first compiled into HTML, and then converted to a Vue SFC. In other words, you can write a Markdown file like a Vue SFC: Blocks and are treated as Vue SFC ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Markdown and Vue SFC\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.72,"words":215},"filePathRelative":"advanced/cookbook/markdown-and-vue-sfc.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/markdown-and-vue-sfc.html-5c47f4ae.js b/assets/markdown-and-vue-sfc.html-5c47f4ae.js new file mode 100644 index 00000000..857b49da --- /dev/null +++ b/assets/markdown-and-vue-sfc.html-5c47f4ae.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-63e02eaa","path":"/zh/advanced/cookbook/markdown-and-vue-sfc.html","title":"Markdown 与 Vue SFC","lang":"zh-CN","frontmatter":{"icon":"fa6-brands:vuejs","description":"每一个 Markdown 文件,首先都会编译为 HTML ,然后转换为一个 Vue 单文件组件 (SFC) 。换句话说,你可以像写 Vue SFC 一样来写 Markdown 文件: 和 标签会直接被当作 Vue SFC 中的标签。换句话说,它们是从 标签中提升到了 SFC 的顶层。; 所有 和 标签的以外的内容,会先被编译为 HTML ,然后被当作 ...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/advanced/cookbook/markdown-and-vue-sfc.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/cookbook/markdown-and-vue-sfc.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Markdown 与 Vue SFC"}],["meta",{"property":"og:description","content":"每一个 Markdown 文件,首先都会编译为 HTML ,然后转换为一个 Vue 单文件组件 (SFC) 。换句话说,你可以像写 Vue SFC 一样来写 Markdown 文件: 和 标签会直接被当作 Vue SFC 中的标签。换句话说,它们是从 标签中提升到了 SFC 的顶层。; 所有 和 标签的以外的内容,会先被编译为 HTML ,然后被当作 ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Markdown 与 Vue SFC\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.96,"words":287},"filePathRelative":"zh/advanced/cookbook/markdown-and-vue-sfc.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/markdown-and-vue-sfc.html-dc45e8fd.js b/assets/markdown-and-vue-sfc.html-dc45e8fd.js new file mode 100644 index 00000000..aafa3e7c --- /dev/null +++ b/assets/markdown-and-vue-sfc.html-dc45e8fd.js @@ -0,0 +1,31 @@ +import{_ as c,r as l,W as i,X as u,$ as n,a5 as t,Y as d,Z as r,a1 as k,j as v}from"./framework-46b0e263.js";const m=k(`alias
when extending or using your theme.# Markdown and Vue SFC
Each Markdown file is first compiled into HTML, and then converted to a Vue SFC. In other words, you can write a Markdown file like a Vue SFC:
- Blocks
<script>
and<style>
are treated as Vue SFC blocks as they are. In other words, they are hoisted from the<template>
block to the top-level of SFC.- Everything outside
<script>
and<style>
will be compiled into HTML, and be treated as Vue SFC<template>
block.Note
As Vue SFC can contain only one
<script>
element, you should avoid using more than one<script>
in VuePress markdown.Here comes an example:
Input
_Hello, {{ msg }}_ + +<RedDiv> + +_Current count is: {{ count }}_ + +</RedDiv> + +<button @click="count++">Click Me!</button> + +<script setup> +import { h, ref } from "vue"; + +const RedDiv = (_, ctx) => + h( + "div", + { + class: "red-div", + }, + ctx.slots.default() + ); +const msg = "Vue in Markdown"; +const count = ref(0); +</script> + +<style> +.red-div { + color: red; +} +</style> +
Output
`,8),g={__name:"markdown-and-vue-sfc.html",setup(b){const e=(o,s)=>v("div",{class:"red-div"},s.slots.default()),p="Vue in Markdown",a=l(0);return(o,s)=>(i(),u("div",null,[m,n("p",null,[n("em",null,"Hello, "+t(p))]),d(e,null,{default:r(()=>[n("p",null,[n("em",null,"Current count is: "+t(a.value),1)])]),_:1}),n("p",null,[n("button",{onClick:s[0]||(s[0]=f=>a.value++)},"Click Me!")])]))}},_=c(g,[["__file","markdown-and-vue-sfc.html.vue"]]);export{_ as default}; diff --git a/assets/markdown-and-vue-sfc.html-ed00f986.js b/assets/markdown-and-vue-sfc.html-ed00f986.js new file mode 100644 index 00000000..dfcec673 --- /dev/null +++ b/assets/markdown-and-vue-sfc.html-ed00f986.js @@ -0,0 +1,31 @@ +import{_ as o,r as l,W as i,X as u,$ as n,a5 as t,Y as d,Z as r,a1 as k,j as v}from"./framework-46b0e263.js";const m=k(`# Markdown 与 Vue SFC
每一个 Markdown 文件,首先都会编译为 HTML ,然后转换为一个 Vue 单文件组件 (SFC) 。换句话说,你可以像写 Vue SFC 一样来写 Markdown 文件:
<script>
和<style>
标签会直接被当作 Vue SFC 中的标签。换句话说,它们是从<template>
标签中提升到了 SFC 的顶层。- 所有
<script>
和<style>
标签的以外的内容,会先被编译为 HTML ,然后被当作 Vue SFC 的<template>
标签。注意
由于 Vue 单文件组件只能包含一个
<script>
标签,你应该避免在 VuePress Markdown 中使用多于一个<script>
标签。我们来看一个例子:
输入
_你好, {{ msg }}_ + +<RedDiv> + +_当前计数为: {{ count }}_ + +</RedDiv> + +<button @click="count++">点我!</button> + +<script setup> +import { h, ref } from "vue"; + +const RedDiv = (_, ctx) => + h( + "div", + { + class: "red-div", + }, + ctx.slots.default() + ); +const msg = "Markdown 中的 Vue"; +const count = ref(0); +</script> + +<style> +.red-div { + color: red; +} +</style> +
输出
`,8),g={__name:"markdown-and-vue-sfc.html",setup(b){const e=(c,s)=>v("div",{class:"red-div"},s.slots.default()),p="Markdown 中的 Vue",a=l(0);return(c,s)=>(i(),u("div",null,[m,n("p",null,[n("em",null,"你好, "+t(p))]),d(e,null,{default:r(()=>[n("p",null,[n("em",null,"当前计数为: "+t(a.value),1)])]),_:1}),n("p",null,[n("button",{onClick:s[0]||(s[0]=_=>a.value++)},"点我!")])]))}},w=o(g,[["__file","markdown-and-vue-sfc.html.vue"]]);export{w as default}; diff --git a/assets/markdown.html-02e69834.js b/assets/markdown.html-02e69834.js new file mode 100644 index 00000000..be01a7db --- /dev/null +++ b/assets/markdown.html-02e69834.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-176c9c4a","path":"/reference/default-theme/markdown.html","title":"Markdown","lang":"en-US","frontmatter":{"icon":"fa6-brands:markdown","description":"Custom Containers Usage:; The type is required, and the title and content are optional. Supported type : tip; warning; danger; details; Alias of CodeGroup (./components.md#codeg...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/default-theme/markdown.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/default-theme/markdown.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Markdown"}],["meta",{"property":"og:description","content":"Custom Containers Usage:; The type is required, and the title and content are optional. Supported type : tip; warning; danger; details; Alias of CodeGroup (./components.md#codeg..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Markdown\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Custom Containers","slug":"custom-containers","link":"#custom-containers","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.61,"words":184},"filePathRelative":"reference/default-theme/markdown.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/markdown.html-72308ea5.js b/assets/markdown.html-72308ea5.js new file mode 100644 index 00000000..ec1a2e3a --- /dev/null +++ b/assets/markdown.html-72308ea5.js @@ -0,0 +1,59 @@ +import{_ as p,W as v,X as m,Y as e,$ as n,a0 as s,Z as a,a1 as t,D as i}from"./framework-46b0e263.js";const g={},b=n("h1",{id:"markdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown","aria-hidden":"true"},"#"),s(" Markdown")],-1),k=n("h2",{id:"custom-containers",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#custom-containers","aria-hidden":"true"},"#"),s(" Custom Containers")],-1),h=t(`Usage:
::: <type> [title] +[content] +::: +
The
type
is required, and thetitle
andcontent
are optional.Supported
`,4),_=n("li",null,[n("code",null,"tip")],-1),w=n("li",null,[n("code",null,"warning")],-1),f=n("li",null,[n("code",null,"danger")],-1),x=n("li",null,[n("code",null,"details")],-1),y=n("ul",null,[n("li",null,[n("code",null,"code-group")]),n("li",null,[n("code",null,"code-group-item")])],-1),T=n("li",null,[n("p",null,"Example 1 (default title):")],-1),C=t(`type
:Input
::: tip + +This is a tip + +::: + +::: warning + +This is a warning + +::: + +::: danger + +This is a dangerous warning + +::: + +::: details +This is a details block + +::: +
Output
Tips
This is a tip
Note
This is a warning
Warning
This is a dangerous warning
Details
This is a details block
- Example 2 (custom title):
Input
::: danger STOP +Danger zone, do not proceed + +::: + +::: details Click me to view the code + +\`\`\`ts +console.log("Hello, VuePress!"); +\`\`\` + +::: +
Output
STOP
Danger zone, do not proceed
Click me to view the code
console.log("Hello, VuePress!"); +
- Example 3 (code group alias):
Input
:::: code-group +::: code-group-item FOO + +\`\`\`ts +const foo = "foo"; +\`\`\` + +::: + +::: code-group-item BAR + +\`\`\`ts +const bar = "bar"; +\`\`\` + +::: + +:::: +
Output
`,17),q=n("div",{class:"language-typescript line-numbers-mode","data-ext":"ts"},[n("pre",{class:"language-typescript"},[n("code",null,[n("span",{class:"token keyword"},"const"),s(" foo "),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"foo"'),n("span",{class:"token punctuation"},";"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])],-1),O=n("div",{class:"language-typescript line-numbers-mode","data-ext":"ts"},[n("pre",{class:"language-typescript"},[n("code",null,[n("span",{class:"token keyword"},"const"),s(" bar "),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"bar"'),n("span",{class:"token punctuation"},";"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])],-1);function B(N,V){const d=i("NpmBadge"),l=i("RouterLink"),o=i("CodeTabs");return v(),m("div",null,[b,e(d,{package:"@vuepress/theme-default"}),k,n("ul",null,[n("li",null,[h,n("ul",null,[_,w,f,x,n("li",null,[s("Alias of "),e(l,{to:"/reference/default-theme/components.html#codegroup"},{default:a(()=>[s("CodeGroup")]),_:1}),s(" and "),e(l,{to:"/reference/default-theme/components.html#codegroupitem"},{default:a(()=>[s("CodeGroupItem")]),_:1}),s(": "),y])])]),T]),C,e(o,{id:"129",data:[{title:"FOO"},{title:"BAR"}]},{tab0:a(({title:c,value:r,isActive:u})=>[q]),tab1:a(({title:c,value:r,isActive:u})=>[O]),_:1})])}const D=p(g,[["render",B],["__file","markdown.html.vue"]]);export{D as default}; diff --git a/assets/markdown.html-8eab8112.js b/assets/markdown.html-8eab8112.js new file mode 100644 index 00000000..f3144668 --- /dev/null +++ b/assets/markdown.html-8eab8112.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-c78c5de8","path":"/zh/reference/default-theme/markdown.html","title":"Markdown","lang":"zh-CN","frontmatter":{"icon":"fa6-brands:markdown","description":"自定义容器 使用:; type 是必需的, title 和 content 是可选的。 支持的 type 有: tip; warning; danger; details; CodeGroup (./components.md#codegroup) 和 CodeGroupItem (./components.md#codegroupitem) 的别名:...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/default-theme/markdown.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/default-theme/markdown.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Markdown"}],["meta",{"property":"og:description","content":"自定义容器 使用:; type 是必需的, title 和 content 是可选的。 支持的 type 有: tip; warning; danger; details; CodeGroup (./components.md#codegroup) 和 CodeGroupItem (./components.md#codegroupitem) 的别名:..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Markdown\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"自定义容器","slug":"自定义容器","link":"#自定义容器","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.78,"words":234},"filePathRelative":"zh/reference/default-theme/markdown.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/markdown.html-aac5e40a.js b/assets/markdown.html-aac5e40a.js new file mode 100644 index 00000000..e54a32f0 --- /dev/null +++ b/assets/markdown.html-aac5e40a.js @@ -0,0 +1,131 @@ +import{_ as k,W as c,X as r,$ as n,a0 as s,Y as a,Z as e,a2 as m,a3 as v,a4 as h,a1 as i,D as p,a5 as g}from"./framework-46b0e263.js";const b={},_=n("h1",{id:"markdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown","aria-hidden":"true"},"#"),s(" Markdown")],-1),f={href:"https://commonmark.org/help/",target:"_blank",rel:"noopener noreferrer"},w=n("h2",{id:"语法扩展",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#语法扩展","aria-hidden":"true"},"#"),s(" 语法扩展")],-1),x={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/markdown-it/markdown-it#syntax-extensions",target:"_blank",rel:"noopener noreferrer"},M=n("p",null,"本章节将会介绍 VuePress 内置支持的 Markdown 语法扩展。",-1),y=n("h3",{id:"内置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#内置","aria-hidden":"true"},"#"),s(" 内置")],-1),j=n("p",null,"由 markdown-it 内置支持:",-1),z={href:"https://help.github.com/articles/organizing-information-with-tables/",target:"_blank",rel:"noopener noreferrer"},E={href:"https://help.github.com/articles/basic-writing-and-formatting-syntax/#styling-text",target:"_blank",rel:"noopener noreferrer"},L=n("h3",{id:"标题锚点",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#标题锚点","aria-hidden":"true"},"#"),s(" 标题锚点")],-1),V=n("p",null,[s("你可能已经注意到,当你把鼠标放在各个章节的标题上时,会显示出一个 "),n("code",null,"#"),s(" 锚点。点击这个 "),n("code",null,"#"),s(" 锚点,可以直接跳转到对应章节。")],-1),T={class:"hint-container tip"},R=n("p",{class:"hint-container-title"},"提示",-1),P={href:"https://github.com/valeriangalliat/markdown-it-anchor",target:"_blank",rel:"noopener noreferrer"},A=n("h3",{id:"链接",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#链接","aria-hidden":"true"},"#"),s(" 链接")],-1),B={href:"https://spec.commonmark.org/0.29/#link-reference-definitions",target:"_blank",rel:"noopener noreferrer"},C=i(`以我们文档的源文件为例:
└─ docs + └─ zh + ├─ guide + │ ├─ getting-started.md + │ ├─ markdown.md # <- 我们在这里 + │ └─ README.md + ├─ reference + │ └─ config.md + └─ README.md +
原始 Markdown
<!-- 相对路径 --> + +[首页](../README.md) +[配置参考](../reference/config.md) +[快速上手](./getting-started.md) + +<!-- 绝对路径 --> + +[指南](/zh/guide/README.md) +[配置参考 > markdown.links](/zh/reference/config.md#links) + +<!-- URL --> + +[GitHub](https://github.com) +
转换为
<template> + <RouterLink to="/zh/">首页</RouterLink> + <RouterLink to="/zh/reference/config.html">配置参考</RouterLink> + <RouterLink to="/zh/guide/getting-started.html">快速上手</RouterLink> + <RouterLink to="/zh/guide/">指南</RouterLink> + <RouterLink to="/zh/reference/config.html#links" + >配置参考 > markdown.links</RouterLink + > + <a href="https://github.com" target="_blank" rel="noopener noreferrer" + >GitHub</a + > +</template> +
渲染为
`,7),D=n("br",null,null,-1),H=n("br",null,null,-1),S=n("br",null,null,-1),F=n("br",null,null,-1),N=n("br",null,null,-1),U={href:"https://github.com",target:"_blank",rel:"noopener noreferrer"},O=n("p",null,[n("strong",null,"解释")],-1),G=n("li",null,[s("内部链接会被转换为 "),n("code",null,""),s(" 以便进行 SPA 导航。")],-1),I=n("code",null,".md",-1),J=n("li",null,[s("外部链接会被添加 "),n("code",null,'target="_blank" rel="noopener noreferrer"'),s(" 属性。")],-1),W=n("p",null,[n("strong",null,"建议")],-1),X=n("p",null,"对于指向内部 Markdown 文件的链接,尽可能使用相对路径而不是绝对路径。",-1),Y=n("ul",null,[n("li",null,"相对路径是指向目标文件的有效链接,在你的编辑器或者代码仓库中浏览源文件时也可以正确跳转。"),n("li",null,"相对路径在不同 locales 下都是一致的,这样在翻译你的内容时就不需要修改 locale 路径了。")],-1),Z={class:"hint-container tip"},$=n("p",{class:"hint-container-title"},"提示",-1),K=n("p",null,"链接扩展是由我们的内置插件支持的。",-1),Q=n("h3",{id:"emoji",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#emoji","aria-hidden":"true"},"#"),s(" Emoji 🎉")],-1),nn=n("p",null,[s("你可以在你的 Markdown 内容中输入 "),n("code",null,":EMOJICODE:"),s(" 来添加 Emoji 表情。")],-1),sn={href:"https://github.com/ikatyang/emoji-cheat-sheet",target:"_blank",rel:"noopener noreferrer"},an=n("p",null,[n("strong",null,"输入")],-1),en=n("div",{class:"language-markdown line-numbers-mode","data-ext":"md"},[n("pre",{class:"language-markdown"},[n("code",null,`VuePress 2 已经发布 :tada: ! +`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])],-1),tn=n("p",null,[n("strong",null,"输出")],-1),on=n("p",null,"VuePress 2 已经发布 🎉 !",-1),ln={class:"hint-container tip"},pn=n("p",{class:"hint-container-title"},"提示",-1),cn={href:"https://github.com/markdown-it/markdown-it-emoji",target:"_blank",rel:"noopener noreferrer"},rn=i(` # 目录
如果你想要把当前页面的目录添加到 Markdown 内容中,你可以使用
[[toc]]
语法。输入
[[toc]] +
输出
`,5),dn={class:"table-of-contents"},un=n("p",null,[s("目录中的标题将会链接到对应的 "),n("a",{href:"#%E6%A0%87%E9%A2%98%E9%94%9A%E7%82%B9"},"标题锚点"),s(",因此如果你禁用了标题锚点,可能会影响目录的功能。")],-1),kn={class:"hint-container tip"},mn=n("p",{class:"hint-container-title"},"提示",-1),vn={href:"https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc",target:"_blank",rel:"noopener noreferrer"},hn=i(`# 代码块
下列代码块扩展是在 Node 端进行 Markdown 解析的时候实现的。这意味着代码块并不会在客户端被处理。
# 行高亮
你可以在代码块添加行数范围标记,来为对应代码行进行高亮:
输入
\`\`\`ts{1,6-8} +import { defaultTheme, defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + title: '你好, VuePress', + + theme: defaultTheme({ + logo: 'https://vuejs.org/images/logo.png', + }), +}) +\`\`\` +
输出
import { defaultTheme, defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + title: '你好, VuePress', + + theme: defaultTheme({ + logo: 'https://vuejs.org/images/logo.png', + }), +}) +
行数范围标记的例子:
`,10),gn={class:"hint-container tip"},bn=n("p",{class:"hint-container-title"},"提示",-1),_n={href:"https://github.com/egoist/markdown-it-highlight-lines",target:"_blank",rel:"noopener noreferrer"},fn=i(`
- 行数范围:
{5-8}
- 多个单行:
{4,7,9}
- 组合:
{4,7-13,16,23-27,40}
# 行号
你肯定已经注意到在代码块的最左侧会展示行号。这个功能是默认启用的,你可以通过配置来禁用它。
你可以在代码块添加
:line-numbers
/:no-line-numbers
标记来覆盖配置项中的设置。输入
\`\`\`ts +// 行号默认是启用的 +const line2 = "This is line 2"; +const line3 = "This is line 3"; +\`\`\` + +\`\`\`ts:no-line-numbers +// 行号被禁用 +const line2 = 'This is line 2' +const line3 = 'This is line 3' +\`\`\` +
输出
// 行号默认是启用的 +const line2 = "This is line 2"; +const line3 = "This is line 3"; +
`,8),wn={class:"hint-container tip"},xn=n("p",{class:"hint-container-title"},"提示",-1),qn=n("p",null,"行号扩展是由我们的内置插件支持的。",-1),Mn=n("h4",{id:"添加-v-pre",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#添加-v-pre","aria-hidden":"true"},"#"),s(" 添加 v-pre")],-1),yn=n("p",null,[s("由于 "),n("a",{href:"#%E6%A8%A1%E6%9D%BF%E8%AF%AD%E6%B3%95"},"模板语法可以在 Markdown 中使用"),s(",它也同样可以在代码块中生效。")],-1),jn={href:"https://v3.vuejs.org/api/directives.html#v-pre",target:"_blank",rel:"noopener noreferrer"},zn=i(`// 行号被禁用 +const line2 = 'This is line 2' +const line3 = 'This is line 3' +
你可以在代码块添加
:v-pre
/:no-v-pre
标记来覆盖配置项中的设置。注意
模板语法的字符有可能会被语法高亮器解析,比如 "Mustache" 语法(即双花括号)。因此,就像下面的例子一样,在某些语言中
:no-v-pre
可能并不能生效。如果你无论如何都想在这种语言中使用 Vue 语法,你可以尝试禁用默认的语法高亮,然后在客户端实现你的自定义代码高亮。
输入
\`\`\`md +<!-- 默认情况下,这里会被保持原样 --> + +1 + 2 + 3 = {{ 1 + 2 + 3 }} +\`\`\` + +\`\`\`md:no-v-pre +<!-- 这里会被 Vue 编译 --> +1 + 2 + 3 = {{ 1 + 2 + 3 }} +\`\`\` + +\`\`\`js:no-v-pre +// 由于 JS 代码高亮,这里不会被正确编译 +const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} +\`\`\` +
输出
<!-- 默认情况下,这里会被保持原样 --> + +1 + 2 + 3 = {{ 1 + 2 + 3 }} +
`,7),En=i(`<!-- 这里会被 Vue 编译 --> +1 + 2 + 3 = 6 +
`,1),Ln={class:"hint-container tip"},Vn=n("p",{class:"hint-container-title"},"提示",-1),Tn=n("p",null,"v-pre 扩展是由我们的内置插件支持的。",-1),Rn=i(`// 由于 JS 代码高亮,这里不会被正确编译 +const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} +
# 导入代码块
你可以使用下面的语法,从文件中导入代码块:
<!-- 最简单的语法 --> + +@[code](../foo.js) +
如果你只想导入这个文件的一部分:
<!-- 仅导入第 1 行至第 10 行 --> + +@[code{1-10}](../foo.js) +
代码语言会根据文件扩展名进行推断,但我们建议你显式指定:
<!-- 指定代码语言 --> + +@[code js](../foo.js) +
实际上,
[]
内的第二部分会被作为代码块标记来处理,因此在上面 代码块 章节中提到的语法在这里都可以支持:<!-- 行高亮 --> + +@[code js{2,4-5}](../foo.js) +
下面是一个复杂的例子:
- 导入
'../foo.js'
文件的第 3 行至第 10 行- 指定语言为
'js'
- 对导入代码的第 3 行进行高亮,即
'../foo.js'
文件的第 5 行- 禁用行号
@[code{3-10} js{3}:no-line-numbers](../foo.js) +
需要注意的是,路径别名在导入代码语法中不会生效。你可以通过下面的配置来自行处理路径别名:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + markdown: { + importCode: { + handleImportPath: (str) => + str.replace(/^@src/, path.resolve(__dirname, "path/to/src")), + }, + }, +}; +
`,15),Pn={class:"hint-container tip"},An=n("p",{class:"hint-container-title"},"提示",-1),Bn=n("p",null,"导入代码扩展是由我们的内置插件支持的。",-1),Cn=n("h2",{id:"在-markdown-中使用-vue",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#在-markdown-中使用-vue","aria-hidden":"true"},"#"),s(" 在 Markdown 中使用 Vue")],-1),Dn=n("p",null,"这一章节会介绍 Vue 在 Markdown 中一些基本用法。",-1),Hn=n("h3",{id:"模板语法",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#模板语法","aria-hidden":"true"},"#"),s(" 模板语法")],-1),Sn=n("p",null,"我们知道:",-1),Fn=n("ul",null,[n("li",null,"Markdown 中允许使用 HTML。"),n("li",null,"Vue 模板语法是和 HTML 兼容的。")],-1),Nn={href:"https://v3.vuejs.org/guide/template-syntax.html",target:"_blank",rel:"noopener noreferrer"},Un=i(`<!-- 会被解析至 'path/to/src/foo.js' --> + +@[code](@src/foo.js) +
输入
一加一等于: {{ 1 + 1 }} + +<span v-for="i in 3"> span: {{ i }} </span> +
输出
一加一等于: 2
`,4),On=i('# 组件
你可以在 Markdown 中直接使用 Vue 组件。
输入
这是默认主题内置的 `<Badge />` 组件 <Badge text="演示" />\n
输出
',5),Gn=n("code",null,"",-1),In={class:"hint-container tip"},Jn=n("p",{class:"hint-container-title"},"提示",-1),Wn=n("h2",{id:"注意事项",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#注意事项","aria-hidden":"true"},"#"),s(" 注意事项")],-1),Xn=n("h3",{id:"非标准的-html-标签",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#非标准的-html-标签","aria-hidden":"true"},"#"),s(" 非标准的 HTML 标签")],-1),Yn=n("p",null,"非标准的 HTML 标签不会被 Vue 模板编译器识别成原生 HTML 标签。相反,Vue 会尝试将这些标签解析为 Vue 组件,而显然这些组件通常是不存在的。 例如:",-1),Zn={href:"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/center",target:"_blank",rel:"noopener noreferrer"},$n={href:"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font",target:"_blank",rel:"noopener noreferrer"},Kn={href:"https://developer.mozilla.org/zh-CN/docs/Web/MathML",target:"_blank",rel:"noopener noreferrer"},Qn=n("p",null,"如果你无论如何都要使用这些标签的话,可以尝试下面两种方法之一:",-1),ns={href:"https://v3.cn.vuejs.org/api/directives.html#v-pre",target:"_blank",rel:"noopener noreferrer"},ss={href:"https://v3.vuejs.org/api/application-config.html#compileroptions",target:"_blank",rel:"noopener noreferrer"},as=n("code",null,"@bundler-webpack",-1),es=n("code",null,"@bundler-vite",-1);function ts(os,ls){const o=p("ExternalLinkIcon"),t=p("RouterLink"),l=p("router-link"),d=p("Badge");return c(),r("div",null,[_,n("p",null,[s("在阅读本章节之前,请确保你已经对 Markdown 有所了解。如果你还不了解 Markdown ,请先学习一些 "),n("a",f,[s("Markdown 教程"),a(o)]),s("。")]),w,n("p",null,[s("VuePress 会使用 "),n("a",x,[s("markdown-it"),a(o)]),s(" 来解析 Markdown 内容,因此可以借助于 markdown-it 插件来实现 "),n("a",q,[s("语法扩展"),a(o)]),s(" 。")]),M,n("p",null,[s("你也可以通过 "),a(t,{to:"/zh/reference/config.html#markdown"},{default:e(()=>[s("markdown")]),_:1}),s(" 和 "),a(t,{to:"/zh/reference/plugin-api.html#extendsmarkdown"},{default:e(()=>[s("extendsMarkdown")]),_:1}),s(" 来配置这些内置扩展、加载更多 markdown-it 插件、实现你自己的扩展等。")]),y,j,n("ul",null,[n("li",null,[n("a",z,[s("表格"),a(o)]),s(" (GFM)")]),n("li",null,[n("a",E,[s("删除线"),a(o)]),s(" (GFM)")])]),L,V,n("div",T,[R,n("p",null,[s("标题锚点扩展由 "),n("a",P,[s("markdown-it-anchor"),a(o)]),s(" 支持。")]),n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-anchor"},{default:e(()=>[s("markdown.anchor")]),_:1})])]),A,n("p",null,[s("在你使用 Markdown 的 "),n("a",B,[s("链接语法"),a(o)]),s(" 时, VuePress 会为你进行一些转换。")]),C,n("p",null,[a(t,{to:"/zh/"},{default:e(()=>[s("首页")]),_:1}),D,a(t,{to:"/zh/reference/config.html"},{default:e(()=>[s("配置参考")]),_:1}),H,a(t,{to:"/zh/guide/getting-started.html"},{default:e(()=>[s("快速上手")]),_:1}),S,a(t,{to:"/zh/guide/"},{default:e(()=>[s("指南")]),_:1}),F,a(t,{to:"/zh/reference/config.html#links"},{default:e(()=>[s("配置参考 > markdown.links")]),_:1}),N,n("a",U,[s("GitHub"),a(o)])]),O,n("ul",null,[G,n("li",null,[s("指向 "),I,s(" 文件的内部链接会被转换为目标页面的 "),a(t,{to:"/zh/guide/page.html#%E8%B7%AF%E7%94%B1"},{default:e(()=>[s("路由路径")]),_:1}),s(",并且支持绝对路径和相对路径。")]),J]),W,X,Y,n("div",Z,[$,K,n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-links"},{default:e(()=>[s("markdown.links")]),_:1})])]),Q,nn,n("p",null,[s("前往 "),n("a",sn,[s("emoji-cheat-sheet"),a(o)]),s(" 来查看所有可用的 Emoji 表情和对应代码。")]),an,en,tn,on,n("div",ln,[pn,n("p",null,[s("Emoji 扩展由 "),n("a",cn,[s("markdown-it-emoji"),a(o)]),s(" 支持。")]),n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-emoji"},{default:e(()=>[s("markdown.emoji")]),_:1})])]),rn,n("nav",dn,[n("ul",null,[n("li",null,[a(l,{to:"#语法扩展"},{default:e(()=>[s("语法扩展")]),_:1}),n("ul",null,[n("li",null,[a(l,{to:"#内置"},{default:e(()=>[s("内置")]),_:1})]),n("li",null,[a(l,{to:"#标题锚点"},{default:e(()=>[s("标题锚点")]),_:1})]),n("li",null,[a(l,{to:"#链接"},{default:e(()=>[s("链接")]),_:1})]),n("li",null,[a(l,{to:"#emoji"},{default:e(()=>[s("Emoji 🎉")]),_:1})]),n("li",null,[a(l,{to:"#目录"},{default:e(()=>[s("目录")]),_:1})]),n("li",null,[a(l,{to:"#代码块"},{default:e(()=>[s("代码块")]),_:1})]),n("li",null,[a(l,{to:"#导入代码块"},{default:e(()=>[s("导入代码块")]),_:1})])])]),n("li",null,[a(l,{to:"#在-markdown-中使用-vue"},{default:e(()=>[s("在 Markdown 中使用 Vue")]),_:1}),n("ul",null,[n("li",null,[a(l,{to:"#模板语法"},{default:e(()=>[s("模板语法")]),_:1})]),n("li",null,[a(l,{to:"#组件"},{default:e(()=>[s("组件")]),_:1})])])]),n("li",null,[a(l,{to:"#注意事项"},{default:e(()=>[s("注意事项")]),_:1}),n("ul",null,[n("li",null,[a(l,{to:"#非标准的-html-标签"},{default:e(()=>[s("非标准的 HTML 标签")]),_:1})])])])])]),un,n("div",kn,[mn,n("p",null,[s("目录扩展由 "),n("a",vn,[s("@mdit-vue/plugin-toc"),a(o)]),s(" 支持。")]),n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-toc"},{default:e(()=>[s("markdown.toc")]),_:1})])]),hn,n("div",gn,[bn,n("p",null,[s("行高亮扩展是由我们的内置插件支持的,该扩展 Fork 并修改自 "),n("a",_n,[s("markdown-it-highlight-lines"),a(o)]),s("。")]),n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-code-highlightlines"},{default:e(()=>[s("markdown.code.highlightLines")]),_:1})])]),fn,n("div",wn,[xn,qn,n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-code-linenumbers"},{default:e(()=>[s("markdown.code.lineNumbers")]),_:1})])]),Mn,yn,n("p",null,[s("为了避免你的代码块被 Vue 编译, VuePress 默认会在你的代码块添加 "),n("a",jn,[s("v-pre"),a(o)]),s(" 指令。这一默认行为可以在配置中关闭。")]),zn,m(` +在 JS 代码块上使用 :no-v-pre 的话,会在使用 shiki 时遇到一些潜在的问题,所以这里 +我们实际上没有使用 :no-v-pre ,只是作为一个错误用法的示例。 +`),En,n("div",Ln,[Vn,Tn,n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-code-vpre-block"},{default:e(()=>[s("markdown.code.vPre.block")]),_:1})])]),Rn,n("div",Pn,[An,Bn,n("p",null,[s("配置参考: "),a(t,{to:"/zh/reference/config.html#markdown-importcode"},{default:e(()=>[s("markdown.importCode")]),_:1})])]),Cn,Dn,n("p",null,[s("可以前往 "),a(t,{to:"/zh/advanced/cookbook/markdown-and-vue-sfc.html"},{default:e(()=>[s("Cookbook > Markdown 和 Vue SFC")]),_:1}),s(" 来了解更多内容。")]),Hn,Sn,Fn,n("p",null,[s("这意味着, Markdown 中允许直接使用 "),n("a",Nn,[s("Vue 模板语法"),a(o)]),s("。")]),Un,n("p",null,[(c(),r(v,null,h(3,u=>n("span",null," span: "+g(u),1)),64))]),On,n("p",null,[s("这是默认主题内置的 "),Gn,s(" 组件 "),a(d,{text:"演示"})]),n("div",In,[Jn,n("p",null,[s("前往 "),a(t,{to:"/zh/reference/components.html"},{default:e(()=>[s("内置组件")]),_:1}),s(" 查看所有内置组件。")]),n("p",null,[s("前往 "),a(t,{to:"/zh/reference/default-theme/components.html"},{default:e(()=>[s("默认主题 > 内置组件")]),_:1}),s(" 查看默认主题中的所有内置组件。")])]),Wn,Xn,Yn,n("ul",null,[n("li",null,[s("已废弃的 HTML 标签,比如 "),n("a",Zn,[s(" "),a(o)]),s(" 和 "),n("a",$n,[s(""),a(o)]),s(" 等。")]),n("li",null,[n("a",Kn,[s("MathML 标签"),a(o)]),s(",它们可能会被一些 markdown-it 的 LaTeX 插件用到。")])]),Qn,n("ul",null,[n("li",null,[s("添加一个 "),n("a",ns,[s("v-pre"),a(o)]),s(" 指令来跳过这个元素和它的子元素的编译过程。注意所有的模板语法也都会失效。")]),n("li",null,[s("设置 "),n("a",ss,[s("compilerOptions.isCustomElement"),a(o)]),s(" 来告诉 Vue 模板编译器不要尝试作为组件来解析它们。 "),n("ul",null,[n("li",null,[s("对于 "),as,s(" ,设置 "),a(t,{to:"/zh/reference/bundler/webpack.html#vue"},{default:e(()=>[s("vue.compilerOptions")]),_:1})]),n("li",null,[s("对于 "),es,s(" ,设置 "),a(t,{to:"/zh/reference/bundler/vite.html#vuepluginoptions"},{default:e(()=>[s("vuePluginOptions.template.compilerOptions")]),_:1})])])])])])}const ps=k(b,[["render",ts],["__file","markdown.html.vue"]]);export{ps as default}; diff --git a/assets/markdown.html-c9777236.js b/assets/markdown.html-c9777236.js new file mode 100644 index 00000000..4dfaf5d2 --- /dev/null +++ b/assets/markdown.html-c9777236.js @@ -0,0 +1,130 @@ +import{_ as m,W as c,X as r,$ as n,a0 as s,Y as e,Z as a,a2 as k,a3 as h,a4 as g,a1 as i,D as p,a5 as v}from"./framework-46b0e263.js";const b={},f=n("h1",{id:"markdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown","aria-hidden":"true"},"#"),s(" Markdown")],-1),_={href:"https://commonmark.org/help/",target:"_blank",rel:"noopener noreferrer"},w=n("h2",{id:"syntax-extensions",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#syntax-extensions","aria-hidden":"true"},"#"),s(" Syntax Extensions")],-1),y={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},x={href:"https://github.com/markdown-it/markdown-it#syntax-extensions",target:"_blank",rel:"noopener noreferrer"},T=n("p",null,"This section will introduce built-in Markdown syntax extensions of VuePress.",-1),C=n("h3",{id:"embedded",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#embedded","aria-hidden":"true"},"#"),s(" Embedded")],-1),q=n("p",null,"Embedded by markdown-it:",-1),j={href:"https://help.github.com/articles/organizing-information-with-tables/",target:"_blank",rel:"noopener noreferrer"},M={href:"https://help.github.com/articles/basic-writing-and-formatting-syntax/#styling-text",target:"_blank",rel:"noopener noreferrer"},L=n("h3",{id:"header-anchors",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#header-anchors","aria-hidden":"true"},"#"),s(" Header Anchors")],-1),R=n("p",null,[s("You might have noticed that, a "),n("code",null,"#"),s(" anchor is displayed when you hover the mouse on the headers of each section. By clicking the "),n("code",null,"#"),s(" anchor, you can jump to the section directly.")],-1),V={class:"hint-container tip"},E=n("p",{class:"hint-container-title"},"Tips",-1),H={href:"https://github.com/valeriangalliat/markdown-it-anchor",target:"_blank",rel:"noopener noreferrer"},I=n("h3",{id:"links",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#links","aria-hidden":"true"},"#"),s(" Links")],-1),S={href:"https://spec.commonmark.org/0.29/#link-reference-definitions",target:"_blank",rel:"noopener noreferrer"},O=i(` Take our documentation source files as an example:
└─ docs + ├─ guide + │ ├─ getting-started.md + │ ├─ markdown.md # <- Here we are + │ └─ README.md + ├─ reference + │ └─ config.md + └─ README.md +
Raw Markdown
<!-- relative path --> + +[Home](../README.md) +[Config Reference](../reference/config.md) +[Getting Started](./getting-started.md) + +<!-- absolute path --> + +[Guide](/guide/README.md) +[Config Reference > markdown.links](/reference/config.md#links) + +<!-- URL --> + +[GitHub](https://github.com) +
Converted to
<template> + <RouterLink to="/">Home</RouterLink> + <RouterLink to="/reference/config.html">Config Reference</RouterLink> + <RouterLink to="/guide/getting-started.html">Getting Started</RouterLink> + <RouterLink to="/guide/">Guide</RouterLink> + <RouterLink to="/reference/config.html#links" + >Config Reference > markdown.links</RouterLink + > + <a href="https://github.com" target="_blank" rel="noopener noreferrer" + >GitHub</a + > +</template> +
Rendered as
`,7),B=n("br",null,null,-1),P=n("br",null,null,-1),N=n("br",null,null,-1),D=n("br",null,null,-1),G=n("br",null,null,-1),U={href:"https://github.com",target:"_blank",rel:"noopener noreferrer"},Y=n("p",null,[n("strong",null,"Explanation")],-1),A=n("li",null,[s("Internal links will be converted to "),n("code",null,""),s(" for SPA navigation.")],-1),F=n("code",null,".md",-1),W=n("li",null,[s("External links will get "),n("code",null,'target="_blank" rel="noopener noreferrer"'),s(" attrs.")],-1),z=n("p",null,[n("strong",null,"Suggestion")],-1),J=n("p",null,"Try to use relative paths instead of absolute paths for internal links to markdown files.",-1),X=n("ul",null,[n("li",null,"Relative paths are a valid links to the target files, and they can navigate correctly when browsing the source files in your editor or repository."),n("li",null,"Relative paths are consistent in different locales, so you don't need to change the locale path when translating your content.")],-1),Z={class:"hint-container tip"},$=n("p",{class:"hint-container-title"},"Tips",-1),K=n("p",null,"This links extension is supported by our built-in plugin.",-1),Q=n("h3",{id:"emoji",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#emoji","aria-hidden":"true"},"#"),s(" Emoji 🎉")],-1),nn=n("p",null,[s("You can add emoji to your Markdown content by typing "),n("code",null,":EMOJICODE:"),s(".")],-1),sn={href:"https://github.com/ikatyang/emoji-cheat-sheet",target:"_blank",rel:"noopener noreferrer"},en=n("p",null,[n("strong",null,"Input")],-1),an=n("div",{class:"language-markdown line-numbers-mode","data-ext":"md"},[n("pre",{class:"language-markdown"},[n("code",null,`VuePress 2 is out :tada: ! +`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])],-1),tn=n("p",null,[n("strong",null,"Output")],-1),on=n("p",null,"VuePress 2 is out 🎉 !",-1),ln={class:"hint-container tip"},pn=n("p",{class:"hint-container-title"},"Tips",-1),cn={href:"https://github.com/markdown-it/markdown-it-emoji",target:"_blank",rel:"noopener noreferrer"},rn=i(` # Table of Contents
If you want to put the table of contents (TOC) of your current page inside your Markdown content, you can use the
[[toc]]
syntax.Input
[[toc]] +
Output
`,5),dn={class:"table-of-contents"},un=n("p",null,[s("The headers in TOC will link to the corresponding "),n("a",{href:"#header-anchors"},"header anchors"),s(", so TOC won't work well if you disable header anchors.")],-1),mn={class:"hint-container tip"},kn=n("p",{class:"hint-container-title"},"Tips",-1),hn={href:"https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc",target:"_blank",rel:"noopener noreferrer"},gn=i(`# Code Blocks
Following code blocks extensions are implemented during markdown parsing in Node side. That means, the code blocks won't be processed in client side.
# Line Highlighting
You can highlight specified lines of your code blocks by adding line ranges mark in your fenced code blocks:
Input
\`\`\`ts{1,6-8} +import { defaultTheme, defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + title: 'Hello, VuePress', + + theme: defaultTheme({ + logo: 'https://vuejs.org/images/logo.png', + }), +}) +\`\`\` +
Output
import { defaultTheme, defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + title: 'Hello, VuePress', + + theme: defaultTheme({ + logo: 'https://vuejs.org/images/logo.png', + }), +}) +
Examples for line ranges mark:
`,10),vn={class:"hint-container tip"},bn=n("p",{class:"hint-container-title"},"Tips",-1),fn={href:"https://github.com/egoist/markdown-it-highlight-lines",target:"_blank",rel:"noopener noreferrer"},_n=i(`
- Line ranges:
{5-8}
- Multiple single lines:
{4,7,9}
- Combined:
{4,7-13,16,23-27,40}
# Line Numbers
You must have noticed that the number of lines is displayed on the left side of code blocks. This is enabled by default and you can disable it in config.
You can add
:line-numbers
/:no-line-numbers
mark in your fenced code blocks to override the value set in config.Input
\`\`\`ts +// line-numbers is enabled by default +const line2 = "This is line 2"; +const line3 = "This is line 3"; +\`\`\` + +\`\`\`ts:no-line-numbers +// line-numbers is disabled +const line2 = 'This is line 2' +const line3 = 'This is line 3' +\`\`\` +
Output
// line-numbers is enabled by default +const line2 = "This is line 2"; +const line3 = "This is line 3"; +
`,8),wn={class:"hint-container tip"},yn=n("p",{class:"hint-container-title"},"Tips",-1),xn=n("p",null,"This line numbers extension is supported by our built-in plugin.",-1),Tn=n("h4",{id:"wrap-with-v-pre",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#wrap-with-v-pre","aria-hidden":"true"},"#"),s(" Wrap with v-pre")],-1),Cn=n("p",null,[s("As "),n("a",{href:"#template-syntax"},"template syntax is allowed in Markdown"),s(", it would also work in code blocks, too.")],-1),qn={href:"https://vuejs.org/api/built-in-directives.html#v-pre",target:"_blank",rel:"noopener noreferrer"},jn=i(`// line-numbers is disabled +const line2 = 'This is line 2' +const line3 = 'This is line 3' +
You can add
:v-pre
/:no-v-pre
mark in your fenced code blocks to override the value set in config.Note
The template syntax characters, for example, the "Mustache" syntax (double curly braces) might be parsed by the syntax highlighter. Thus, as the following example,
:no-v-pre
might not work well in some languages.If you want to make Vue syntax work in those languages anyway, try to disable the default syntax highlighting and implement your own syntax highlighting in client side.
Input
\`\`\`md +<!-- This will be kept as is by default --> + +1 + 2 + 3 = {{ 1 + 2 + 3 }} +\`\`\` + +\`\`\`md:no-v-pre +<!-- This will be compiled by Vue --> +1 + 2 + 3 = {{ 1 + 2 + 3 }} +\`\`\` + +\`\`\`js:no-v-pre +// This won't be compiled correctly because of js syntax highlighting +const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} +\`\`\` +
Output
<!-- This will be kept as is --> + +1 + 2 + 3 = {{ 1 + 2 + 3 }} +
`,7),Mn=i(`<!-- This will be compiled by Vue --> +1 + 2 + 3 = 6 +
`,1),Ln={class:"hint-container tip"},Rn=n("p",{class:"hint-container-title"},"Tips",-1),Vn=n("p",null,"This v-pre extension is supported by our built-in plugin.",-1),En=i(`// This won't be compiled correctly because of js syntax highlighting +const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} +
# Import Code Blocks
You can import code blocks from files with following syntax:
<!-- minimal syntax --> + +@[code](../foo.js) +
If you want to partially import the file:
<!-- partial import, from line 1 to line 10 --> + +@[code{1-10}](../foo.js) +
The code language is inferred from the file extension, while it is recommended to specify it explicitly:
<!-- specify the code language --> + +@[code js](../foo.js) +
In fact, the second part inside the
[]
will be treated as the mark of the code fence, so it supports all the syntax mentioned in the above Code Blocks section:<!-- line highlighting --> + +@[code js{2,4-5}](../foo.js) +
Here is a complex example:
- import line 3 to line 10 of the
'../foo.js'
file- specify the language as
'js'
- highlight line 3 of the imported code, i.e. line 5 of the
'../foo.js'
file- disable line numbers
@[code{3-10} js{3}:no-line-numbers](../foo.js) +
Notice that path aliases are not available in import code syntax. You can use following config to handle path alias yourself:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + markdown: { + importCode: { + handleImportPath: (str) => + str.replace(/^@src/, path.resolve(__dirname, "path/to/src")), + }, + }, +}; +
`,15),Hn={class:"hint-container tip"},In=n("p",{class:"hint-container-title"},"Tips",-1),Sn=n("p",null,"This import code extension is supported by our built-in plugin.",-1),On=n("h2",{id:"using-vue-in-markdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#using-vue-in-markdown","aria-hidden":"true"},"#"),s(" Using Vue in Markdown")],-1),Bn=n("p",null,"This section will introduce some basic usage of Vue in Markdown.",-1),Pn=n("h3",{id:"template-syntax",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#template-syntax","aria-hidden":"true"},"#"),s(" Template Syntax")],-1),Nn=n("p",null,"As we know:",-1),Dn=n("ul",null,[n("li",null,"HTML is allowed in Markdown."),n("li",null,"Vue template syntax is compatible with HTML.")],-1),Gn={href:"https://vuejs.org/guide/essentials/template-syntax.html",target:"_blank",rel:"noopener noreferrer"},Un=i(`<!-- it will be resolved to 'path/to/src/foo.js' --> + +@[code](@src/foo.js) +
Input
One plus one equals: {{ 1 + 1 }} + +<span v-for="i in 3"> span: {{ i }} </span> +
Output
One plus one equals: 2
`,4),Yn=i('# Components
You can use Vue components directly in Markdown.
Input
This is default theme built-in `<Badge />` component <Badge text="demo" />\n
Output
',5),An=n("code",null,"",-1),Fn={class:"hint-container tip"},Wn=n("p",{class:"hint-container-title"},"Tips",-1),zn=n("h2",{id:"cautions",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#cautions","aria-hidden":"true"},"#"),s(" Cautions")],-1),Jn=n("h3",{id:"non-standard-html-tags",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#non-standard-html-tags","aria-hidden":"true"},"#"),s(" Non-Standard HTML Tags")],-1),Xn=n("p",null,"Non-standard HTML tags would not be recognized as native HTML tags by Vue template compiler. Instead, Vue will try to resolve those tags as Vue components, and obviously these components usually don't exist. For example:",-1),Zn={href:"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/center",target:"_blank",rel:"noopener noreferrer"},$n={href:"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font",target:"_blank",rel:"noopener noreferrer"},Kn={href:"https://developer.mozilla.org/en-US/docs/Web/MathML",target:"_blank",rel:"noopener noreferrer"},Qn=n("p",null,"If you want to use those tags anyway, try either of the following workarounds:",-1),ns={href:"https://vuejs.org/api/built-in-directives.html#v-pre",target:"_blank",rel:"noopener noreferrer"},ss={href:"https://vuejs.org/api/application.html#app-config-compileroptions",target:"_blank",rel:"noopener noreferrer"},es=n("code",null,"@bundler-webpack",-1),as=n("code",null,"@bundler-vite",-1);function ts(os,ls){const o=p("ExternalLinkIcon"),t=p("RouterLink"),l=p("router-link"),d=p("Badge");return c(),r("div",null,[f,n("p",null,[s("Make sure you already know Markdown well before reading this section. If not, please learn some "),n("a",_,[s("Markdown tutorials"),e(o)]),s(" first.")]),w,n("p",null,[s("The Markdown content in VuePress will be parsed by "),n("a",y,[s("markdown-it"),e(o)]),s(", which supports "),n("a",x,[s("syntax extensions"),e(o)]),s(" via markdown-it plugins.")]),T,n("p",null,[s("You can also configure those built-in extensions, load more markdown-it plugins and implement your own extensions via "),e(t,{to:"/reference/config.html#markdown"},{default:a(()=>[s("markdown")]),_:1}),s(" option and "),e(t,{to:"/reference/plugin-api.html#extendsmarkdown"},{default:a(()=>[s("extendsMarkdown")]),_:1}),s(" option.")]),C,q,n("ul",null,[n("li",null,[n("a",j,[s("Tables"),e(o)]),s(" (GFM)")]),n("li",null,[n("a",M,[s("Strikethrough"),e(o)]),s(" (GFM)")])]),L,R,n("div",V,[E,n("p",null,[s("This header anchors extension is supported by "),n("a",H,[s("markdown-it-anchor"),e(o)]),s(".")]),n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-anchor"},{default:a(()=>[s("markdown.anchor")]),_:1})])]),I,n("p",null,[s("When using Markdown "),n("a",S,[s("link syntax"),e(o)]),s(", VuePress will implement some conversions for you.")]),O,n("p",null,[e(t,{to:"/"},{default:a(()=>[s("Home")]),_:1}),B,e(t,{to:"/reference/config.html"},{default:a(()=>[s("Config Reference")]),_:1}),P,e(t,{to:"/guide/getting-started.html"},{default:a(()=>[s("Getting Started")]),_:1}),N,e(t,{to:"/guide/"},{default:a(()=>[s("Guide")]),_:1}),D,e(t,{to:"/reference/config.html#links"},{default:a(()=>[s("Config Reference > markdown.links")]),_:1}),G,n("a",U,[s("GitHub"),e(o)])]),Y,n("ul",null,[A,n("li",null,[s("Internal links to "),F,s(" files will be converted to the "),e(t,{to:"/guide/page.html#routing"},{default:a(()=>[s("page route path")]),_:1}),s(", and both absolute path and relative path are supported.")]),W]),z,J,X,n("div",Z,[$,K,n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-links"},{default:a(()=>[s("markdown.links")]),_:1})])]),Q,nn,n("p",null,[s("For a full list of available emoji and codes, check out "),n("a",sn,[s("emoji-cheat-sheet"),e(o)]),s(".")]),en,an,tn,on,n("div",ln,[pn,n("p",null,[s("This emoji extension is supported by "),n("a",cn,[s("markdown-it-emoji"),e(o)]),s(".")]),n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-emoji"},{default:a(()=>[s("markdown.emoji")]),_:1})])]),rn,n("nav",dn,[n("ul",null,[n("li",null,[e(l,{to:"#syntax-extensions"},{default:a(()=>[s("Syntax Extensions")]),_:1}),n("ul",null,[n("li",null,[e(l,{to:"#embedded"},{default:a(()=>[s("Embedded")]),_:1})]),n("li",null,[e(l,{to:"#header-anchors"},{default:a(()=>[s("Header Anchors")]),_:1})]),n("li",null,[e(l,{to:"#links"},{default:a(()=>[s("Links")]),_:1})]),n("li",null,[e(l,{to:"#emoji"},{default:a(()=>[s("Emoji 🎉")]),_:1})]),n("li",null,[e(l,{to:"#table-of-contents"},{default:a(()=>[s("Table of Contents")]),_:1})]),n("li",null,[e(l,{to:"#code-blocks"},{default:a(()=>[s("Code Blocks")]),_:1})]),n("li",null,[e(l,{to:"#import-code-blocks"},{default:a(()=>[s("Import Code Blocks")]),_:1})])])]),n("li",null,[e(l,{to:"#using-vue-in-markdown"},{default:a(()=>[s("Using Vue in Markdown")]),_:1}),n("ul",null,[n("li",null,[e(l,{to:"#template-syntax"},{default:a(()=>[s("Template Syntax")]),_:1})]),n("li",null,[e(l,{to:"#components"},{default:a(()=>[s("Components")]),_:1})])])]),n("li",null,[e(l,{to:"#cautions"},{default:a(()=>[s("Cautions")]),_:1}),n("ul",null,[n("li",null,[e(l,{to:"#non-standard-html-tags"},{default:a(()=>[s("Non-Standard HTML Tags")]),_:1})])])])])]),un,n("div",mn,[kn,n("p",null,[s("This toc extension is supported by "),n("a",hn,[s("@mdit-vue/plugin-toc"),e(o)]),s(".")]),n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-toc"},{default:a(()=>[s("markdown.toc")]),_:1})])]),gn,n("div",vn,[bn,n("p",null,[s("This line highlighting extension is supported by our built-in plugin, which is forked and modified from "),n("a",fn,[s("markdown-it-highlight-lines"),e(o)]),s(".")]),n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-code-highlightlines"},{default:a(()=>[s("markdown.code.highlightLines")]),_:1})])]),_n,n("div",wn,[yn,xn,n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-code-linenumbers"},{default:a(()=>[s("markdown.code.lineNumbers")]),_:1})])]),Tn,Cn,n("p",null,[s("To avoid your code blocks being compiled by Vue, VuePress will add "),n("a",qn,[s("v-pre"),e(o)]),s(" directive to your code blocks by default, which can be disabled in config.")]),jn,k(` +using :no-v-pre on JS code blocks has potential issue with shiki, so we are +not actually using :no-v-pre here, just as an example of incorrect usage +`),Mn,n("div",Ln,[Rn,Vn,n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-code-vpre-block"},{default:a(()=>[s("markdown.code.vPre.block")]),_:1})])]),En,n("div",Hn,[In,Sn,n("p",null,[s("Config reference: "),e(t,{to:"/reference/config.html#markdown-importcode"},{default:a(()=>[s("markdown.importCode")]),_:1})])]),On,Bn,n("p",null,[s("Check out "),e(t,{to:"/advanced/cookbook/markdown-and-vue-sfc.html"},{default:a(()=>[s("Cookbook > Markdown and Vue SFC")]),_:1}),s(" for more details.")]),Pn,Nn,Dn,n("p",null,[s("That means, "),n("a",Gn,[s("Vue template syntax"),e(o)]),s(" is allowed in Markdown.")]),Un,n("p",null,[(c(),r(h,null,g(3,u=>n("span",null," span: "+v(u),1)),64))]),Yn,n("p",null,[s("This is default theme built-in "),An,s(" component "),e(d,{text:"demo"})]),n("div",Fn,[Wn,n("p",null,[s("Check out the "),e(t,{to:"/reference/components.html"},{default:a(()=>[s("Built-in Components")]),_:1}),s(" for a full list of built-in components.")]),n("p",null,[s("Check out the "),e(t,{to:"/reference/default-theme/components.html"},{default:a(()=>[s("Default Theme > Built-in Components")]),_:1}),s(" for a full list of default theme built-in components.")])]),zn,Jn,Xn,n("ul",null,[n("li",null,[s("Deprecated HTML tags such as "),n("a",Zn,[s(" "),e(o)]),s(" and "),n("a",$n,[s(""),e(o)]),s(".")]),n("li",null,[n("a",Kn,[s("MathML tags"),e(o)]),s(", which might be used by some markdown-it LaTeX plugin.")])]),Qn,n("ul",null,[n("li",null,[s("Adding a "),n("a",ns,[s("v-pre"),e(o)]),s(" directive to skip the compilation of the element and its children. Notice that the template syntax would also be invalid.")]),n("li",null,[s("Using "),n("a",ss,[s("compilerOptions.isCustomElement"),e(o)]),s(" to tell Vue template compiler not try to resolve them as components. "),n("ul",null,[n("li",null,[s("For "),es,s(", set "),e(t,{to:"/reference/bundler/webpack.html#vue"},{default:a(()=>[s("vue.compilerOptions")]),_:1})]),n("li",null,[s("For "),as,s(", set "),e(t,{to:"/reference/bundler/vite.html#vuepluginoptions"},{default:a(()=>[s("vuePluginOptions.template.compilerOptions")]),_:1})])])])])])}const ps=m(b,[["render",ts],["__file","markdown.html.vue"]]);export{ps as default}; diff --git a/assets/markdown.html-daca0316.js b/assets/markdown.html-daca0316.js new file mode 100644 index 00000000..efad1b81 --- /dev/null +++ b/assets/markdown.html-daca0316.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0978b044","path":"/guide/markdown.html","title":"Markdown","lang":"en-US","frontmatter":{"icon":"fa6-brands:markdown","description":"Make sure you already know Markdown well before reading this section. If not, please learn some Markdown tutorials (https://commonmark.org/help/) first. Syntax Extensions The Ma...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/markdown.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/markdown.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Markdown"}],["meta",{"property":"og:description","content":"Make sure you already know Markdown well before reading this section. If not, please learn some Markdown tutorials (https://commonmark.org/help/) first. Syntax Extensions The Ma..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Markdown\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Syntax Extensions","slug":"syntax-extensions","link":"#syntax-extensions","children":[{"level":3,"title":"Embedded","slug":"embedded","link":"#embedded","children":[]},{"level":3,"title":"Header Anchors","slug":"header-anchors","link":"#header-anchors","children":[]},{"level":3,"title":"Links","slug":"links","link":"#links","children":[]},{"level":3,"title":"Emoji 🎉","slug":"emoji","link":"#emoji","children":[]},{"level":3,"title":"Table of Contents","slug":"table-of-contents","link":"#table-of-contents","children":[]},{"level":3,"title":"Code Blocks","slug":"code-blocks","link":"#code-blocks","children":[]},{"level":3,"title":"Import Code Blocks","slug":"import-code-blocks","link":"#import-code-blocks","children":[]}]},{"level":2,"title":"Using Vue in Markdown","slug":"using-vue-in-markdown","link":"#using-vue-in-markdown","children":[{"level":3,"title":"Template Syntax","slug":"template-syntax","link":"#template-syntax","children":[]},{"level":3,"title":"Components","slug":"components","link":"#components","children":[]}]},{"level":2,"title":"Cautions","slug":"cautions","link":"#cautions","children":[{"level":3,"title":"Non-Standard HTML Tags","slug":"non-standard-html-tags","link":"#non-standard-html-tags","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":6.08,"words":1825},"filePathRelative":"guide/markdown.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/markdown.html-f0b871b8.js b/assets/markdown.html-f0b871b8.js new file mode 100644 index 00000000..48019c88 --- /dev/null +++ b/assets/markdown.html-f0b871b8.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6a0a3d62","path":"/zh/guide/markdown.html","title":"Markdown","lang":"zh-CN","frontmatter":{"icon":"fa6-brands:markdown","description":"在阅读本章节之前,请确保你已经对 Markdown 有所了解。如果你还不了解 Markdown ,请先学习一些 Markdown 教程 (https://commonmark.org/help/)。 语法扩展 VuePress 会使用 markdown-it (https://github.com/markdown-it/markdown-it) 来解...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/markdown.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/markdown.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Markdown"}],["meta",{"property":"og:description","content":"在阅读本章节之前,请确保你已经对 Markdown 有所了解。如果你还不了解 Markdown ,请先学习一些 Markdown 教程 (https://commonmark.org/help/)。 语法扩展 VuePress 会使用 markdown-it (https://github.com/markdown-it/markdown-it) 来解..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Markdown\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"语法扩展","slug":"语法扩展","link":"#语法扩展","children":[{"level":3,"title":"内置","slug":"内置","link":"#内置","children":[]},{"level":3,"title":"标题锚点","slug":"标题锚点","link":"#标题锚点","children":[]},{"level":3,"title":"链接","slug":"链接","link":"#链接","children":[]},{"level":3,"title":"Emoji 🎉","slug":"emoji","link":"#emoji","children":[]},{"level":3,"title":"目录","slug":"目录","link":"#目录","children":[]},{"level":3,"title":"代码块","slug":"代码块","link":"#代码块","children":[]},{"level":3,"title":"导入代码块","slug":"导入代码块","link":"#导入代码块","children":[]}]},{"level":2,"title":"在 Markdown 中使用 Vue","slug":"在-markdown-中使用-vue","link":"#在-markdown-中使用-vue","children":[{"level":3,"title":"模板语法","slug":"模板语法","link":"#模板语法","children":[]},{"level":3,"title":"组件","slug":"组件","link":"#组件","children":[]}]},{"level":2,"title":"注意事项","slug":"注意事项","link":"#注意事项","children":[{"level":3,"title":"非标准的 HTML 标签","slug":"非标准的-html-标签","link":"#非标准的-html-标签","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":8.43,"words":2530},"filePathRelative":"zh/guide/markdown.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/markdown.html-f26fa0b6.js b/assets/markdown.html-f26fa0b6.js new file mode 100644 index 00000000..c479605b --- /dev/null +++ b/assets/markdown.html-f26fa0b6.js @@ -0,0 +1,59 @@ +import{_ as p,W as v,X as m,Y as e,$ as n,Z as a,a0 as s,a1 as t,D as i}from"./framework-46b0e263.js";const b={},g=n("h1",{id:"markdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown","aria-hidden":"true"},"#"),s(" Markdown")],-1),k=n("h2",{id:"自定义容器",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#自定义容器","aria-hidden":"true"},"#"),s(" 自定义容器")],-1),h=t(` 使用:
::: <type> [title] +[content] +::: +
type
是必需的,title
和content
是可选的。支持的
`,4),_=n("li",null,[n("code",null,"tip")],-1),f=n("li",null,[n("code",null,"warning")],-1),w=n("li",null,[n("code",null,"danger")],-1),y=n("li",null,[n("code",null,"details")],-1),x=n("ul",null,[n("li",null,[n("code",null,"code-group")]),n("li",null,[n("code",null,"code-group-item")])],-1),q=n("li",null,[n("p",null,"示例 1 (默认标题):")],-1),B=t(`type
有:输入
::: tip + +这是一个提示 + +::: + +::: warning + +这是一个警告 + +::: + +::: danger + +这是一个危险警告 + +::: + +::: details +这是一个 details 标签 + +::: +
输出
提示
这是一个提示
注意
这是一个警告
警告
这是一个危险警告
详情
这是一个 details 标签
- 示例 2 (自定义标题):
输入
::: danger STOP +危险区域,禁止通行 + +::: + +::: details 点击查看代码 + +\`\`\`ts +console.log("你好,VuePress!"); +\`\`\` + +::: +
输出
STOP
危险区域,禁止通行
点击查看代码
console.log("你好,VuePress!"); +
- 示例 3 (Code Group 别名):
输入
:::: code-group +::: code-group-item FOO + +\`\`\`ts +const foo = "foo"; +\`\`\` + +::: + +::: code-group-item BAR + +\`\`\`ts +const bar = "bar"; +\`\`\` + +::: + +:::: +
输出
`,17),C=n("div",{class:"language-typescript line-numbers-mode","data-ext":"ts"},[n("pre",{class:"language-typescript"},[n("code",null,[n("span",{class:"token keyword"},"const"),s(" foo "),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"foo"'),n("span",{class:"token punctuation"},";"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])],-1),N=n("div",{class:"language-typescript line-numbers-mode","data-ext":"ts"},[n("pre",{class:"language-typescript"},[n("code",null,[n("span",{class:"token keyword"},"const"),s(" bar "),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"bar"'),n("span",{class:"token punctuation"},";"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])],-1);function O(V,T){const d=i("NpmBadge"),l=i("RouterLink"),c=i("CodeTabs");return v(),m("div",null,[g,e(d,{package:"@vuepress/theme-default"}),k,n("ul",null,[n("li",null,[h,n("ul",null,[_,f,w,y,n("li",null,[e(l,{to:"/zh/reference/default-theme/components.html#codegroup"},{default:a(()=>[s("CodeGroup")]),_:1}),s(" 和 "),e(l,{to:"/zh/reference/default-theme/components.html#codegroupitem"},{default:a(()=>[s("CodeGroupItem")]),_:1}),s(" 的别名: "),x])])]),q]),B,e(c,{id:"129",data:[{title:"FOO"},{title:"BAR"}]},{tab0:a(({title:o,value:r,isActive:u})=>[C]),tab1:a(({title:o,value:r,isActive:u})=>[N]),_:1})])}const P=p(b,[["render",O],["__file","markdown.html.vue"]]);export{P as default}; diff --git a/assets/medium-zoom.html-7c5262ed.js b/assets/medium-zoom.html-7c5262ed.js new file mode 100644 index 00000000..9181e18d --- /dev/null +++ b/assets/medium-zoom.html-7c5262ed.js @@ -0,0 +1,26 @@ +import{_ as p,W as l,X as c,Y as a,$ as n,a0 as s,a1 as o,D as t}from"./framework-46b0e263.js";const u={},d=n("h1",{id:"medium-zoom",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#medium-zoom","aria-hidden":"true"},"#"),s(" medium-zoom")],-1),r={href:"https://github.com/francoischalifour/medium-zoom#readme",target:"_blank",rel:"noopener noreferrer"},m=o(`该插件已经集成到默认主题中。
# 使用方法
npm i -D @vuepress/plugin-medium-zoom@next +
import { mediumZoomPlugin } from "@vuepress/plugin-medium-zoom"; + +export default { + plugins: [ + mediumZoomPlugin({ + // 配置项 + }), + ], +}; +
# 配置项
# selector
类型:
string
默认值:
':not(a) > img'
详情:
可缩放的图片的选择器。
默认情况下,该插件会使
<a>
标签以外的所有图片都支持缩放。# delay
类型:
number
默认值:
500
详情:
以毫秒为单位的延迟。
在切换路由进入一个新页面时,该插件会在一定延迟后才使页面内的图片支持缩放。
# zoomOptions
`,10),h=n("li",null,[n("p",null,[s("类型: "),n("code",null,"Object")])],-1),k=n("li",null,[n("p",null,"详情:"),n("p",null,"medium-zoom 的配置项。")],-1),v=n("p",null,"参考:",-1),b={href:"https://github.com/francoischalifour/medium-zoom#options",target:"_blank",rel:"noopener noreferrer"},_=o('# 样式
你可以通过 zoomOptions 对大部分的缩放样式进行自定义,不过作为补充,该插件同样提供了一些 CSS 变量:
File not found
# Composition API
# useMediumZoom
',5),f=n("p",null,"详情:",-1),g=n("code",null,"Zoom",-1),z={href:"https://github.com/francoischalifour/medium-zoom#methods",target:"_blank",rel:"noopener noreferrer"},x=n("p",null,"该插件会在切换路由进入当前页面时使图片支持缩放。但如果你要动态添加新图片,那么你可能就需要这个方法来让这些新图片也支持缩放。",-1),y=n("p",null,[s("该插件在 "),n("code",null,"Zoom"),s(" 实例上额外添加了一个 "),n("code",null,"refresh"),s(" 方法,它将使用 "),n("a",{href:"#selector"},"selector"),s(" 作为默认参数,先调用 "),n("code",null,"zoom.detach()"),s(" 再调用 "),n("code",null,"zoom.attach()"),s(" ,便于你快速刷新当前页面图片的缩放状态。")],-1),w=n("li",null,[n("p",null,"示例:")],-1),Z=o(``,1);function q(N,B){const i=t("NpmBadge"),e=t("ExternalLinkIcon");return l(),c("div",null,[d,a(i,{package:"@vuepress/plugin-medium-zoom"}),n("p",null,[s("将 "),n("a",r,[s("medium-zoom"),a(e)]),s(" 集成到 VuePress 中,为图片提供可缩放的功能。")]),m,n("ul",null,[h,k,n("li",null,[v,n("ul",null,[n("li",null,[n("a",b,[s("medium-zoom > Options"),a(e)])])])])]),_,n("ul",null,[n("li",null,[f,n("p",null,[s("返回该插件使用的 "),g,s(" 实例,便于你直接使用实例上的 "),n("a",z,[s("methods"),a(e)]),s(" 。")]),x,y]),w]),Z])}const O=p(u,[["render",q],["__file","medium-zoom.html.vue"]]);export{O as default}; diff --git a/assets/medium-zoom.html-926244f2.js b/assets/medium-zoom.html-926244f2.js new file mode 100644 index 00000000..3eac8909 --- /dev/null +++ b/assets/medium-zoom.html-926244f2.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2ad6454d","path":"/reference/plugin/medium-zoom.html","title":"medium-zoom","lang":"en-US","frontmatter":{"description":"Integrate medium-zoom (https://github.com/francoischalifour/medium-zoom#readme) into VuePress, which can provide the ability to zoom images. This plugin has been integrated into...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/medium-zoom.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/medium-zoom.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"medium-zoom"}],["meta",{"property":"og:description","content":"Integrate medium-zoom (https://github.com/francoischalifour/medium-zoom#readme) into VuePress, which can provide the ability to zoom images. This plugin has been integrated into..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"medium-zoom\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"selector","slug":"selector","link":"#selector","children":[]},{"level":3,"title":"delay","slug":"delay","link":"#delay","children":[]},{"level":3,"title":"zoomOptions","slug":"zoomoptions","link":"#zoomoptions","children":[]}]},{"level":2,"title":"Styles","slug":"styles","link":"#styles","children":[]},{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"useMediumZoom","slug":"usemediumzoom","link":"#usemediumzoom","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.03,"words":310},"filePathRelative":"reference/plugin/medium-zoom.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/medium-zoom.html-b884d404.js b/assets/medium-zoom.html-b884d404.js new file mode 100644 index 00000000..5ceda26d --- /dev/null +++ b/assets/medium-zoom.html-b884d404.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-32cfa4fe","path":"/zh/reference/plugin/medium-zoom.html","title":"medium-zoom","lang":"zh-CN","frontmatter":{"description":"将 medium-zoom (https://github.com/francoischalifour/medium-zoom#readme) 集成到 VuePress 中,为图片提供可缩放的功能。 该插件已经集成到默认主题中。 使用方法 配置项 selector 类型: string; 默认值: ':not(a) > img'; 详情:; 可缩放的图...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/medium-zoom.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/medium-zoom.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"medium-zoom"}],["meta",{"property":"og:description","content":"将 medium-zoom (https://github.com/francoischalifour/medium-zoom#readme) 集成到 VuePress 中,为图片提供可缩放的功能。 该插件已经集成到默认主题中。 使用方法 配置项 selector 类型: string; 默认值: ':not(a) > img'; 详情:; 可缩放的图..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"medium-zoom\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"selector","slug":"selector","link":"#selector","children":[]},{"level":3,"title":"delay","slug":"delay","link":"#delay","children":[]},{"level":3,"title":"zoomOptions","slug":"zoomoptions","link":"#zoomoptions","children":[]}]},{"level":2,"title":"样式","slug":"样式","link":"#样式","children":[]},{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"useMediumZoom","slug":"usemediumzoom","link":"#usemediumzoom","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.57,"words":471},"filePathRelative":"zh/reference/plugin/medium-zoom.md","localizedDate":"2023年2月22日","autoDesc":true}`);export{e as data}; diff --git a/assets/medium-zoom.html-bf739c54.js b/assets/medium-zoom.html-bf739c54.js new file mode 100644 index 00000000..30488b67 --- /dev/null +++ b/assets/medium-zoom.html-bf739c54.js @@ -0,0 +1,26 @@ +import{_ as l,W as p,X as c,Y as a,$ as n,a0 as s,a1 as o,D as t}from"./framework-46b0e263.js";const u={},d=n("h1",{id:"medium-zoom",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#medium-zoom","aria-hidden":"true"},"#"),s(" medium-zoom")],-1),r={href:"https://github.com/francoischalifour/medium-zoom#readme",target:"_blank",rel:"noopener noreferrer"},m=o(`import { nextTick } from "vue"; +import { useMediumZoom } from "@vuepress/plugin-medium-zoom/client"; + +export default { + setup() { + const zoom = useMediumZoom(); + + // ... 进行了一些操作,在当前页面添加了新的图片 + + // 此时你可能需要手动调用 \`refresh\` 来让这些新图片支持缩放 + nextTick(() => { + zoom.refresh(); + }); + }, +}; +
This plugin has been integrated into the default theme.
# Usage
npm i -D @vuepress/plugin-medium-zoom@next +
import { mediumZoomPlugin } from "@vuepress/plugin-medium-zoom"; + +export default { + plugins: [ + mediumZoomPlugin({ + // options + }), + ], +}; +
# Options
# selector
Type:
string
Default:
':not(a) > img'
Details:
Selector of zoomable images.
By default this plugin will make all images zoomable except those inside
<a>
tags.# delay
Type:
number
Default:
500
Details:
Delay in milliseconds.
After navigating to a new page, this plugin will make images zoomable with a delay.
# zoomOptions
`,10),h=n("li",null,[n("p",null,[s("Type: "),n("code",null,"Object")])],-1),k=n("li",null,[n("p",null,"Details:"),n("p",null,"Options for medium-zoom.")],-1),v=n("p",null,"Also see:",-1),g={href:"https://github.com/francoischalifour/medium-zoom#options",target:"_blank",rel:"noopener noreferrer"},b=o('# Styles
You can customize most of the zoom styles via zoomOptions, while this plugin also provides some CSS variables for additional customization:
File not found
# Composition API
# useMediumZoom
',5),f=n("p",null,"Details:",-1),_=n("code",null,"Zoom",-1),y={href:"https://github.com/francoischalifour/medium-zoom#methods",target:"_blank",rel:"noopener noreferrer"},z=n("p",null,"This plugin will make images zoomable after navigating to current page. But if you are going to add new images dynamically, you may need this method to make those new images zoomable, too.",-1),x=n("p",null,[s("This plugin adds an extra "),n("code",null,"refresh"),s(" method on the "),n("code",null,"Zoom"),s(" instance, which will call "),n("code",null,"zoom.detach()"),s(" then "),n("code",null,"zoom.attach()"),s(" with the "),n("a",{href:"#selector"},"selector"),s(" as the default parameter. It will help you to refresh the zoomable images for current page.")],-1),w=n("li",null,[n("p",null,"Example:")],-1),D=o(``,1);function T(Z,B){const i=t("NpmBadge"),e=t("ExternalLinkIcon");return p(),c("div",null,[d,a(i,{package:"@vuepress/plugin-medium-zoom"}),n("p",null,[s("Integrate "),n("a",r,[s("medium-zoom"),a(e)]),s(" into VuePress, which can provide the ability to zoom images.")]),m,n("ul",null,[h,k,n("li",null,[v,n("ul",null,[n("li",null,[n("a",g,[s("medium-zoom > Options"),a(e)])])])])]),b,n("ul",null,[n("li",null,[f,n("p",null,[s("Returns the "),_,s(" instance that used by this plugin, so that you can use the instance "),n("a",y,[s("methods"),a(e)]),s(" directly.")]),z,x]),w]),D])}const N=l(u,[["render",T],["__file","medium-zoom.html.vue"]]);export{N as default}; diff --git a/assets/migration.html-2aa2394a.js b/assets/migration.html-2aa2394a.js new file mode 100644 index 00000000..ecfe6817 --- /dev/null +++ b/assets/migration.html-2aa2394a.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-d0112c92","path":"/guide/migration.html","title":"Migrating from v1","lang":"en-US","frontmatter":{"icon":"fa6-solid:code-compare","description":"Plugins and themes of VuePress v1 are not compatible with VuePress v2. You need to update them to corresponding v2 version. Some major changes and enhancements of VuePress v2: V...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/migration.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/migration.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Migrating from v1"}],["meta",{"property":"og:description","content":"Plugins and themes of VuePress v1 are not compatible with VuePress v2. You need to update them to corresponding v2 version. Some major changes and enhancements of VuePress v2: V..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Migrating from v1\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"For Users","slug":"for-users","link":"#for-users","children":[{"level":3,"title":"User Config Change","slug":"user-config-change","link":"#user-config-change","children":[]},{"level":3,"title":"Frontmatter Change","slug":"frontmatter-change","link":"#frontmatter-change","children":[]},{"level":3,"title":"Permalink Patterns Change","slug":"permalink-patterns-change","link":"#permalink-patterns-change","children":[]},{"level":3,"title":"Palette System Change","slug":"palette-system-change","link":"#palette-system-change","children":[]},{"level":3,"title":"Conventional Files Change","slug":"conventional-files-change","link":"#conventional-files-change","children":[]},{"level":3,"title":"Markdown slot Change","slug":"markdown-slot-change","link":"#markdown-slot-change","children":[]},{"level":3,"title":"CLI Change","slug":"cli-change","link":"#cli-change","children":[]},{"level":3,"title":"Default Theme Change","slug":"default-theme-change","link":"#default-theme-change","children":[]},{"level":3,"title":"Official Plugins Change","slug":"official-plugins-change","link":"#official-plugins-change","children":[]},{"level":3,"title":"Community Themes and Plugins","slug":"community-themes-and-plugins","link":"#community-themes-and-plugins","children":[]}]},{"level":2,"title":"For Plugin Authors","slug":"for-plugin-authors","link":"#for-plugin-authors","children":[{"level":3,"title":"Plugin API Change","slug":"plugin-api-change","link":"#plugin-api-change","children":[]}]},{"level":2,"title":"For Theme Authors","slug":"for-theme-authors","link":"#for-theme-authors","children":[{"level":3,"title":"Theme API Change","slug":"theme-api-change","link":"#theme-api-change","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":5.52,"words":1657},"filePathRelative":"guide/migration.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/migration.html-41dd8c51.js b/assets/migration.html-41dd8c51.js new file mode 100644 index 00000000..bc1d190a --- /dev/null +++ b/assets/migration.html-41dd8c51.js @@ -0,0 +1,72 @@ +import{_ as i,W as d,X as o,$ as n,a0 as e,Y as a,Z as t,a1 as l,D as c}from"./framework-46b0e263.js";const r={},p=l(`import { nextTick } from "vue"; +import { useMediumZoom } from "@vuepress/plugin-medium-zoom/client"; + +export default { + setup() { + const zoom = useMediumZoom(); + + // ... do something to add new images in current page + + // then you may need to call \`refresh\` manually to make those new images zoomable + nextTick(() => { + zoom.refresh(); + }); + }, +}; +
# 从 v1 迁移
注意
VuePress v1 的插件和主题与 VuePress v2 不兼容。你需要将它们升级到与 v2 对应的版本。
VuePress v2 的一些主要改动和优化:
- VuePress v2 现在使用 Vue 3 ,因此你要保证你的组件和其他客户端文件是适用于 Vue 3 的。
- VuePress v2 是使用 TypeScript 开发的,因此它现在提供了更好的类型支持。我们强烈推荐你使用 TypeScript 来开发插件和主题。 VuePress 配置文件也同样支持 TypeScript ,你可以直接使用
.vuepress/config.ts
。- VuePress v2 支持使用 Webpack 和 Vite 作为打包工具。现在默认的打包工具是 Vite ,但你仍然可以选择使用 Webpack 。你甚至可以在开发模式使用 Vite 来获取更好的开发体验,而在构建模式使用 Webpack 来获取更好的浏览器兼容性。
- VuePress v2 现在是纯 ESM 包, CommonJS 格式的配置文件不再被支持。
VuePress v2 的核心思想和流程是和 v1 一致的,但 v2 API 经过了重新设计,更加标准化。因此在将现有的 v1 项目迁移至 v2 时,你很可能会遇到一些 Breaking Changes 。本指南将帮助你将 v1 的站点 / 插件 / 主题迁移至 v2 。
# 给用户
# 用户配置变更
配置文件应该使用 ESM 格式, CommonJS 格式的配置文件已不再支持。
// .vuepress/config.js + +- module.exports = { +- // 用户配置 +- } + ++ export default { ++ // 用户配置 ++ } +
# theme
不再支持通过字符串使用主题。需要直接引入主题。
- module.exports = { +- theme: '@vuepress/theme-default', +- themeConfig: { +- // 默认主题配置 +- }, +- } + ++ import { defaultTheme } from 'vuepress' ++ export default { ++ theme: defaultTheme({ ++ // 默认主题配置 ++ }) ++ } +
# themeConfig
移除。直接向主题传入配置。
# plugins
不再支持通过字符串使用插件。需要直接引入插件。
- module.exports = { +- plugins: [ +- [ +- '@vuepress/plugin-google-analytics', +- { +- id: 'G-XXXXXXXXXX', +- }, +- ], +- ], +- } + ++ import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' ++ export default { ++ plugins: [ ++ googleAnalyticsPlugin({ ++ id: 'G-XXXXXXXXXX', ++ }), ++ ], ++ } +
# shouldPrefetch
默认值从
() => true
更改为true
。# extraWatchFiles
移除。
`,22),u=n("h4",{id:"patterns",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#patterns","aria-hidden":"true"},"#"),e(" patterns")],-1),h=n("p",null,[e("重命名为 "),n("code",null,"pagePatterns"),e(" 。")],-1),k=n("h4",{id:"markdown-linenumbers",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-linenumbers","aria-hidden":"true"},"#"),e(" markdown.lineNumbers")],-1),m=n("p",null,[e("默认值从 "),n("code",null,"false"),e(" 更改为 "),n("code",null,"true"),e(" 。")],-1),f=n("h4",{id:"markdown-pagesuffix",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-pagesuffix","aria-hidden":"true"},"#"),e(" markdown.pageSuffix")],-1),v=n("p",null,"移除。",-1),_=n("h4",{id:"markdown-externallinks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-externallinks","aria-hidden":"true"},"#"),e(" markdown.externalLinks")],-1),b=n("h4",{id:"markdown-toc",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-toc","aria-hidden":"true"},"#"),e(" markdown.toc")],-1),g=n("p",null,"有改动。",-1),x=n("h4",{id:"markdown-plugins",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-plugins","aria-hidden":"true"},"#"),e(" markdown.plugins")],-1),w=n("p",null,"移除。",-1),y=n("h4",{id:"markdown-extendmarkdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-extendmarkdown","aria-hidden":"true"},"#"),e(" markdown.extendMarkdown")],-1),C=n("p",null,"移除。",-1),B=n("h4",{id:"markdown-extractheaders",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-extractheaders","aria-hidden":"true"},"#"),e(" markdown.extractHeaders")],-1),P=l(`# Webpack 相关配置
所有 Webpack 相关的配置都移动至
@vuepress/bundler-webpack
的配置项中,包括:
postcss
stylus
scss
sass
less
chainWebpack
configureWebpack
evergreen
:默认值从false
更改为true
`,4),z=n("h3",{id:"frontmatter-变更",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#frontmatter-变更","aria-hidden":"true"},"#"),e(" Frontmatter 变更")],-1),S=n("h4",{id:"meta",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#meta","aria-hidden":"true"},"#"),e(" meta")],-1),E=n("p",null,"移除。",-1),V=l(`- module.exports = { +- sass: { /* ... */ }, +- } + ++ import { webpackBundler } from '@vuepress/bundler-webpack' ++ export default { ++ bundler: webpackBundler({ ++ sass: { /* ... */ }, ++ }), ++ } +
head: + - - meta + - name: foo + content: bar + - - link + - rel: canonical + href: foobar + - - script + - {} + - console.log('hello from frontmatter'); +
和以下结构相同:
// .vuepress/config.ts +export default { + // ... + head: [ + ["meta", { name: "foo", content: "bar" }], + ["link", { rel: "canonical", href: "foobar" }], + ["script", {}, \`console.log('hello from frontmatter');\`], + ], + // ... +}; +
# 永久链接 Patterns 变更
`,5),X=n("h3",{id:"调色板系统变更",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#调色板系统变更","aria-hidden":"true"},"#"),e(" 调色板系统变更")],-1),A=n("p",null,[e("VuePress v1 的 Stylus 调色板系统 (即 "),n("code",null,"styles/palette.styl"),e(" 和 "),n("code",null,"styles/index.styl"),e(") 不再由 VuePress Core 默认提供支持。")],-1),q=n("p",null,"主题作者可以使用自己的方式来为用户提供自定义样式的能力,而不必被限制在 Stylus 当中。",-1),W=n("h3",{id:"约定文件变更",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#约定文件变更","aria-hidden":"true"},"#"),e(" 约定文件变更")],-1),F=n("h4",{id:"vuepress-enhanceapp-js",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepress-enhanceapp-js","aria-hidden":"true"},"#"),e(" .vuepress/enhanceApp.js")],-1),H=n("p",null,[e("重命名为 "),n("code",null,".vuepress/client.{js,ts}"),e(" ,使用方法也有改动。")],-1),j=n("h4",{id:"vuepress-components",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepress-components","aria-hidden":"true"},"#"),e(" .vuepress/components/")],-1),M=n("p",null,"在该目录下的文件不会被自动注册为 Vue 组件。",-1),I=n("code",null,".vuepress/client.{js,ts}",-1),D=n("h4",{id:"vuepress-theme",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepress-theme","aria-hidden":"true"},"#"),e(" .vuepress/theme/")],-1),T=n("p",null,"即使该目录存在,也不会被隐式默认当作本地主题目录。",-1),G=l('
:i_month
:移除:i_day
:移除:minutes
:移除(v1 文档中未列出):seconds
:移除(v1 文档中未列出):regular
:重命名为:raw
# Markdown 插槽变更
Markdown 插槽不再被支持。
# CLI 变更
# eject 命令
移除。
# cache 选项
-c, --cache [cache]
:修改为--cache <cache>
,意味着-c
不再是cache
选项的缩写,并且cache
选项的值不再是可选的。--no-cache
:重命名为--clean-cache
。# 默认主题变更
# 内置组件
<CodeGroup />
和<CodeBlock />
重命名为<CodeGroup />
和<CodeGroupItem />
<Badge />
$badgeErrorColor
调色板变量重命名为$badgeDangerColor
type
Prop 现在只接受tip
、warning
和danger
# 调色板系统
默认主题的调色板系统迁移为 SASS 和 CSS 变量。
',12),N=n("h4",{id:"主题配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#主题配置","aria-hidden":"true"},"#"),e(" 主题配置")],-1),L=n("p",null,"默认主题的配置有大量变更,建议你阅读 v2 的默认主题配置参考文档来进行迁移。",-1),$=l('# 官方插件变更
查看 v2 版本的官方插件文档。
# 社区主题和插件
v1 的主题和插件和 v2 并不兼容。
请确保你在使用的主题和插件已经支持 v2 ,并前往它们各自的文档查看迁移指南。
# 给插件作者
一些主要的 Breaking Changes :
',7),J=n("li",null,"你不能再在你的插件中使用其他插件了,这避免了很多由于插件嵌套引发的问题。如果你的插件依赖于别的插件,你可以在文档中列出他们,并让用户手动引入。或者,你也可以向用户提供一个插件数组以方便使用。",-1),R=n("li",null,[e("大部分 v1 Hook 都在 v2 中存在等效的 Hook 或实现方式。唯一的例外是 "),n("code",null,"extendsCli"),e(" ,它被移除了。")],-1),O=l('# 插件 API 变更
',2),U=n("h2",{id:"给主题作者",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#给主题作者","aria-hidden":"true"},"#"),e(" 给主题作者")],-1),Y=n("p",null,[e("请先浏览 "),n("a",{href:"#%E6%8F%92%E4%BB%B6-api-%E5%8F%98%E6%9B%B4"},"插件 API 变更"),e(" 和 "),n("a",{href:"#%E4%B8%BB%E9%A2%98-api-%E5%8F%98%E6%9B%B4"},"主题 API 变更"),e("。")],-1),Z=n("p",null,"虽然我们不允许在插件中使用其他插件了,但是你仍然可以在你的主题中使用插件。",-1),K=n("p",null,"一些主要的 Breaking Changes :",-1),Q=n("strong",null,"主题目录结构约定",-1),ee=n("li",null,[n("code",null,"theme/enhanceApp.js"),e(" 文件不会被隐式作为 Client App Enhance 文件。你需要在 "),n("code",null,"clientConfigFile"),e(" Hook 中显式指定它。")],-1),ne=n("code",null,"theme/global-components/",-1),se=n("code",null,"clientConfigFile",-1),ae=l("
plugins
:移除ready
:重命名为onPrepared
updated
:重命名为onWatched
generated
:重命名为onGenerated
additionalPages
:移除,改为在onInitialized
Hook 中使用app.pages.push(createPage())
clientDynamicModules
:移除,改为在onPrepared
Hook 中使用app.writeTemp()
enhanceAppFiles
:移除,使用clientConfigFile
HookglobalUIComponents
:移除,使用clientConfigFile
HookclientRootMixin
:移除,使用clientConfigFile
HookextendMarkdown
:重命名为extendsMarkdown
chainMarkdown
:移除extendPageData
:重命名为extendsPage
extendsCli
:移除configureWebpack
:移除chainWebpack
:移除beforeDevServer
:移除afterDevServer
:移除theme/layouts/
目录下的文件不会被自动注册为布局组件。你需要在clientConfigFile
中通过layouts
来显式指定。theme/templates/
目录下的文件不会被自动用作 dev / ssr 的模板。你需要通过templateBuild
和templateDev
配置项来显式指定。你始终需要提供一个合法的 JS 入口文件,不要再使用 ",3),te=n("code",null,"themeConfig",-1),le=n("code",null,"this.$site.themeConfig",-1),ie=n("code",null,"themeConfig",-1),de=n("code",null,"useThemeData",-1),oe=n("li",null,[e("考虑到可扩展性, "),n("code",null,"this.$site.pages"),e(" 不再可用。")],-1),ce=n("h3",{id:"主题-api-变更",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#主题-api-变更","aria-hidden":"true"},"#"),e(" 主题 API 变更")],-1),re=n("h4",{id:"layouts",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#layouts","aria-hidden":"true"},"#"),e(" layouts")],-1),pe=n("p",null,"移除。",-1),ue=n("p",null,"现在你需要在客户端配置文件中设置布局组件。",-1),he=n("h4",{id:"extend",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#extend","aria-hidden":"true"},"#"),e(" extend")],-1),ke=n("p",null,[e("重命名为 "),n("code",null,"extends"),e(" 。")],-1),me=n("p",null,[e("你仍然可以通过 "),n("code",null,"extends: parentTheme()"),e(" 来继承一个父主题,这将会继承其插件和布局等。")],-1),fe=n("code",null,"@theme",-1),ve=n("code",null,"@parent-theme",-1);function _e(be,ge){const s=c("RouterLink");return d(),o("div",null,[p,n("p",null,[e("你可以手动在 "),a(s,{to:"/zh/reference/plugin-api.html#onwatched"},{default:t(()=>[e("onWatched")]),_:1}),e(" Hook 中监听文件变化。")]),u,h,k,n("p",null,[e("移动至 "),a(s,{to:"/zh/reference/config.html#markdown-code-linenumbers"},{default:t(()=>[e("markdown.code.lineNumbers")]),_:1}),e(" 。")]),m,f,v,_,n("p",null,[e("移动至 "),a(s,{to:"/zh/reference/config.html#markdown-links"},{default:t(()=>[e("markdown.links.externalAttrs")]),_:1}),e(" 。")]),b,g,n("p",null,[e("参考 "),a(s,{to:"/zh/reference/config.html#markdown-toc"},{default:t(()=>[e("配置 > markdown.toc")]),_:1})]),x,w,n("p",null,[e("在 "),a(s,{to:"/zh/reference/plugin-api.html#extendsmarkdown"},{default:t(()=>[e("extendsMarkdown")]),_:1}),e(" Hook 中使用 markdown-it 插件。")]),y,C,n("p",null,[e("使用 "),a(s,{to:"/zh/reference/plugin-api.html#extendsmarkdown"},{default:t(()=>[e("extendsMarkdown")]),_:1}),e(" Hook 。")]),B,n("p",null,[e("移动至 "),a(s,{to:"/zh/reference/config.html#markdown-headers"},{default:t(()=>[e("markdown.headers")]),_:1}),e(" 。")]),P,n("p",null,[e("请参考 "),a(s,{to:"/zh/guide/bundler.html"},{default:t(()=>[e("指南 > Bundler")]),_:1}),e(" 。")]),z,S,E,n("p",null,[e("改为使用 "),a(s,{to:"/zh/reference/frontmatter.html#head"},{default:t(()=>[e("head")]),_:1}),e(" 。例如:")]),V,n("p",null,[e("参考 "),a(s,{to:"/zh/reference/frontmatter.html#permalinkpattern"},{default:t(()=>[e("Frontmatter > permalinkPattern")]),_:1}),e(" 。")]),X,A,n("p",null,[e("调色板系统提取到了 "),a(s,{to:"/zh/reference/plugin/palette.html"},{default:t(()=>[e("@vuepress/plugin-palette")]),_:1}),e(" 当中。")]),q,n("p",null,[e("如果你使用的是默认主题,那么调色板系统仍然存在,但改为使用 SASS ,并且大部分变量都迁移为 CSS 变量。参考 "),a(s,{to:"/zh/reference/default-theme/styles.html"},{default:t(()=>[e("默认主题 > 样式")]),_:1}),e(" 。")]),W,F,H,n("p",null,[e("参考 "),a(s,{to:"/zh/advanced/cookbook/usage-of-client-config.html"},{default:t(()=>[e("深入 > Cookbook > 客户端配置的使用方法")]),_:1}),e(" 。")]),j,M,n("p",null,[e("你需要使用 "),a(s,{to:"/zh/reference/plugin/register-components.html"},{default:t(()=>[e("@vuepress/plugin-register-components")]),_:1}),e(" ,或者在 "),I,e(" 中手动注册你的组件。")]),D,T,n("p",null,[e("你需要在 "),a(s,{to:"/zh/reference/config.html#theme"},{default:t(()=>[e("theme")]),_:1}),e(" 配置项中显式引入并使用本地主题。")]),G,n("p",null,[e("参考 "),a(s,{to:"/zh/reference/default-theme/styles.html"},{default:t(()=>[e("默认主题 > 样式")]),_:1}),e(" 。")]),N,L,n("p",null,[e("参考 "),a(s,{to:"/zh/reference/default-theme/config.html"},{default:t(()=>[e("默认主题 > 配置")]),_:1}),e(" 。")]),$,n("ul",null,[J,R,n("li",null,[e("Webpack 相关的 Hook 都被移除了,因为 VuePress Core 已经和 Webpack 解耦了。你可以尝试使用 "),a(s,{to:"/zh/reference/plugin-api.html#extendsbundleroptions"},{default:t(()=>[e("extendsBundlerOptions")]),_:1}),e(" Hook 来进行相似的操作,但要注意应适配所有不同的打包工具。")])]),n("p",null,[e("你可以参考 "),a(s,{to:"/zh/advanced/plugin.html"},{default:t(()=>[e("深入 > 开发插件")]),_:1}),e(" 来了解如何开发一个 v2 插件。")]),O,n("p",null,[e("参考 "),a(s,{to:"/zh/reference/plugin-api.html"},{default:t(()=>[e("插件 API")]),_:1}),e(" 。")]),U,Y,Z,K,n("ul",null,[n("li",null,[e("所谓的 "),Q,e(" 不再存在。 "),n("ul",null,[ee,n("li",null,[ne,e(" 目录下的文件不会被自动注册为 Vue 组件。你需要使用 "),a(s,{to:"/zh/reference/plugin/register-components.html"},{default:t(()=>[e("@vuepress/plugin-register-components")]),_:1}),e(" ,或者在 "),se,e(" 中手动注册组件。")]),ae])]),n("li",null,[te,e(" 已经从用户配置和站点数据中移除。如果你想要像 v1 一样通过 "),le,e(" 来访问 "),ie,e(" ,我们现在建议使用 "),a(s,{to:"/zh/reference/plugin/theme-data.html"},{default:t(()=>[e("@vuepress/plugin-theme-data")]),_:1}),e(" 插件和它提供的 Composition API "),de,e(" 。")]),n("li",null,[e("Stylus 不再是默认的 CSS 预处理器,并且 Stylus 调色板系统不再被默认支持。如果你仍然想要使用和 v1 类似的调色板系统,可以使用 "),a(s,{to:"/zh/reference/plugin/palette.html"},{default:t(()=>[e("@vuepress/plugin-palette")]),_:1}),e(" 。")]),n("li",null,[e("由 Prism.js 提供的 Markdown 代码块的语法高亮不再被默认支持。你可以选择使用 "),a(s,{to:"/zh/reference/plugin/prismjs.html"},{default:t(()=>[e("@vuepress/plugin-prismjs")]),_:1}),e(" 或 "),a(s,{to:"/zh/reference/plugin/shiki.html"},{default:t(()=>[e("@vuepress/plugin-shiki")]),_:1}),e(" ,或者用你自己的方式实现语法高亮。")]),oe]),n("p",null,[e("你可以参考 "),a(s,{to:"/zh/advanced/theme.html"},{default:t(()=>[e("深入 > 开发主题")]),_:1}),e(" 来了解如何开发一个 v2 主题。")]),ce,re,pe,ue,n("p",null,[e("参考 "),a(s,{to:"/zh/advanced/theme.html"},{default:t(()=>[e("深入 > 开发主题")]),_:1}),e(" 。")]),he,ke,me,n("p",null,[e("你可以参考 "),a(s,{to:"/zh/reference/default-theme/extending.html"},{default:t(()=>[e("默认主题 > 继承")]),_:1}),e(" 来了解如何继承默认主题。")]),n("p",null,[fe,e(" 和 "),ve,e(" 别名默认被移除了,但你仍然可以使用类似的方式来开发一个可继承的主题,参考 "),a(s,{to:"/zh/advanced/cookbook/making-a-theme-extendable.html"},{default:t(()=>[e("深入 > Cookbook > 开发一个可继承的主题")]),_:1}),e(" 。")])])}const we=i(r,[["render",_e],["__file","migration.html.vue"]]);export{we as default}; diff --git a/assets/migration.html-cc0874ae.js b/assets/migration.html-cc0874ae.js new file mode 100644 index 00000000..4fb51b17 --- /dev/null +++ b/assets/migration.html-cc0874ae.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-81b14334","path":"/zh/guide/migration.html","title":"从 v1 迁移","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:code-compare","description":"VuePress v1 的插件和主题与 VuePress v2 不兼容。你需要将它们升级到与 v2 对应的版本。 VuePress v2 的一些主要改动和优化: VuePress v2 现在使用 Vue 3 ,因此你要保证你的组件和其他客户端文件是适用于 Vue 3 的。; VuePress v2 是使用 TypeScript 开发的,因此它现在提供了...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/migration.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/migration.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"从 v1 迁移"}],["meta",{"property":"og:description","content":"VuePress v1 的插件和主题与 VuePress v2 不兼容。你需要将它们升级到与 v2 对应的版本。 VuePress v2 的一些主要改动和优化: VuePress v2 现在使用 Vue 3 ,因此你要保证你的组件和其他客户端文件是适用于 Vue 3 的。; VuePress v2 是使用 TypeScript 开发的,因此它现在提供了..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"从 v1 迁移\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"给用户","slug":"给用户","link":"#给用户","children":[{"level":3,"title":"用户配置变更","slug":"用户配置变更","link":"#用户配置变更","children":[]},{"level":3,"title":"Frontmatter 变更","slug":"frontmatter-变更","link":"#frontmatter-变更","children":[]},{"level":3,"title":"永久链接 Patterns 变更","slug":"永久链接-patterns-变更","link":"#永久链接-patterns-变更","children":[]},{"level":3,"title":"调色板系统变更","slug":"调色板系统变更","link":"#调色板系统变更","children":[]},{"level":3,"title":"约定文件变更","slug":"约定文件变更","link":"#约定文件变更","children":[]},{"level":3,"title":"Markdown 插槽变更","slug":"markdown-插槽变更","link":"#markdown-插槽变更","children":[]},{"level":3,"title":"CLI 变更","slug":"cli-变更","link":"#cli-变更","children":[]},{"level":3,"title":"默认主题变更","slug":"默认主题变更","link":"#默认主题变更","children":[]},{"level":3,"title":"官方插件变更","slug":"官方插件变更","link":"#官方插件变更","children":[]},{"level":3,"title":"社区主题和插件","slug":"社区主题和插件","link":"#社区主题和插件","children":[]}]},{"level":2,"title":"给插件作者","slug":"给插件作者","link":"#给插件作者","children":[{"level":3,"title":"插件 API 变更","slug":"插件-api-变更","link":"#插件-api-变更","children":[]}]},{"level":2,"title":"给主题作者","slug":"给主题作者","link":"#给主题作者","children":[{"level":3,"title":"主题 API 变更","slug":"主题-api-变更","link":"#主题-api-变更","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":8.02,"words":2405},"filePathRelative":"zh/guide/migration.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/migration.html-feaf251f.js b/assets/migration.html-feaf251f.js new file mode 100644 index 00000000..deb70629 --- /dev/null +++ b/assets/migration.html-feaf251f.js @@ -0,0 +1,72 @@ +import{_ as o,W as l,X as d,$ as n,a0 as e,Y as s,Z as t,a1 as i,D as r}from"./framework-46b0e263.js";const c={},p=i(`"main": "layouts/Layout.vue"
作为主题入口。# Migrating from v1
Note
Plugins and themes of VuePress v1 are not compatible with VuePress v2. You need to update them to corresponding v2 version.
Some major changes and enhancements of VuePress v2:
- VuePress v2 is now using Vue 3, so make sure your components and other client files are compatible with Vue 3.
- VuePress v2 is developed with TypeScript, so it provides better TS support now. It's highly recommended to use TypeScript to develop plugins and themes. VuePress config file also supports TypeScript, and you can use
.vuepress/config.ts
directly.- VuePress v2 supports both Webpack and Vite as bundler. Now Vite is the default bundler, while you can still choose to use Webpack. You can even use Vite in dev mode to get better development experience, and use Webpack in build mode to get better browser compatibility.
- VuePress v2 is now released as pure ESM packages, and CommonJS config files are no longer supported.
Core ideas and processes of VuePress v2 are the same with v1, while v2 API has been re-designed and becomes more normalized. So you might encounter breaking changes when migrating an existing v1 project to v2. This guide is here to help you migrating v1 sites / plugins / themes to v2.
- If you are a common user, you need to read the guide for users.
- If you are a plugin author, you need to read the guide for plugin authors.
- If you are a theme author, you need to read the guide for theme authors.
# For Users
# User Config Change
Config file should be in ESM format, and CommonJS format config file is no longer supported.
// .vuepress/config.js + +- module.exports = { +- // user config +- } + ++ export default { ++ // user config ++ } +
# theme
Using a theme via string is not supported. Import the theme directly.
- module.exports = { +- theme: '@vuepress/theme-default', +- themeConfig: { +- // default theme config +- }, +- } + ++ import { defaultTheme } from 'vuepress' ++ export default { ++ theme: defaultTheme({ ++ // default theme config ++ }) ++ } +
# themeConfig
Removed. Set config to the theme directly.
# plugins
Using a plugin via string is not supported. Import the plugin directly.
- module.exports = { +- plugins: [ +- [ +- '@vuepress/plugin-google-analytics', +- { +- id: 'G-XXXXXXXXXX', +- }, +- ], +- ], +- } + ++ import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' ++ export default { ++ plugins: [ ++ googleAnalyticsPlugin({ ++ id: 'G-XXXXXXXXXX', ++ }), ++ ], ++ } +
# shouldPrefetch
Default value is changed from
() => true
totrue
.# extraWatchFiles
Removed.
`,22),u=n("h4",{id:"patterns",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#patterns","aria-hidden":"true"},"#"),e(" patterns")],-1),h=n("p",null,[e("Renamed to "),n("code",null,"pagePatterns")],-1),m=n("h4",{id:"markdown-linenumbers",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-linenumbers","aria-hidden":"true"},"#"),e(" markdown.lineNumbers")],-1),f=n("p",null,[e("Default value is changed from "),n("code",null,"false"),e(" to "),n("code",null,"true"),e(".")],-1),g=n("h4",{id:"markdown-pagesuffix",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-pagesuffix","aria-hidden":"true"},"#"),e(" markdown.pageSuffix")],-1),v=n("p",null,"Removed.",-1),k=n("h4",{id:"markdown-externallinks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-externallinks","aria-hidden":"true"},"#"),e(" markdown.externalLinks")],-1),b=n("h4",{id:"markdown-toc",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-toc","aria-hidden":"true"},"#"),e(" markdown.toc")],-1),_=n("p",null,"Changed.",-1),x=n("h4",{id:"markdown-plugins",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-plugins","aria-hidden":"true"},"#"),e(" markdown.plugins")],-1),y=n("p",null,"Removed.",-1),w=n("h4",{id:"markdown-extendmarkdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-extendmarkdown","aria-hidden":"true"},"#"),e(" markdown.extendMarkdown")],-1),C=n("p",null,"Removed.",-1),P=n("h4",{id:"markdown-extractheaders",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown-extractheaders","aria-hidden":"true"},"#"),e(" markdown.extractHeaders")],-1),S=i(`# Webpack Related Configs
All webpack related configs are moved to options of
@vuepress/bundler-webpack
, including:
postcss
stylus
scss
sass
less
chainWebpack
configureWebpack
evergreen
: default value is changed fromfalse
totrue
`,4),T=n("h3",{id:"frontmatter-change",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#frontmatter-change","aria-hidden":"true"},"#"),e(" Frontmatter Change")],-1),A=n("h4",{id:"meta",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#meta","aria-hidden":"true"},"#"),e(" meta")],-1),V=n("p",null,"Removed.",-1),F=i(`- module.exports = { +- sass: { /* ... */ }, +- } + ++ import { webpackBundler } from '@vuepress/bundler-webpack' ++ export default { ++ bundler: webpackBundler({ ++ sass: { /* ... */ }, ++ }), ++ } +
head: + - - meta + - name: foo + content: bar + - - link + - rel: canonical + href: foobar + - - script + - {} + - console.log('hello from frontmatter'); +
Has the same structure with:
// .vuepress/config.ts +export default { + // ... + head: [ + ["meta", { name: "foo", content: "bar" }], + ["link", { rel: "canonical", href: "foobar" }], + ["script", {}, \`console.log('hello from frontmatter');\`], + ], + // ... +}; +
# Permalink Patterns Change
`,5),X=n("h3",{id:"palette-system-change",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#palette-system-change","aria-hidden":"true"},"#"),e(" Palette System Change")],-1),q=n("p",null,[e("The stylus palette system of VuePress v1 (i.e. "),n("code",null,"styles/palette.styl"),e(" and "),n("code",null,"styles/index.styl"),e(") is no longer provided by VuePress Core.")],-1),M=n("p",null,"Theme authors can use their own way to allow users to customize styles, and not be limited with stylus.",-1),j=n("h3",{id:"conventional-files-change",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#conventional-files-change","aria-hidden":"true"},"#"),e(" Conventional Files Change")],-1),I=n("h4",{id:"vuepress-enhanceapp-js",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepress-enhanceapp-js","aria-hidden":"true"},"#"),e(" .vuepress/enhanceApp.js")],-1),D=n("p",null,[e("Renamed to "),n("code",null,".vuepress/client.{js,ts}"),e(", and the usage has been changed, too.")],-1),W=n("h4",{id:"vuepress-components",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepress-components","aria-hidden":"true"},"#"),e(" .vuepress/components/")],-1),Y=n("p",null,"Files in this directory will not be registered as Vue components automatically.",-1),R=n("code",null,".vuepress/client.{js,ts}",-1),B=n("h4",{id:"vuepress-theme",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepress-theme","aria-hidden":"true"},"#"),e(" .vuepress/theme/")],-1),N=n("p",null,"This directory will not be used as local theme implicitly if it is existed.",-1),U=i('
:i_month
: removed:i_day
: removed:minutes
: removed (undocumented in v1):seconds
: removed (undocumented in v1):regular
: renamed to:raw
# Markdown slot Change
Markdown slot is no longer supported.
# CLI Change
# eject command
Removed.
# cache options
-c, --cache [cache]
: changed to--cache <cache>
, which means that the shorthand-c
is not forcache
option, and the value ofcache
option is not optional.--no-cache
: renamed to--clean-cache
.# Default Theme Change
# Built-in Components
<CodeGroup />
and<CodeBlock />
renamed to<CodeGroup />
and<CodeGroupItem />
<Badge />
$badgeErrorColor
palette variable renamed to$badgeDangerColor
type
prop only acceptstip
,warning
anddanger
now# Palette System
The palette system of default theme has migrated to SASS and CSS variables.
',12),G=n("h4",{id:"theme-config",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#theme-config","aria-hidden":"true"},"#"),e(" Theme Config")],-1),E=n("p",null,"Default theme config has been changed a lot. You'd better check the config reference of v2 default theme to migrate it properly.",-1),L=i('# Official Plugins Change
Check the v2 docs of official plugins.
# Community Themes and Plugins
Themes and plugins of v1 are not compatible with v2.
Please make sure that those themes and plugins you are using have supported v2, and refer to their own documentation for migration guide.
# For Plugin Authors
Some major breaking changes:
',7),$=n("li",null,"You cannot use other plugins in your plugin anymore, which avoids lots of potential issues caused by plugin nesting. If your plugin depends on other plugins, you could list them in the docs to ask users import them manually. Alternatively, you can provide users with an array of plugins for convenience.",-1),z=n("li",null,[e("Most of the v1 hooks have equivalents in v2. The only exception is "),n("code",null,"extendsCli"),e(", which has been removed.")],-1),H=i('# Plugin API Change
',2),J=n("h2",{id:"for-theme-authors",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#for-theme-authors","aria-hidden":"true"},"#"),e(" For Theme Authors")],-1),O=n("p",null,"Although we do not allow using other plugins in a plugin anymore, you can still use plugins in your theme.",-1),Z=n("p",null,"Some major breaking changes:",-1),K=n("strong",null,"conventional theme directory structure",-1),Q=n("li",null,[e("The file "),n("code",null,"theme/enhanceApp.js"),e(" will not be used as client app enhance file implicitly. You need to specify it explicitly in "),n("code",null,"clientConfigFile"),e(" hook.")],-1),ee=n("code",null,"theme/global-components/",-1),ne=n("code",null,"clientConfigFile",-1),ae=i("
plugins
: removedready
: renamed toonPrepared
updated
: renamed toonWatched
generated
: renamed toonGenerated
additionalPages
: removed, useapp.pages.push(createPage())
inonInitialized
hookclientDynamicModules
: removed, useapp.writeTemp()
inonPrepared
hookenhanceAppFiles
: removed, useclientConfigFile
hookglobalUIComponents
: removed, useclientConfigFile
hookclientRootMixin
: removed, useclientConfigFile
hookextendMarkdown
: renamed toextendsMarkdown
chainMarkdown
: removedextendPageData
: renamed toextendsPage
extendsCli
: removedconfigureWebpack
: removedchainWebpack
: removedbeforeDevServer
: removedafterDevServer
: removedFiles in theme/layouts/
directory will not be registered as layout components automatically. You need to specify it explicitly inlayouts
option inclientConfigFile
.Files in theme/templates/
directory will not be used as dev / ssr template automatically. You need to specify theme explicitly intemplateBuild
andtemplateDev
option.Always provide a valid js entry file, and do not use ",3),se=n("code",null,"themeConfig",-1),te=n("code",null,"themeConfig",-1),ie=n("code",null,"this.$site.themeConfig",-1),oe=n("code",null,"useThemeData",-1),le=n("li",null,[e("For scalability concerns, "),n("code",null,"this.$site.pages"),e(" is not available any more.")],-1),de=n("h3",{id:"theme-api-change",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#theme-api-change","aria-hidden":"true"},"#"),e(" Theme API Change")],-1),re=n("h4",{id:"layouts",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#layouts","aria-hidden":"true"},"#"),e(" layouts")],-1),ce=n("p",null,"Removed.",-1),pe=n("p",null,"Now you need to specify layout component in the client config file of your theme.",-1),ue=n("h4",{id:"extend",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#extend","aria-hidden":"true"},"#"),e(" extend")],-1),he=n("p",null,[e("Renamed to "),n("code",null,"extends"),e(".")],-1),me=n("p",null,[e("You can still inherit a parent theme with "),n("code",null,"extends: parentTheme()"),e(", which will extends the plugins, layouts, etc.")],-1),fe=n("code",null,"@theme",-1),ge=n("code",null,"@parent-theme",-1);function ve(ke,be){const a=r("RouterLink");return l(),d("div",null,[p,n("p",null,[e("You can watch files manually in "),s(a,{to:"/reference/plugin-api.html#onwatched"},{default:t(()=>[e("onWatched")]),_:1}),e(" hook.")]),u,h,m,n("p",null,[e("Moved to "),s(a,{to:"/reference/config.html#markdown-code-linenumbers"},{default:t(()=>[e("markdown.code.lineNumbers")]),_:1}),e(".")]),f,g,v,k,n("p",null,[e("Moved to "),s(a,{to:"/reference/config.html#markdown-links"},{default:t(()=>[e("markdown.links.externalAttrs")]),_:1}),e(".")]),b,_,n("p",null,[e("See "),s(a,{to:"/reference/config.html#markdown-toc"},{default:t(()=>[e("Config > markdown.toc")]),_:1})]),x,y,n("p",null,[e("Use markdown-it plugins in "),s(a,{to:"/reference/plugin-api.html#extendsmarkdown"},{default:t(()=>[e("extendsMarkdown")]),_:1}),e(" hook.")]),w,C,n("p",null,[e("Use "),s(a,{to:"/reference/plugin-api.html#extendsmarkdown"},{default:t(()=>[e("extendsMarkdown")]),_:1}),e(" hook.")]),P,n("p",null,[e("Moved to "),s(a,{to:"/reference/config.html#markdown-headers"},{default:t(()=>[e("markdown.headers")]),_:1}),e(".")]),S,n("p",null,[e("Please refer to "),s(a,{to:"/guide/bundler.html"},{default:t(()=>[e("Guide > Bundler")]),_:1}),e(".")]),T,A,V,n("p",null,[e("Use "),s(a,{to:"/reference/frontmatter.html#head"},{default:t(()=>[e("head")]),_:1}),e(" instead. For example:")]),F,n("p",null,[e("See "),s(a,{to:"/reference/frontmatter.html#permalinkpattern"},{default:t(()=>[e("Frontmatter > permalinkPattern")]),_:1}),e(".")]),X,q,n("p",null,[e("The palette system is extracted to "),s(a,{to:"/reference/plugin/palette.html"},{default:t(()=>[e("@vuepress/plugin-palette")]),_:1}),e(".")]),M,n("p",null,[e("If you are using default theme, the palette system is still available but migrated to SASS, while most variables have been migrated to CSS variables. See "),s(a,{to:"/reference/default-theme/styles.html"},{default:t(()=>[e("Default Theme > Styles")]),_:1}),e(".")]),j,I,D,n("p",null,[e("See "),s(a,{to:"/advanced/cookbook/usage-of-client-config.html"},{default:t(()=>[e("Advanced > Cookbook > Usage of Client Config")]),_:1}),e(".")]),W,Y,n("p",null,[e("You need to use "),s(a,{to:"/reference/plugin/register-components.html"},{default:t(()=>[e("@vuepress/plugin-register-components")]),_:1}),e(", or register your components manually in "),R,e(".")]),B,N,n("p",null,[e("You need to import and set your local theme via "),s(a,{to:"/reference/config.html#theme"},{default:t(()=>[e("theme")]),_:1}),e(" option.")]),U,n("p",null,[e("See "),s(a,{to:"/reference/default-theme/styles.html"},{default:t(()=>[e("Default Theme > Styles")]),_:1}),e(".")]),G,E,n("p",null,[e("See "),s(a,{to:"/reference/default-theme/config.html"},{default:t(()=>[e("Default Theme > Config")]),_:1}),e(".")]),L,n("ul",null,[$,z,n("li",null,[e("Webpack related hooks are removed, because VuePress Core has decoupled with webpack. You can try to use "),s(a,{to:"/reference/plugin-api.html#extendsbundleroptions"},{default:t(()=>[e("extendsBundlerOptions")]),_:1}),e(" hook for similar purpose, and make sure to work with all bundlers.")])]),n("p",null,[e("For more detailed guide about how to write a plugin in v2, see "),s(a,{to:"/advanced/plugin.html"},{default:t(()=>[e("Advanced > Writing a Plugin")]),_:1}),e(".")]),H,n("p",null,[e("See "),s(a,{to:"/reference/plugin-api.html"},{default:t(()=>[e("Plugin API")]),_:1}),e(".")]),J,O,Z,n("ul",null,[n("li",null,[e("There is no "),K,e(" anymore. "),n("ul",null,[Q,n("li",null,[e("Files in "),ee,e(" directory will not be registered as Vue components automatically. You need to use "),s(a,{to:"/reference/plugin/register-components.html"},{default:t(()=>[e("@vuepress/plugin-register-components")]),_:1}),e(", or register components manually in "),ne,e(".")]),ae])]),n("li",null,[se,e(" is removed from user config and site data. To access the "),te,e(" as you would via "),ie,e(" in v1, we now recommend using the "),s(a,{to:"/reference/plugin/theme-data.html"},{default:t(()=>[e("@vuepress/plugin-theme-data")]),_:1}),e(" plugin and its "),oe,e(" composition API.")]),n("li",null,[e("Stylus is no longer the default CSS pre-processor, and the stylus palette system is not embedded. If you still want to use similar palette system as v1, "),s(a,{to:"/reference/plugin/palette.html"},{default:t(()=>[e("@vuepress/plugin-palette")]),_:1}),e(" may help.")]),n("li",null,[e("Markdown code blocks syntax highlighting by Prism.js is not embedded by default. You can use either "),s(a,{to:"/reference/plugin/prismjs.html"},{default:t(()=>[e("@vuepress/plugin-prismjs")]),_:1}),e(" or "),s(a,{to:"/reference/plugin/shiki.html"},{default:t(()=>[e("@vuepress/plugin-shiki")]),_:1}),e(", or implement syntax highlighting in your own way.")]),le]),n("p",null,[e("For more detailed guide about how to write a theme in v2, see "),s(a,{to:"/advanced/theme.html"},{default:t(()=>[e("Advanced > Writing a Theme")]),_:1}),e(".")]),de,re,ce,pe,n("p",null,[e("See "),s(a,{to:"/advanced/theme.html"},{default:t(()=>[e("Advanced > Writing a theme")]),_:1}),e(".")]),ue,he,me,n("p",null,[e("You can refer to "),s(a,{to:"/reference/default-theme/extending.html"},{default:t(()=>[e("Default Theme > Extending")]),_:1}),e(" for how to extend default theme.")]),n("p",null,[e("The "),fe,e(" and "),ge,e(" aliases are removed by default, but you can still make a extendable theme with similar approach, see "),s(a,{to:"/advanced/cookbook/making-a-theme-extendable.html"},{default:t(()=>[e("Advanced > Cookbook > Making a Theme Extendable")]),_:1}),e(".")])])}const xe=o(c,[["render",ve],["__file","migration.html.vue"]]);export{xe as default}; diff --git a/assets/node-api.html-18ff42ee.js b/assets/node-api.html-18ff42ee.js new file mode 100644 index 00000000..0738a450 --- /dev/null +++ b/assets/node-api.html-18ff42ee.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4986678d","path":"/reference/node-api.html","title":"Node API","lang":"en-US","frontmatter":{"icon":"fa6-brands:node-js","description":"Node API is provided by @vuepress/core (https://www.npmjs.com/package/@vuepress/core) package. It is a dependency of the vuepress (https://www.npmjs.com/package/vuepress) packag...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/node-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/node-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Node API"}],["meta",{"property":"og:description","content":"Node API is provided by @vuepress/core (https://www.npmjs.com/package/@vuepress/core) package. It is a dependency of the vuepress (https://www.npmjs.com/package/vuepress) packag..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Node API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"App","slug":"app","link":"#app","children":[{"level":3,"title":"createBuildApp","slug":"createbuildapp","link":"#createbuildapp","children":[]},{"level":3,"title":"createDevApp","slug":"createdevapp","link":"#createdevapp","children":[]}]},{"level":2,"title":"App Properties","slug":"app-properties","link":"#app-properties","children":[{"level":3,"title":"options","slug":"options","link":"#options","children":[]},{"level":3,"title":"siteData","slug":"sitedata","link":"#sitedata","children":[]},{"level":3,"title":"version","slug":"version","link":"#version","children":[]},{"level":3,"title":"env.isBuild","slug":"env-isbuild","link":"#env-isbuild","children":[]},{"level":3,"title":"env.isDev","slug":"env-isdev","link":"#env-isdev","children":[]},{"level":3,"title":"env.isDebug","slug":"env-isdebug","link":"#env-isdebug","children":[]},{"level":3,"title":"markdown","slug":"markdown","link":"#markdown","children":[]},{"level":3,"title":"pages","slug":"pages","link":"#pages","children":[]}]},{"level":2,"title":"App Methods","slug":"app-methods","link":"#app-methods","children":[{"level":3,"title":"dir","slug":"dir","link":"#dir","children":[]},{"level":3,"title":"writeTemp","slug":"writetemp","link":"#writetemp","children":[]},{"level":3,"title":"init","slug":"init","link":"#init","children":[]},{"level":3,"title":"prepare","slug":"prepare","link":"#prepare","children":[]},{"level":3,"title":"build","slug":"build","link":"#build","children":[]},{"level":3,"title":"dev","slug":"dev","link":"#dev","children":[]}]},{"level":2,"title":"Page","slug":"page","link":"#page","children":[{"level":3,"title":"createPage","slug":"createpage","link":"#createpage","children":[]}]},{"level":2,"title":"Page Properties","slug":"page-properties","link":"#page-properties","children":[{"level":3,"title":"key","slug":"key","link":"#key","children":[]},{"level":3,"title":"path","slug":"path","link":"#path","children":[]},{"level":3,"title":"title","slug":"title","link":"#title","children":[]},{"level":3,"title":"lang","slug":"lang","link":"#lang","children":[]},{"level":3,"title":"frontmatter","slug":"frontmatter","link":"#frontmatter","children":[]},{"level":3,"title":"headers","slug":"headers","link":"#headers","children":[]},{"level":3,"title":"data","slug":"data","link":"#data","children":[]},{"level":3,"title":"content","slug":"content","link":"#content","children":[]},{"level":3,"title":"contentRendered","slug":"contentrendered","link":"#contentrendered","children":[]},{"level":3,"title":"date","slug":"date","link":"#date","children":[]},{"level":3,"title":"deps","slug":"deps","link":"#deps","children":[]},{"level":3,"title":"links","slug":"links","link":"#links","children":[]},{"level":3,"title":"pathInferred","slug":"pathinferred","link":"#pathinferred","children":[]},{"level":3,"title":"pathLocale","slug":"pathlocale","link":"#pathlocale","children":[]},{"level":3,"title":"permalink","slug":"permalink","link":"#permalink","children":[]},{"level":3,"title":"routeMeta","slug":"routemeta","link":"#routemeta","children":[]},{"level":3,"title":"sfcBlocks","slug":"sfcblocks","link":"#sfcblocks","children":[]},{"level":3,"title":"slug","slug":"slug","link":"#slug","children":[]},{"level":3,"title":"filePath","slug":"filepath","link":"#filepath","children":[]},{"level":3,"title":"filePathRelative","slug":"filepathrelative","link":"#filepathrelative","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":5.11,"words":1532},"filePathRelative":"reference/node-api.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/node-api.html-3f616fc7.js b/assets/node-api.html-3f616fc7.js new file mode 100644 index 00000000..c34d6c43 --- /dev/null +++ b/assets/node-api.html-3f616fc7.js @@ -0,0 +1,104 @@ +import{_ as c,W as u,X as d,Y as s,$ as n,a0 as a,Z as t,a1 as l,D as i}from"./framework-46b0e263.js";const r={},h=n("h1",{id:"node-api",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#node-api","aria-hidden":"true"},"#"),a(" Node API")],-1),k={href:"https://www.npmjs.com/package/@vuepress/core",target:"_blank",rel:"noopener noreferrer"},v={href:"https://www.npmjs.com/package/vuepress",target:"_blank",rel:"noopener noreferrer"},m=l(`"main": "layouts/Layout.vue"
as the theme entry anymore.npm i -D @vuepress/core@next +
# App
`,2),b=l(`
BuildApp
和DevApp
除了 build 和 dev 方法外,拥有一样的属性和方法。# createBuildApp
- 函数签名:
const createBuildApp: (config: AppConfig) => BuildApp; +
- 参数:
参数 类型 描述 config AppConfig
创建 VuePress App 的选项。
详情:
创建一个 Build 模式的 App 实例,用于构建静态文件。
示例:
const build = async () => { + const app = createBuildApp({ + // ...配置项 + }); + + // 初始化和准备 + await app.init(); + await app.prepare(); + + // 构建 + await app.build(); + + // 处理 onGenerated hook + await app.pluginApi.hooks.onGenerated.process(app); +}; +
# createDevApp
- 函数签名:
const createDevApp: (config: AppConfig) => DevApp; +
- 参数:
参数 类型 描述 config AppConfig
创建 VuePress App 的选项。
详情:
创建一个 Dev 模式的 App 实例,用于启动开发服务器。
示例:
const dev = async () => { + const app = createDevApp({ + // ...配置项 + }); + + // 初始化和准备 + await app.init(); + await app.prepare(); + + // 启动开发服务器 + const closeDevServer = await app.dev(); + + // 准备文件监听器 + const watchers = []; + + // 重启开发服务器 + const restart = async () => { + await Promise.all([ + // 关闭所有监听器 + ...watchers.map((item) => item.close()), + // 关闭当前的开发服务器 + closeDevServer(), + ]); + await dev(); + }; + + // 处理 onWatched hook + await app.pluginApi.hooks.onWatched.process(app, watchers, restart); +}; +
# App 属性
# options
类型:
AppOptions
详情:
VuePress App 的配置项。
这些配置项来自于 createBuildApp / createDevApp 的
config
参数,但所有可选的字段都填充上了默认值。# siteData
`,21),g=n("li",null,[n("p",null,[a("类型: "),n("code",null,"SiteData")])],-1),_=n("p",null,"详情:",-1),f=l('# version
类型:
string
详情:
VuePress App 的版本,即
@vuepress/core
包的版本。# env.isBuild
类型:
boolean
详情:
用于判断 App 是否运行在 Build 模式的环境标记,即当前 App 是否是 BuildApp 实例。
# env.isDev
类型:
boolean
详情:
用于判断 App 是否运行在 Dev 模式的环境标记,即当前 App 是否是 DevApp 实例。
# env.isDebug
类型:
boolean
详情:
用于判断 App 是否开启 Debug 模式的环境标记。
# markdown
',9),y=n("li",null,[n("p",null,[a("类型: "),n("code",null,"MarkdownIt")])],-1),w=n("p",null,"详情:",-1),P={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},x=n("h3",{id:"pages",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pages","aria-hidden":"true"},"#"),a(" pages")],-1),A=n("li",null,[n("p",null,[a("类型: "),n("code",null,"Page[]")])],-1),B=n("p",null,"详情:",-1),E=n("p",null,[n("a",{href:"#page"},"Page"),a(" 对象数组。")],-1),z=l(`# App 方法
# dir
工具函数:
dir.cache()
: 解析至缓存目录dir.temp()
: 解析至临时文件目录dir.source()
: 解析至源文件目录dir.dest()
: 解析至输出目录dir.client()
: 解析至@vuepress/client
目录dir.public()
: 解析至 Public 文件目录函数签名:
type AppDirFunction = (...args: string[]) => string; +
详情:
用于解析对应目录下的文件绝对路径的一些工具函数。
如果你不传入任何参数,就会返回对应目录的绝对路径。
示例:
// 解析 \`\${sourceDir}/README.md\` 文件的绝对路径 +const homeSourceFile = app.dir.source("README.md"); +
# writeTemp
- 函数签名:
writeTemp(file: string, content: string): Promise<string> +
- 参数:
参数 类型 描述 file string
要写入的临时文件的路径,相对于临时文件目录。 content string
要写入的临时文件路径的内容。
详情:
用于写入临时文件的方法。
写入的文件可以在客户端文件中通过
@temp
别名来引入。示例:
export default { + // 在 onPrepared hook 中写入临时文件 + async onPrepared() { + await app.writeTemp("foo.js", "export const foo = 'bar'"); + }, +}; +
// 在客户端文件中引入临时文件 +import { foo } from "@temp/foo"; +
# init
- 函数签名:
`,17),D=n("li",null,[n("p",null,"详情:"),n("p",null,"初始化 VuePress App 。")],-1),M=n("p",null,"参考:",-1),I=l(`init(): Promise<void> +
# prepare
- 函数签名:
`,3),F=n("li",null,[n("p",null,"详情:"),n("p",null,"准备客户端临时文件。")],-1),R=n("p",null,"参考:",-1),q=l(`prepare(): Promise<void> +
# build
- 函数签名:
`,3),N=n("li",null,[n("p",null,"详情:"),n("p",null,"生成静态站点文件。"),n("p",null,[a("该方法仅在 "),n("a",{href:"#createbuildapp"},"BuildApp"),a(" 中可用。")])],-1),V=n("p",null,"参考:",-1),C=l(`build(): Promise<void> +
# dev
- 函数签名:
`,3),H=n("li",null,[n("p",null,"详情:"),n("p",null,"启动开发服务器。"),n("p",null,[a("该方法仅在 "),n("a",{href:"#createdevapp"},"DevApp"),a(" 中可用。")])],-1),L=n("p",null,"参考:",-1),S=l(`dev(): Promise<() => Promise<void>> +
# Page
# createPage
- 函数签名:
const createPage: (app: App, options: PageOptions) => Promise<Page>; +
- 参数:
参数 类型 描述 app App
VuePress App 实例。 options PageOptions
创建 VuePress Page 的选项。
详情:
创建一个 VuePress Page 对象。
示例:
`,8),j=n("li",null,[n("a",{href:"#pages"},"Node API > App 属性 > pages")],-1),T=n("h2",{id:"page-属性",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#page-属性","aria-hidden":"true"},"#"),a(" Page 属性")],-1),O=n("h3",{id:"key",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#key","aria-hidden":"true"},"#"),a(" key")],-1),W=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),G=n("p",null,"详情:",-1),$=n("p",null,"该 Page 的标识。",-1),K={href:"https://router.vuejs.org/api/#name-2",target:"_blank",rel:"noopener noreferrer"},U=n("p",null,"参考:",-1),X=n("h3",{id:"path",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#path","aria-hidden":"true"},"#"),a(" path")],-1),Y=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),Z=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 的路由路径。")],-1),J=n("p",null,"参考:",-1),Q=n("li",null,[n("a",{href:"#pathinferred"},"Node API > Page 属性 > pathInferred")],-1),nn=n("h3",{id:"title",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#title","aria-hidden":"true"},"#"),a(" title")],-1),an=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string")])],-1),sn=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 的标题。")],-1),en=n("p",null,"参考:",-1),tn=n("h3",{id:"lang",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#lang","aria-hidden":"true"},"#"),a(" lang")],-1),ln=l("import { createPage } from "@vuepress/core"; + +export default { + // 在 onInitialized hook 中创建一个额外页面 + async onInitialized(app) { + app.pages.push( + await createPage(app, { + path: "/foo.html", + frontmatter: { + layout: "Layout", + }, + content: \`\\ +# 某个 Page + +你好,世界。 +\`, + }) + ); + }, +}; +
类型:
string
详情:
该 Page 的语言。
",3),pn=n("p",null,"参考:",-1),on=n("h3",{id:"frontmatter",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),a(" frontmatter")],-1),cn=n("li",null,[n("p",null,[a("类型: "),n("code",null,"PageFrontmatter")])],-1),un=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 的 Frontmatter 。")],-1),dn=n("p",null,"参考:",-1),rn=l(` 示例:
'en-US'
'zh-CN'
# headers
- 类型:
PageHeader[]
`,3),hn=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 的小标题。")],-1),kn=n("p",null,"参考:",-1),vn=l(`interface PageHeader { + level: number; + title: string; + slug: string; + children: PageHeader[]; +} +
# data
- 类型:
PageData
`,3),mn=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 的数据。"),n("p",null,"Page 数据可以在客户端代码中使用。")],-1),bn=n("p",null,"参考:",-1),gn=l('interface PageData { + key: string; + path: string; + title: string; + lang: string; + frontmatter: PageFrontmatter; + headers: PageHeader[]; +} +
# content
类型:
string
详情:
该 Page 的未经渲染的原始内容。
# contentRendered
类型:
string
详情:
该 Page 的渲染后的内容。
# date
',5),_n=l("类型:
string
详情:
该 Page 的日期,遵从 'yyyy-MM-dd' 格式。
",3),fn=n("p",null,"参考:",-1),yn=n("h3",{id:"deps",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#deps","aria-hidden":"true"},"#"),a(" deps")],-1),wn=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string[]")])],-1),Pn=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 的依赖。"),n("p",null,[a("举例来说,如果在页面中导入了代码片段,那么被导入文件的绝对路径就会被添加到 "),n("code",null,"deps"),a(" 中。")])],-1),xn=n("p",null,"参考:",-1),An=l(` 示例:
'0000-00-00'
'2021-08-16
'# links
- 类型:
MarkdownLink[]
interface MarkdownLink { + raw: string; + relative: string; + absolute: string; +} +
详情:
该 Page 中的链接。
# pathInferred
`,5),Bn=l('类型:
string | null
详情:
该 Page 根据文件路径推断出的路由路径。
默认情况下,路由路径是根据 Markdown 源文件的相对文件路径推断出来的。然而,用户可能会显式指定页面路由,比如通过 permalink 来指定该页面最终使用的路由路径。因此我们在 Page 属性中保留推断出来的路径,以便于你在某些情况下可能会用到它。
如果该 Page 不是来自于 Markdown 源文件,那么该属性会为
null
。',3),En=n("p",null,"参考:",-1),zn=n("li",null,[n("a",{href:"#path"},"Node API > Page 属性 > path")],-1),Dn=n("h3",{id:"pathlocale",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pathlocale","aria-hidden":"true"},"#"),a(" pathLocale")],-1),Mn=l(" 示例:
'/'
'/foo.html'
类型:
string
详情:
该 Page 路由路径的 Locale 前缀。
它是根据页面的 Markdown 源文件相对路径、以及用户配置的
locales
的键推断得到的。",3),In=n("p",null,"参考:",-1),Fn=n("h3",{id:"permalink",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#permalink","aria-hidden":"true"},"#"),a(" permalink")],-1),Rn=n("li",null,[n("p",null,[a("类型: "),n("code",null,"string | null")])],-1),qn=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 的永久链接。")],-1),Nn=n("p",null,"参考:",-1),Vn=n("h3",{id:"routemeta",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#routemeta","aria-hidden":"true"},"#"),a(" routeMeta")],-1),Cn=n("li",null,[n("p",null,[a("类型: "),n("code",null,"Record 示例:
'/'
'/en/'
'/zh/'
")])],-1),Hn=n("li",null,[n("p",null,"详情:"),n("p",null,"附加到 vue-router 路由记录上的额外数据。")],-1),Ln=n("p",null,"参考:",-1),Sn={href:"https://router.vuejs.org/zh/api/#meta",target:"_blank",rel:"noopener noreferrer"},jn=l(' Route Meta 和 Page Data 的区别是什么?
Route Meta 和 Page Data 都可以在客户端代码中使用。然而, Route Meta 是附加在路由记录上的,因此当用户进入你的站点时,所有页面的 Route Meta 都会立即被加载。相比之下, Page Data 是存储在单独的文件中的,只有在用户进入对应页面时才会被加载。
因此,不建议在 Route Meta 中存储大量的信息,否则在站点有很多页面时,将会影响站点的初始加载速度。
# sfcBlocks
',2),Tn=n("li",null,[n("p",null,[a("类型: "),n("code",null,"MarkdownSfcBlocks")])],-1),On=n("li",null,[n("p",null,"详情:"),n("p",null,"该 Page 中提取出的 Vue SFC Blocks 。")],-1),Wn=n("p",null,"参考:",-1),Gn=l('# slug
类型:
string
详情:
该 Page 的 Slug 。
它是根据页面的 Markdown 源文件的文件名推断得到的。
# filePath
类型:
string | null
详情:
该 Page 的 Markdown 源文件的绝对路径。
如果该 Page 不是来自于 Markdown 源文件,那么该属性会为
null
。# filePathRelative
',6);function $n(Kn,Un){const o=i("NpmBadge"),p=i("ExternalLinkIcon"),e=i("RouterLink");return u(),d("div",null,[h,s(o,{package:"@vuepress/core"}),n("p",null,[a("Node API 是由 "),n("a",k,[a("@vuepress/core"),s(p)]),a(" 包提供的。它是 "),n("a",v,[a("vuepress"),s(p)]),a(" 包的依赖之一,当然你也可以单独安装它:")]),m,n("p",null,[s(e,{to:"/zh/reference/plugin-api.html"},{default:t(()=>[a("插件 API")]),_:1}),a(" 的所有 Hooks 中都可以获取到 App 实例。")]),b,n("ul",null,[g,n("li",null,[_,n("p",null,[a("由用户设置的站点数据,包含所有的 "),s(e,{to:"/zh/reference/config.html#%E7%AB%99%E7%82%B9%E9%85%8D%E7%BD%AE"},{default:t(()=>[a("站点配置")]),_:1}),a(" ,可以在客户端代码中使用。")])])]),f,n("ul",null,[y,n("li",null,[w,n("p",null,[a("用于解析 Markdown 内容的 "),n("a",P,[a("markdown-it"),s(p)]),a(" 实例。")]),n("p",null,[a("它仅在 "),s(e,{to:"/zh/reference/plugin-api.html#oninitialized"},{default:t(()=>[a("onInitialized")]),_:1}),a(" 以及之后的 Hooks 中才可用。")])])]),x,n("ul",null,[A,n("li",null,[B,E,n("p",null,[a("它仅在 "),s(e,{to:"/zh/reference/plugin-api.html#oninitialized"},{default:t(()=>[a("onInitialized")]),_:1}),a(" 以及之后的 Hooks 中才可用。")])])]),z,n("ul",null,[D,n("li",null,[M,n("ul",null,[n("li",null,[s(e,{to:"/zh/advanced/architecture.html#%E6%A0%B8%E5%BF%83%E6%B5%81%E7%A8%8B%E4%B8%8E-hooks"},{default:t(()=>[a("深入 > 架构 > 核心流程与 Hooks")]),_:1})])])])]),I,n("ul",null,[F,n("li",null,[R,n("ul",null,[n("li",null,[s(e,{to:"/zh/advanced/architecture.html#%E6%A0%B8%E5%BF%83%E6%B5%81%E7%A8%8B%E4%B8%8E-hooks"},{default:t(()=>[a("深入 > 架构 > 核心流程与 Hooks")]),_:1})])])])]),q,n("ul",null,[N,n("li",null,[V,n("ul",null,[n("li",null,[s(e,{to:"/zh/advanced/architecture.html#%E6%A0%B8%E5%BF%83%E6%B5%81%E7%A8%8B%E4%B8%8E-hooks"},{default:t(()=>[a("深入 > 架构 > 核心流程与 Hooks")]),_:1})])])])]),C,n("ul",null,[H,n("li",null,[L,n("ul",null,[n("li",null,[s(e,{to:"/zh/advanced/architecture.html#%E6%A0%B8%E5%BF%83%E6%B5%81%E7%A8%8B%E4%B8%8E-hooks"},{default:t(()=>[a("深入 > 架构 > 核心流程与 Hooks")]),_:1})])])])]),S,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[j,n("li",null,[s(e,{to:"/zh/advanced/cookbook/adding-extra-pages.html"},{default:t(()=>[a("Cookbook > 添加额外页面")]),_:1})])])])]),T,O,n("ul",null,[W,n("li",null,[G,$,n("p",null,[a("Page Key 会被用作页面路由的 "),n("a",K,[a("name"),s(p)]),a("。")])]),n("li",null,[U,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/components.html#content"},{default:t(()=>[a("Built-in Components > Content")]),_:1})])])])]),X,n("ul",null,[Y,Z,n("li",null,[J,n("ul",null,[n("li",null,[s(e,{to:"/zh/guide/page.html#%E8%B7%AF%E7%94%B1"},{default:t(()=>[a("指南 > 页面 > 路由")]),_:1})]),Q])])]),nn,n("ul",null,[an,sn,n("li",null,[en,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/frontmatter.html#title"},{default:t(()=>[a("Frontmatter > title")]),_:1})])])])]),tn,n("ul",null,[ln,n("li",null,[pn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/frontmatter.html#title"},{default:t(()=>[a("Frontmatter > lang")]),_:1})])])])]),on,n("ul",null,[cn,un,n("li",null,[dn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/frontmatter.html"},{default:t(()=>[a("Frontmatter")]),_:1})])])])]),rn,n("ul",null,[hn,n("li",null,[kn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/config.html#markdown-headers"},{default:t(()=>[a("配置 > markdown.headers")]),_:1})])])])]),vn,n("ul",null,[mn,n("li",null,[bn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/client-api.html#usepagedata"},{default:t(()=>[a("客户端 API > usePageData")]),_:1})]),n("li",null,[s(e,{to:"/zh/reference/plugin-api.html#extendspage"},{default:t(()=>[a("插件 API > extendsPage")]),_:1})])])])]),gn,n("ul",null,[_n,n("li",null,[fn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/frontmatter.html#date"},{default:t(()=>[a("Frontmatter > date")]),_:1})])])])]),yn,n("ul",null,[wn,Pn,n("li",null,[xn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/config.html#markdown-importcode"},{default:t(()=>[a("配置 > markdown.importCode")]),_:1})])])])]),An,n("ul",null,[Bn,n("li",null,[En,n("ul",null,[n("li",null,[s(e,{to:"/zh/guide/page.html#%E8%B7%AF%E7%94%B1"},{default:t(()=>[a("指南 > 页面 > 路由")]),_:1})]),zn])])]),Dn,n("ul",null,[Mn,n("li",null,[In,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/config.html#locales"},{default:t(()=>[a("配置 > locales")]),_:1})])])])]),Fn,n("ul",null,[Rn,qn,n("li",null,[Nn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/frontmatter.html#permalink"},{default:t(()=>[a("Frontmatter > permalink")]),_:1})]),n("li",null,[s(e,{to:"/zh/reference/frontmatter.html#permalinkpattern"},{default:t(()=>[a("Frontmatter > permalinkPattern")]),_:1})])])])]),Vn,n("ul",null,[Cn,Hn,n("li",null,[Ln,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/frontmatter.html#routemeta"},{default:t(()=>[a("Frontmatter > routeMeta")]),_:1})]),n("li",null,[n("a",Sn,[a("vue-router > API 参考 > RouteRecordRaw > meta"),s(p)])])])])]),jn,n("ul",null,[Tn,On,n("li",null,[Wn,n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/config.html#markdown-sfc"},{default:t(()=>[a("配置 > markdown.sfc")]),_:1})])])])]),Gn])}const Yn=c(r,[["render",$n],["__file","node-api.html.vue"]]);export{Yn as default}; diff --git a/assets/node-api.html-85bdab9d.js b/assets/node-api.html-85bdab9d.js new file mode 100644 index 00000000..3010fc06 --- /dev/null +++ b/assets/node-api.html-85bdab9d.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-e19cff04","path":"/zh/reference/node-api.html","title":"Node API","lang":"zh-CN","frontmatter":{"icon":"fa6-brands:node-js","description":"Node API 是由 @vuepress/core (https://www.npmjs.com/package/@vuepress/core) 包提供的。它是 vuepress (https://www.npmjs.com/package/vuepress) 包的依赖之一,当然你也可以单独安装它: App 插件 API (./plugin-api....","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/node-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/node-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Node API"}],["meta",{"property":"og:description","content":"Node API 是由 @vuepress/core (https://www.npmjs.com/package/@vuepress/core) 包提供的。它是 vuepress (https://www.npmjs.com/package/vuepress) 包的依赖之一,当然你也可以单独安装它: App 插件 API (./plugin-api...."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Node API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"App","slug":"app","link":"#app","children":[{"level":3,"title":"createBuildApp","slug":"createbuildapp","link":"#createbuildapp","children":[]},{"level":3,"title":"createDevApp","slug":"createdevapp","link":"#createdevapp","children":[]}]},{"level":2,"title":"App 属性","slug":"app-属性","link":"#app-属性","children":[{"level":3,"title":"options","slug":"options","link":"#options","children":[]},{"level":3,"title":"siteData","slug":"sitedata","link":"#sitedata","children":[]},{"level":3,"title":"version","slug":"version","link":"#version","children":[]},{"level":3,"title":"env.isBuild","slug":"env-isbuild","link":"#env-isbuild","children":[]},{"level":3,"title":"env.isDev","slug":"env-isdev","link":"#env-isdev","children":[]},{"level":3,"title":"env.isDebug","slug":"env-isdebug","link":"#env-isdebug","children":[]},{"level":3,"title":"markdown","slug":"markdown","link":"#markdown","children":[]},{"level":3,"title":"pages","slug":"pages","link":"#pages","children":[]}]},{"level":2,"title":"App 方法","slug":"app-方法","link":"#app-方法","children":[{"level":3,"title":"dir","slug":"dir","link":"#dir","children":[]},{"level":3,"title":"writeTemp","slug":"writetemp","link":"#writetemp","children":[]},{"level":3,"title":"init","slug":"init","link":"#init","children":[]},{"level":3,"title":"prepare","slug":"prepare","link":"#prepare","children":[]},{"level":3,"title":"build","slug":"build","link":"#build","children":[]},{"level":3,"title":"dev","slug":"dev","link":"#dev","children":[]}]},{"level":2,"title":"Page","slug":"page","link":"#page","children":[{"level":3,"title":"createPage","slug":"createpage","link":"#createpage","children":[]}]},{"level":2,"title":"Page 属性","slug":"page-属性","link":"#page-属性","children":[{"level":3,"title":"key","slug":"key","link":"#key","children":[]},{"level":3,"title":"path","slug":"path","link":"#path","children":[]},{"level":3,"title":"title","slug":"title","link":"#title","children":[]},{"level":3,"title":"lang","slug":"lang","link":"#lang","children":[]},{"level":3,"title":"frontmatter","slug":"frontmatter","link":"#frontmatter","children":[]},{"level":3,"title":"headers","slug":"headers","link":"#headers","children":[]},{"level":3,"title":"data","slug":"data","link":"#data","children":[]},{"level":3,"title":"content","slug":"content","link":"#content","children":[]},{"level":3,"title":"contentRendered","slug":"contentrendered","link":"#contentrendered","children":[]},{"level":3,"title":"date","slug":"date","link":"#date","children":[]},{"level":3,"title":"deps","slug":"deps","link":"#deps","children":[]},{"level":3,"title":"links","slug":"links","link":"#links","children":[]},{"level":3,"title":"pathInferred","slug":"pathinferred","link":"#pathinferred","children":[]},{"level":3,"title":"pathLocale","slug":"pathlocale","link":"#pathlocale","children":[]},{"level":3,"title":"permalink","slug":"permalink","link":"#permalink","children":[]},{"level":3,"title":"routeMeta","slug":"routemeta","link":"#routemeta","children":[]},{"level":3,"title":"sfcBlocks","slug":"sfcblocks","link":"#sfcblocks","children":[]},{"level":3,"title":"slug","slug":"slug","link":"#slug","children":[]},{"level":3,"title":"filePath","slug":"filepath","link":"#filepath","children":[]},{"level":3,"title":"filePathRelative","slug":"filepathrelative","link":"#filepathrelative","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":7.06,"words":2118},"filePathRelative":"zh/reference/node-api.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/node-api.html-d6fde234.js b/assets/node-api.html-d6fde234.js new file mode 100644 index 00000000..bcd027fa --- /dev/null +++ b/assets/node-api.html-d6fde234.js @@ -0,0 +1,104 @@ +import{_ as c,W as r,X as d,Y as a,$ as n,a0 as e,Z as t,a1 as l,D as o}from"./framework-46b0e263.js";const u={},h=n("h1",{id:"node-api",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#node-api","aria-hidden":"true"},"#"),e(" Node API")],-1),k={href:"https://www.npmjs.com/package/@vuepress/core",target:"_blank",rel:"noopener noreferrer"},v={href:"https://www.npmjs.com/package/vuepress",target:"_blank",rel:"noopener noreferrer"},m=l(`
类型:
string | null
详情:
该 Page 的 Markdown 源文件的相对路径。
如果该 Page 不是来自于 Markdown 源文件,那么该属性会为
null
。npm i -D @vuepress/core@next +
# App
`,2),f=l(`The
BuildApp
andDevApp
share almost the same properties and methods, except build and dev method.# createBuildApp
- Signature:
const createBuildApp: (config: AppConfig) => BuildApp; +
- Parameters:
Parameter Type Description config AppConfig
Config to create a VuePress app.
Details:
Create a build mode app instance, which is used for building static files.
Example:
const build = async () => { + const app = createBuildApp({ + // ...options + }); + + // initialize and prepare + await app.init(); + await app.prepare(); + + // build + await app.build(); + + // process onGenerated hook + await app.pluginApi.hooks.onGenerated.process(app); +}; +
- Also see:
# createDevApp
- Signature:
const createDevApp: (config: AppConfig) => DevApp; +
- Parameters:
Parameter Type Description config AppConfig
Config to create a VuePress app.
Details:
Create a dev mode app instance, which is used for starting a dev server.
Example:
const dev = async () => { + const app = createDevApp({ + // ...options + }); + + // initialize and prepare + await app.init(); + await app.prepare(); + + // start dev server + const closeDevServer = await app.dev(); + + // set up file watchers + const watchers = []; + + // restart dev server + const restart = async () => { + await Promise.all([ + // close all watchers + ...watchers.map((item) => item.close()), + // close current dev server + closeDevServer(), + ]); + await dev(); + }; + + // process onWatched hook + await app.pluginApi.hooks.onWatched.process(app, watchers, restart); +}; +
- Also see:
# App Properties
# options
Type:
AppOptions
Details:
Options of VuePress app.
The options come from the
config
argument in createBuildApp / createDevApp, while all optional fields will be filled with a default value.# siteData
`,21),g=n("li",null,[n("p",null,[e("Type: "),n("code",null,"SiteData")])],-1),b=n("p",null,"Details:",-1),_=l('# version
Type:
string
Details:
Version of VuePress app, i.e. version of
@vuepress/core
package.# env.isBuild
Type:
boolean
Details:
Environment flag used to identify whether the app is running in build mode, i.e. whether a BuildApp instance.
# env.isDev
Type:
boolean
Details:
Environment flag used to identify whether the app is running in dev mode, i.e. whether a DevApp instance.
# env.isDebug
Type:
boolean
Details:
Environment flag used to identify whether the debug mode is enabled.
# markdown
',9),y=n("li",null,[n("p",null,[e("Type: "),n("code",null,"MarkdownIt")])],-1),w=n("p",null,"Details:",-1),x={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},A=n("h3",{id:"pages",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pages","aria-hidden":"true"},"#"),e(" pages")],-1),P=n("li",null,[n("p",null,[e("Type: "),n("code",null,"Page[]")])],-1),D=n("p",null,"Details:",-1),T=n("p",null,[e("The "),n("a",{href:"#page"},"Page"),e(" object array.")],-1),I=l(`# App Methods
# dir
Utils:
dir.cache()
: resolve to cache directorydir.temp()
: resolve to temp directorydir.source()
: resolve to source directorydir.dest()
: resolve to dest directorydir.client()
: resolve to@vuepress/client
directorydir.public()
: resolve to public directorySignature:
type AppDirFunction = (...args: string[]) => string; +
Details:
Utils to resolve the absolute file path in corresponding directory.
If you don't provide any arguments, it will return the absolute path of the directory.
Example:
// resolve the absolute file path of the \`\${sourceDir}/README.md\` +const homeSourceFile = app.dir.source("README.md"); +
# writeTemp
- Signature:
writeTemp(file: string, content: string): Promise<string> +
- Parameters:
Parameter Type Description file string
Filepath of the temp file that going to be written. Relative to temp directory. content string
Content of the temp file that going to be written.
Details:
A method to write temp file.
The written file could be imported via
@temp
alias in client files.Example:
export default { + // write temp file in onPrepared hook + async onPrepared() { + await app.writeTemp("foo.js", "export const foo = 'bar'"); + }, +}; +
// import temp file in client code +import { foo } from "@temp/foo"; +
# init
- Signature:
`,17),C=n("li",null,[n("p",null,"Details:"),n("p",null,"Initialize VuePress app.")],-1),E=n("p",null,"Also see:",-1),M=l(`init(): Promise<void> +
# prepare
- Signature:
`,3),S=n("li",null,[n("p",null,"Details:"),n("p",null,"Prepare client temp files.")],-1),B=n("p",null,"Also see:",-1),R=l(`prepare(): Promise<void> +
# build
- Signature:
`,3),F=n("li",null,[n("p",null,"Details:"),n("p",null,"Generate static site files."),n("p",null,[e("This method is only available in "),n("code",null,"BuildApp"),e(".")])],-1),N=n("p",null,"Also see:",-1),q=n("li",null,[n("a",{href:"#createbuildapp"},"Node API > App > createBuildApp")],-1),V=l(`build(): Promise<void> +
# dev
- Signature:
`,3),H=n("li",null,[n("p",null,"Details:"),n("p",null,"Start dev server."),n("p",null,[e("This method is only available in "),n("code",null,"DevApp"),e(".")])],-1),z=n("p",null,"Also see:",-1),L=n("li",null,[n("a",{href:"#createdevapp"},"Node API > App > createDevApp")],-1),j=l(`dev(): Promise<() => Promise<void>> +
# Page
# createPage
- Signature:
const createPage: (app: App, options: PageOptions) => Promise<Page>; +
- Parameters:
Parameter Type Description app App
The VuePress app instance. options PageOptions
Options to create VuePress page.
Details:
Create a VuePress page object.
Example:
`,8),G=n("li",null,[n("a",{href:"#pages"},"Node API > App Properties > pages")],-1),O=n("h2",{id:"page-properties",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#page-properties","aria-hidden":"true"},"#"),e(" Page Properties")],-1),W=n("h3",{id:"key",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#key","aria-hidden":"true"},"#"),e(" key")],-1),U=n("li",null,[n("p",null,[e("Type: "),n("code",null,"string")])],-1),$=n("p",null,"Details:",-1),X=n("p",null,"Identifier of the page.",-1),Y={href:"https://router.vuejs.org/api/#name-2",target:"_blank",rel:"noopener noreferrer"},Z=n("p",null,"Also see:",-1),J=n("h3",{id:"path",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#path","aria-hidden":"true"},"#"),e(" path")],-1),K=n("li",null,[n("p",null,[e("Type: "),n("code",null,"string")])],-1),Q=n("li",null,[n("p",null,"Details:"),n("p",null,"Route path of the page.")],-1),nn=n("p",null,"Also see:",-1),en=n("li",null,[n("a",{href:"#pathinferred"},"Node API > Page Properties > pathInferred")],-1),an=n("h3",{id:"title",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#title","aria-hidden":"true"},"#"),e(" title")],-1),sn=n("li",null,[n("p",null,[e("Type: "),n("code",null,"string")])],-1),tn=n("li",null,[n("p",null,"Details:"),n("p",null,"Title of the page.")],-1),ln=n("p",null,"Also see:",-1),on=n("h3",{id:"lang",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#lang","aria-hidden":"true"},"#"),e(" lang")],-1),pn=l("import { createPage } from "@vuepress/core"; + +export default { + // create an extra page in onInitialized hook + async onInitialized(app) { + app.pages.push( + await createPage(app, { + path: "/foo.html", + frontmatter: { + layout: "Layout", + }, + content: \`\\ +# Foo Page + +Hello, world. +\`, + }) + ); + }, +}; +
Type:
string
Details:
Language of the page.
",3),cn=n("p",null,"Also see:",-1),rn=n("h3",{id:"frontmatter",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),e(" frontmatter")],-1),dn=n("li",null,[n("p",null,[e("Type: "),n("code",null,"PageFrontmatter")])],-1),un=n("li",null,[n("p",null,"Details:"),n("p",null,"Frontmatter of the page.")],-1),hn=n("p",null,"Also see:",-1),kn=l(` Example:
'en-US'
'zh-CN'
# headers
- Type:
PageHeader[]
`,3),vn=n("li",null,[n("p",null,"Details:"),n("p",null,"Headers of the page.")],-1),mn=n("p",null,"Also see:",-1),fn=l(`interface PageHeader { + level: number; + title: string; + slug: string; + children: PageHeader[]; +} +
# data
- Type:
PageData
`,3),gn=n("li",null,[n("p",null,"Details:"),n("p",null,"Data of the page."),n("p",null,"Page data would be available in client side.")],-1),bn=n("p",null,"Also see:",-1),_n=l('interface PageData { + key: string; + path: string; + title: string; + lang: string; + frontmatter: PageFrontmatter; + headers: PageHeader[]; +} +
# content
Type:
string
Details:
Raw content of the page.
# contentRendered
Type:
string
Details:
Rendered content of the page.
# date
',5),yn=l("Type:
string
Details:
Date of the page, in 'yyyy-MM-dd' format.
",3),wn=n("p",null,"Also see:",-1),xn=n("h3",{id:"deps",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#deps","aria-hidden":"true"},"#"),e(" deps")],-1),An=n("li",null,[n("p",null,[e("Type: "),n("code",null,"string[]")])],-1),Pn=n("li",null,[n("p",null,"Details:"),n("p",null,"Dependencies of the page."),n("p",null,[e("For example, if users import code snippet in the page, the absolute file path of the imported file would be added to "),n("code",null,"deps"),e(".")])],-1),Dn=n("p",null,"Also see:",-1),Tn=l(` Example:
'0000-00-00'
'2021-08-16
'# links
- Type:
MarkdownLink[]
interface MarkdownLink { + raw: string; + relative: string; + absolute: string; +} +
Details:
Links of the page.
# pathInferred
`,5),In=l('Type:
string | null
Details:
Route path of the page that inferred from file path.
By default, the route path is inferred from the relative file path of the Markdown source file. However, users may explicitly set the route path, e.g. permalink, which would be used as the final route path of the page. So we keep the inferred path as a page property in case you may need it.
It would be
null
if the page does not come from a Markdown source file.',3),Cn=n("p",null,"Also see:",-1),En=n("li",null,[n("a",{href:"#path"},"Node API > Page Properties > path")],-1),Mn=n("h3",{id:"pathlocale",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pathlocale","aria-hidden":"true"},"#"),e(" pathLocale")],-1),Sn=l(" Example:
'/'
'/foo.html'
Type:
string
Details:
Locale prefix of the page route path.
It is inferred from the relative file path of the Markdown source file and the key of
locales
option in user config.",3),Bn=n("p",null,"Also see:",-1),Rn=n("h3",{id:"permalink",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#permalink","aria-hidden":"true"},"#"),e(" permalink")],-1),Fn=n("li",null,[n("p",null,[e("Type: "),n("code",null,"string | null")])],-1),Nn=n("li",null,[n("p",null,"Details:"),n("p",null,"Permalink of the page.")],-1),qn=n("p",null,"Also see:",-1),Vn=n("h3",{id:"routemeta",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#routemeta","aria-hidden":"true"},"#"),e(" routeMeta")],-1),Hn=n("li",null,[n("p",null,[e("Type: "),n("code",null,"Record Example:
'/'
'/en/'
'/zh/'
")])],-1),zn=n("li",null,[n("p",null,"Details:"),n("p",null,"Custom data to be attached to the route record of vue-router.")],-1),Ln=n("p",null,"Also see:",-1),jn={href:"https://router.vuejs.org/api/#meta",target:"_blank",rel:"noopener noreferrer"},Gn=l(' What's the difference between route meta and page data?
Both route meta and page data is available in client side. However, route meta is attached to the route record, so the route meta of all pages would be loaded at once when users enter your site. In the contrast, page data is saved in separated files, which would be loaded only when users enter the corresponding page.
Therefore, it's not recommended to store large amounts of info into route meta, otherwise the initial loading speed will be affected a lot when your site has a large number of pages.
# sfcBlocks
',2),On=n("li",null,[n("p",null,[e("Type: "),n("code",null,"MarkdownSfcBlocks")])],-1),Wn=n("li",null,[n("p",null,"Details:"),n("p",null,"Extracted vue SFC blocks of the page.")],-1),Un=n("p",null,"Also see:",-1),$n=l('# slug
Type:
string
Details:
Slug of the page.
It is inferred from the filename of the Markdown source file.
# filePath
Type:
string | null
Details:
Absolute path of the Markdown source file of the page.
It would be
null
if the page does not come from a Markdown source file.# filePathRelative
',6);function Xn(Yn,Zn){const p=o("NpmBadge"),i=o("ExternalLinkIcon"),s=o("RouterLink");return r(),d("div",null,[h,a(p,{package:"@vuepress/core"}),n("p",null,[e("Node API is provided by "),n("a",k,[e("@vuepress/core"),a(i)]),e(" package. It is a dependency of the "),n("a",v,[e("vuepress"),a(i)]),e(" package, and you can also install it separately:")]),m,n("p",null,[e("The app instance is available in all hooks of "),a(s,{to:"/reference/plugin-api.html"},{default:t(()=>[e("Plugin API")]),_:1}),e(".")]),f,n("ul",null,[g,n("li",null,[b,n("p",null,[e("Site data that set by user, including all the "),a(s,{to:"/reference/config.html#site-config"},{default:t(()=>[e("site config")]),_:1}),e(", which will be used in client side.")])])]),_,n("ul",null,[y,n("li",null,[w,n("p",null,[e("The "),n("a",x,[e("markdown-it"),a(i)]),e(" instance used for parsing markdown content.")]),n("p",null,[e("It is only available in and after "),a(s,{to:"/reference/plugin-api.html#oninitialized"},{default:t(()=>[e("onInitialized")]),_:1}),e(" hook.")])])]),A,n("ul",null,[P,n("li",null,[D,T,n("p",null,[e("It is only available in and after "),a(s,{to:"/reference/plugin-api.html#oninitialized"},{default:t(()=>[e("onInitialized")]),_:1}),e(" hook.")])])]),I,n("ul",null,[C,n("li",null,[E,n("ul",null,[n("li",null,[a(s,{to:"/advanced/architecture.html#core-process-and-hooks"},{default:t(()=>[e("Advanced > Architecture > Core Process and Hooks")]),_:1})])])])]),M,n("ul",null,[S,n("li",null,[B,n("ul",null,[n("li",null,[a(s,{to:"/advanced/architecture.html#core-process-and-hooks"},{default:t(()=>[e("Advanced > Architecture > Core Process and Hooks")]),_:1})])])])]),R,n("ul",null,[F,n("li",null,[N,n("ul",null,[q,n("li",null,[a(s,{to:"/advanced/architecture.html#core-process-and-hooks"},{default:t(()=>[e("Advanced > Architecture > Core Process and Hooks")]),_:1})])])])]),V,n("ul",null,[H,n("li",null,[z,n("ul",null,[L,n("li",null,[a(s,{to:"/advanced/architecture.html#core-process-and-hooks"},{default:t(()=>[e("Advanced > Architecture > Core Process and Hooks")]),_:1})])])])]),j,n("ul",null,[n("li",null,[e("Also see: "),n("ul",null,[G,n("li",null,[a(s,{to:"/advanced/cookbook/adding-extra-pages.html"},{default:t(()=>[e("Cookbook > Adding Extra Pages")]),_:1})])])])]),O,W,n("ul",null,[U,n("li",null,[$,X,n("p",null,[e("The page key would be used as the "),n("a",Y,[e("name"),a(i)]),e(" of the page route.")])]),n("li",null,[Z,n("ul",null,[n("li",null,[a(s,{to:"/reference/components.html#content"},{default:t(()=>[e("Built-in Components > Content")]),_:1})])])])]),J,n("ul",null,[K,Q,n("li",null,[nn,n("ul",null,[n("li",null,[a(s,{to:"/guide/page.html#routing"},{default:t(()=>[e("Guide > Page > Routing")]),_:1})]),en])])]),an,n("ul",null,[sn,tn,n("li",null,[ln,n("ul",null,[n("li",null,[a(s,{to:"/reference/frontmatter.html#title"},{default:t(()=>[e("Frontmatter > title")]),_:1})])])])]),on,n("ul",null,[pn,n("li",null,[cn,n("ul",null,[n("li",null,[a(s,{to:"/reference/frontmatter.html#title"},{default:t(()=>[e("Frontmatter > lang")]),_:1})])])])]),rn,n("ul",null,[dn,un,n("li",null,[hn,n("ul",null,[n("li",null,[a(s,{to:"/reference/frontmatter.html"},{default:t(()=>[e("Frontmatter")]),_:1})])])])]),kn,n("ul",null,[vn,n("li",null,[mn,n("ul",null,[n("li",null,[a(s,{to:"/reference/config.html#markdown-headers"},{default:t(()=>[e("Config > markdown.headers")]),_:1})])])])]),fn,n("ul",null,[gn,n("li",null,[bn,n("ul",null,[n("li",null,[a(s,{to:"/reference/client-api.html#usepagedata"},{default:t(()=>[e("Client API > usePageData")]),_:1})]),n("li",null,[a(s,{to:"/reference/plugin-api.html#extendspage"},{default:t(()=>[e("Plugin API > extendsPage")]),_:1})])])])]),_n,n("ul",null,[yn,n("li",null,[wn,n("ul",null,[n("li",null,[a(s,{to:"/reference/frontmatter.html#date"},{default:t(()=>[e("Frontmatter > date")]),_:1})])])])]),xn,n("ul",null,[An,Pn,n("li",null,[Dn,n("ul",null,[n("li",null,[a(s,{to:"/reference/config.html#markdown-importcode"},{default:t(()=>[e("Config > markdown.importCode")]),_:1})])])])]),Tn,n("ul",null,[In,n("li",null,[Cn,n("ul",null,[n("li",null,[a(s,{to:"/guide/page.html#routing"},{default:t(()=>[e("Guide > Page > Routing")]),_:1})]),En])])]),Mn,n("ul",null,[Sn,n("li",null,[Bn,n("ul",null,[n("li",null,[a(s,{to:"/reference/config.html#locales"},{default:t(()=>[e("Config > locales")]),_:1})])])])]),Rn,n("ul",null,[Fn,Nn,n("li",null,[qn,n("ul",null,[n("li",null,[a(s,{to:"/reference/frontmatter.html#permalink"},{default:t(()=>[e("Frontmatter > permalink")]),_:1})]),n("li",null,[a(s,{to:"/reference/frontmatter.html#permalinkpattern"},{default:t(()=>[e("Frontmatter > permalinkPattern")]),_:1})])])])]),Vn,n("ul",null,[Hn,zn,n("li",null,[Ln,n("ul",null,[n("li",null,[a(s,{to:"/reference/frontmatter.html#routemeta"},{default:t(()=>[e("Frontmatter > routeMeta")]),_:1})]),n("li",null,[n("a",jn,[e("vue-router > API Reference > RouteRecordRaw > meta"),a(i)])])])])]),Gn,n("ul",null,[On,Wn,n("li",null,[Un,n("ul",null,[n("li",null,[a(s,{to:"/reference/config.html#markdown-sfc"},{default:t(()=>[e("Config > markdown.sfc")]),_:1})])])])]),$n])}const Kn=c(u,[["render",Xn],["__file","node-api.html.vue"]]);export{Kn as default}; diff --git a/assets/nprogress.html-1022e6a7.js b/assets/nprogress.html-1022e6a7.js new file mode 100644 index 00000000..1b7d1388 --- /dev/null +++ b/assets/nprogress.html-1022e6a7.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-46d4f19d","path":"/reference/plugin/nprogress.html","title":"nprogress","lang":"en-US","frontmatter":{"title":"nprogress","description":"Integrate nprogress (https://github.com/rstacruz/nprogress) into VuePress, which can provide a progress bar when navigating to another page. This plugin has been integrated into...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/nprogress.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/nprogress.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"nprogress"}],["meta",{"property":"og:description","content":"Integrate nprogress (https://github.com/rstacruz/nprogress) into VuePress, which can provide a progress bar when navigating to another page. This plugin has been integrated into..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"nprogress\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Styles","slug":"styles","link":"#styles","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.39,"words":118},"filePathRelative":"reference/plugin/nprogress.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/nprogress.html-64571246.js b/assets/nprogress.html-64571246.js new file mode 100644 index 00000000..6aa814c0 --- /dev/null +++ b/assets/nprogress.html-64571246.js @@ -0,0 +1,7 @@ +import{_ as i,W as p,X as c,a2 as n,Y as a,$ as s,a0 as e,a1 as l,D as t}from"./framework-46b0e263.js";const d={},u=s("h1",{id:"nprogress-plugin",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#nprogress-plugin","aria-hidden":"true"},"#"),e(" nprogress Plugin")],-1),g={href:"https://github.com/rstacruz/nprogress",target:"_blank",rel:"noopener noreferrer"},h=l(`
Type:
string | null
Details:
Relative path of the Markdown source file of the page.
It would be
null
if the page does not come from a Markdown source file.This plugin has been integrated into the default theme.
# Usage
npm i -D @vuepress/plugin-nprogress@next +
import { nprogressPlugin } from "@vuepress/plugin-nprogress"; + +export default { + plugins: [nprogressPlugin()], +}; +
# Styles
You can customize the style of the progress bar via CSS variables:
`,7);function m(v,k){const r=t("NpmBadge"),o=t("ExternalLinkIcon");return p(),c("div",null,[n(' `# nprogress` will be rendered as `File not found
`, and the id will conflict with the nprogress bar (stupid) '),n(" so we add a 'plugin' suffix in the h1 title, and use title frontmatter to set the page title "),u,a(r,{package:"@vuepress/plugin-nprogress"}),s("p",null,[e("Integrate "),s("a",g,[e("nprogress"),a(o)]),e(" into VuePress, which can provide a progress bar when navigating to another page.")]),h])}const f=i(d,[["render",m],["__file","nprogress.html.vue"]]);export{f as default}; diff --git a/assets/nprogress.html-aaaab1e3.js b/assets/nprogress.html-aaaab1e3.js new file mode 100644 index 00000000..a3d63c8a --- /dev/null +++ b/assets/nprogress.html-aaaab1e3.js @@ -0,0 +1,7 @@ +import{_ as p,W as c,X as i,a2 as e,Y as a,$ as n,a0 as s,a1 as l,D as t}from"./framework-46b0e263.js";const d={},u=n("h1",{id:"nprogress-插件",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#nprogress-插件","aria-hidden":"true"},"#"),s(" nprogress 插件")],-1),g={href:"https://github.com/rstacruz/nprogress",target:"_blank",rel:"noopener noreferrer"},h=l(`
该插件已经集成到默认主题中。
# 使用方法
npm i -D @vuepress/plugin-nprogress@next +
import { nprogressPlugin } from "@vuepress/plugin-nprogress"; + +export default { + plugins: [nprogressPlugin()], +}; +
# 样式
你可以通过 CSS 变量来自定义进度条的样式:
`,7);function m(v,k){const r=t("NpmBadge"),o=t("ExternalLinkIcon");return c(),i("div",null,[e(' `# nprogress` 会被渲染成 `File not found
` ,导致 id 和 nprogress 进度条冲突 (有点蠢) '),e(" 所以我们在 h1 标题后添加一个 '插件' 后缀,然后通过 title frontmatter 来设置页面标题 "),u,a(r,{package:"@vuepress/plugin-nprogress"}),n("p",null,[s("将 "),n("a",g,[s("nprogress"),a(o)]),s(" 集成到 VuePress 中,在切换到另一个页面时会展示进度条。")]),h])}const b=p(d,[["render",m],["__file","nprogress.html.vue"]]);export{b as default}; diff --git a/assets/nprogress.html-bcdc2bc9.js b/assets/nprogress.html-bcdc2bc9.js new file mode 100644 index 00000000..fbad8aa1 --- /dev/null +++ b/assets/nprogress.html-bcdc2bc9.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-9f56ece4","path":"/zh/reference/plugin/nprogress.html","title":"nprogress","lang":"zh-CN","frontmatter":{"title":"nprogress","description":"将 nprogress (https://github.com/rstacruz/nprogress) 集成到 VuePress 中,在切换到另一个页面时会展示进度条。 该插件已经集成到默认主题中。 使用方法 样式 你可以通过 CSS 变量来自定义进度条的样式: code css (@vuepress/plugin-nprogress/src/clie...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/nprogress.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/nprogress.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"nprogress"}],["meta",{"property":"og:description","content":"将 nprogress (https://github.com/rstacruz/nprogress) 集成到 VuePress 中,在切换到另一个页面时会展示进度条。 该插件已经集成到默认主题中。 使用方法 样式 你可以通过 CSS 变量来自定义进度条的样式: code css (@vuepress/plugin-nprogress/src/clie..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"nprogress\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"样式","slug":"样式","link":"#样式","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.52,"words":155},"filePathRelative":"zh/reference/plugin/nprogress.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/page.html-207516b6.js b/assets/page.html-207516b6.js new file mode 100644 index 00000000..359a4544 --- /dev/null +++ b/assets/page.html-207516b6.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4eaf9f84","path":"/guide/page.html","title":"Page","lang":"en-US","frontmatter":{"icon":"fa6-solid:file","description":"VuePress is markdown-centered. Each markdown file inside your project is a standalone page. Routing By default, the route path of a page is determined by the relative path of yo...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/page.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/page.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Page"}],["meta",{"property":"og:description","content":"VuePress is markdown-centered. Each markdown file inside your project is a standalone page. Routing By default, the route path of a page is determined by the relative path of yo..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Page\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Routing","slug":"routing","link":"#routing","children":[]},{"level":2,"title":"Frontmatter","slug":"frontmatter","link":"#frontmatter","children":[]},{"level":2,"title":"Content","slug":"content","link":"#content","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.33,"words":398},"filePathRelative":"guide/page.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/page.html-69e8d1e1.js b/assets/page.html-69e8d1e1.js new file mode 100644 index 00000000..a9fc19bf --- /dev/null +++ b/assets/page.html-69e8d1e1.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7a8fca2f","path":"/zh/guide/page.html","title":"页面","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:file","description":"VuePress 是以 Markdown 为中心的。你项目中的每一个 Markdown 文件都是一个单独的页面。 路由 默认情况下,页面的路由路径是根据你的 Markdown 文件的相对路径决定的。 假设这是你的 Markdown 文件所处的目录结构: 将 docs 目录作为你的 sourceDir (../reference/cli.md) ,例如你...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/page.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/page.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"页面"}],["meta",{"property":"og:description","content":"VuePress 是以 Markdown 为中心的。你项目中的每一个 Markdown 文件都是一个单独的页面。 路由 默认情况下,页面的路由路径是根据你的 Markdown 文件的相对路径决定的。 假设这是你的 Markdown 文件所处的目录结构: 将 docs 目录作为你的 sourceDir (../reference/cli.md) ,例如你..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"页面\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"路由","slug":"路由","link":"#路由","children":[]},{"level":2,"title":"Frontmatter","slug":"frontmatter","link":"#frontmatter","children":[]},{"level":2,"title":"内容","slug":"内容","link":"#内容","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.87,"words":560},"filePathRelative":"zh/guide/page.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/page.html-713a4212.js b/assets/page.html-713a4212.js new file mode 100644 index 00000000..8f302438 --- /dev/null +++ b/assets/page.html-713a4212.js @@ -0,0 +1,12 @@ +import{_ as r,W as l,X as c,$ as t,a0 as e,Y as n,Z as a,a1 as s,D as i}from"./framework-46b0e263.js";const u={},h=s(`
# Page
VuePress is markdown-centered. Each markdown file inside your project is a standalone page.
# Routing
By default, the route path of a page is determined by the relative path of your markdown file.
Assuming this is the directory structure of your markdown files:
`,6),m=t("code",null,"docs",-1),p=t("code",null,"vuepress dev docs",-1),f=s("└─ docs + ├─ guide + │ ├─ getting-started.md + │ └─ README.md + ├─ contributing.md + └─ README.md +
",1),_={class:"hint-container tip"},g=t("p",{class:"hint-container-title"},"Tips",-1),k=t("p",null,[e("By default, both "),t("code",null,"README.md"),e(" and "),t("code",null,"index.md"),e(" would be converted to "),t("code",null,"index.html"),e(" and generate a slash-ending route path. However, it might cause conflicts if you want to keep both of the two files.")],-1),v=t("code",null,"['**/*.md', '!**/README.md', '!.vuepress', '!node_modules']",-1),b=t("code",null,"README.md",-1),w=t("h2",{id:"frontmatter",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),e(" Frontmatter")],-1),y={href:"https://yaml.org/",target:"_blank",rel:"noopener noreferrer"},x=s(`
Relative Path Route Path /README.md
/
/index.md
/
/contributing.md
/contributing.html
/guide/README.md
/guide/
/guide/getting-started.md
/guide/getting-started.html
`,1),E=t("code",null,"lang",-1),M=t("code",null,"title",-1),R=t("code",null,"description",-1),V=t("p",null,"Also, VuePress has built-in support for some frontmatter fields, and your theme may have its own special frontmatter, too.",-1),A={class:"hint-container tip"},D=t("p",{class:"hint-container-title"},"Tips",-1),T=t("h2",{id:"content",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#content","aria-hidden":"true"},"#"),e(" Content")],-1),P=t("p",null,[e("The main content of your page is written in Markdown. VuePress will firstly transform your Markdown to HTML code, then treat the HTML code as "),t("code",null,""),e(" of Vue SFC.")],-1),C={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"};function L(B,F){const o=i("RouterLink"),d=i("ExternalLinkIcon");return l(),c("div",null,[h,t("p",null,[e("Take the "),m,e(" directory as your "),n(o,{to:"/reference/cli.html"},{default:a(()=>[e("sourceDir")]),_:1}),e(", e.g. you are running "),p,e(" command. Then the route paths of your markdown files would be:")]),f,t("div",_,[g,k,t("p",null,[e("In such case, you can set the "),n(o,{to:"/reference/config.html#pagepatterns"},{default:a(()=>[e("pagePatterns")]),_:1}),e(" to avoid one of them being processed by VuePress, e.g. use "),v,e(" to exclude all "),b,e(" files.")])]),w,t("p",null,[e("A markdown file could contain a "),t("a",y,[e("YAML"),n(d)]),e(" frontmatter. The frontmatter must be at the top of the Markdown file and must be wrapped with a couple of triple-dashed lines. Here is a basic example:")]),x,t("p",null,[e("You must have noticed that those fields are similar with the "),n(o,{to:"/guide/configuration.html#site-config"},{default:a(()=>[e("Site Config")]),_:1}),e(" in the "),n(o,{to:"/guide/configuration.html#config-file"},{default:a(()=>[e("Config File")]),_:1}),e(". You can override "),E,e(", "),M,e(", "),R,e(", etc., of current page via frontmatter. So you can take frontmatter as page scope config.")]),V,t("div",A,[D,t("p",null,[e("Check out the "),n(o,{to:"/reference/frontmatter.html"},{default:a(()=>[e("Frontmatter Reference")]),_:1}),e(" for a full list of VuePress built-in frontmatter.")]),t("p",null,[e("Check out the "),n(o,{to:"/reference/default-theme/frontmatter.html"},{default:a(()=>[e("Default Theme > Frontmatter Reference")]),_:1}),e(" for the frontmatter of default theme.")])]),T,P,t("p",null,[e("With the power of "),t("a",C,[e("markdown-it"),n(d)]),e(" and Vue template syntax, the basic Markdown can be extended a lot. Next, check out the "),n(o,{to:"/guide/markdown.html"},{default:a(()=>[e("Markdown")]),_:1}),e(" guide for all the extensions of Markdown in VuePress.")])])}const S=r(u,[["render",L],["__file","page.html.vue"]]);export{S as default}; diff --git a/assets/page.html-c8245648.js b/assets/page.html-c8245648.js new file mode 100644 index 00000000..e98142fd --- /dev/null +++ b/assets/page.html-c8245648.js @@ -0,0 +1,12 @@ +import{_ as i,W as l,X as c,$ as t,a0 as e,Y as n,Z as a,a1 as o,D as r}from"./framework-46b0e263.js";const u={},h=o(`--- +lang: en-US +title: Title of this page +description: Description of this page +--- +
# 页面
VuePress 是以 Markdown 为中心的。你项目中的每一个 Markdown 文件都是一个单独的页面。
# 路由
默认情况下,页面的路由路径是根据你的 Markdown 文件的相对路径决定的。
假设这是你的 Markdown 文件所处的目录结构:
`,6),m=t("code",null,"docs",-1),p=t("code",null,"vuepress dev docs",-1),_=o("└─ docs + ├─ guide + │ ├─ getting-started.md + │ └─ README.md + ├─ contributing.md + └─ README.md +
",1),g={class:"hint-container tip"},k=t("p",{class:"hint-container-title"},"提示",-1),f=t("p",null,[e("默认配置下, "),t("code",null,"README.md"),e(" 和 "),t("code",null,"index.md"),e(" 都会被转换成 "),t("code",null,"index.html"),e(" ,并且其对应的路由路径都是由斜杠结尾的。然而,如果你想同时保留这两个文件,就可能会造成冲突。")],-1),v=t("code",null,"['**/*.md', '!**/README.md', '!.vuepress', '!node_modules']",-1),b=t("code",null,"README.md",-1),E=t("h2",{id:"frontmatter",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#frontmatter","aria-hidden":"true"},"#"),e(" Frontmatter")],-1),M={href:"https://yaml.org/",target:"_blank",rel:"noopener noreferrer"},w=o(`
相对路径 路由路径 /README.md
/
/index.md
/
/contributing.md
/contributing.html
/guide/README.md
/guide/
/guide/getting-started.md
/guide/getting-started.html
`,1),x=t("code",null,"lang",-1),F=t("code",null,"title",-1),V=t("code",null,"description",-1),D=t("p",null,"同样的,VuePress 有一些内置支持的 Frontmatter 字段,而你使用的主题也可能有它自己的特殊 Frontmatter 。",-1),A={class:"hint-container tip"},R=t("p",{class:"hint-container-title"},"提示",-1),y=t("h2",{id:"内容",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#内容","aria-hidden":"true"},"#"),e(" 内容")],-1),z=t("p",null,[e("页面的主要内容是使用 Markdown 书写的。VuePress 首先会将 Markdown 转换为 HTML ,然后将 HTML 作为 Vue 单文件组件的 "),t("code",null,""),e(" 。")],-1),L={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"};function P(B,N){const d=r("RouterLink"),s=r("ExternalLinkIcon");return l(),c("div",null,[h,t("p",null,[e("将 "),m,e(" 目录作为你的 "),n(d,{to:"/zh/reference/cli.html"},{default:a(()=>[e("sourceDir")]),_:1}),e(" ,例如你在运行 "),p,e(" 命令。此时,你的 Markdown 文件对应的路由路径为:")]),_,t("div",g,[k,f,t("p",null,[e("在这种情况下,你可以设置 "),n(d,{to:"/zh/reference/config.html#pagepatterns"},{default:a(()=>[e("pagePatterns")]),_:1}),e(" 来避免某个文件被 VuePress 处理,例如使用 "),v,e(" 来排除所有的 "),b,e(" 文件。")])]),E,t("p",null,[e("Markdown 文件可以包含一个 "),t("a",M,[e("YAML"),n(s)]),e(" Frontmatter 。Frontmatter 必须在 Markdown 文件的顶部,并且被包裹在一对三短划线中间。下面是一个基本的示例:")]),w,t("p",null,[e("你肯定注意到 Frontmatter 中的字段和"),n(d,{to:"/zh/guide/configuration.html#config-file"},{default:a(()=>[e("配置文件")]),_:1}),e("中的"),n(d,{to:"/zh/guide/configuration.html#%E7%AB%99%E7%82%B9%E9%85%8D%E7%BD%AE"},{default:a(()=>[e("站点配置")]),_:1}),e("十分类似。你可以通过 Frontmatter 来覆盖当前页面的 "),x,e(", "),F,e(", "),V,e(" 等属性。因此,你可以把 Frontmatter 当作页面级作用域的配置。")]),D,t("div",A,[R,t("p",null,[e("前往 "),n(d,{to:"/zh/reference/config.html"},{default:a(()=>[e("Frontmatter 参考")]),_:1}),e(" 查看 VuePress 支持的 Frontmatter 配置。")]),t("p",null,[e("前往 "),n(d,{to:"/zh/reference/default-theme/frontmatter.html"},{default:a(()=>[e("默认主题 > Frontmatter 参考")]),_:1}),e(" 查看默认主题的 Frontmatter 配置。")])]),y,z,t("p",null,[e("借助 "),t("a",L,[e("markdown-it"),n(s)]),e(" 和 Vue 模板语法的能力,基础的 Markdown 可以得到很多的扩展功能。接下来,前往 "),n(d,{to:"/zh/guide/markdown.html"},{default:a(()=>[e("Markdown")]),_:1}),e(" 章节来了解 VuePress 中 Markdown 的扩展功能。")])])}const T=i(u,[["render",P],["__file","page.html.vue"]]);export{T as default}; diff --git a/assets/palette.html-56c56250.js b/assets/palette.html-56c56250.js new file mode 100644 index 00000000..6b0c9921 --- /dev/null +++ b/assets/palette.html-56c56250.js @@ -0,0 +1,39 @@ +import{_ as p,W as o,X as c,Y as a,$ as s,a0 as e,a1 as l,D as t}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"palette",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#palette","aria-hidden":"true"},"#"),e(" palette")],-1),u=l(`--- +lang: zh-CN +title: 页面的标题 +description: 页面的描述 +--- +
Provide palette support for your theme.
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.
For theme authors, this plugin will help you to provide styles customization for users.
# Usage
npm i -D @vuepress/plugin-palette@next +
import { palettePlugin } from "@vuepress/plugin-palette"; + +export default { + plugins: [ + palettePlugin({ + // options + }), + ], +}; +
# Palette and Style
This plugin will provide a
`,8),h={href:"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties",target:"_blank",rel:"noopener noreferrer"},v={href:"https://sass-lang.com/documentation/variables",target:"_blank",rel:"noopener noreferrer"},m={href:"http://lesscss.org/features/#variables-feature",target:"_blank",rel:"noopener noreferrer"},f={href:"https://stylus-lang.com/docs/variables.html",target:"_blank",rel:"noopener noreferrer"},k=l(`@vuepress/plugin-palette/palette
(palette file) and a@vuepress/plugin-palette/style
(style file) to be imported in your theme styles.The style file is used for overriding the default styles or adding extra styles, so it's likely to be imported at the end of your theme styles.
# Usage
Use this plugin in your theme, assuming you are using SASS:
export default { + // ... + plugins: [palettePlugin({ preset: "sass" })], +}; +
# Usage of Palette
Import the plugin's palette file where your theme needs to use the corresponding variables, such as in the
Layout.vue
file:<template> + <h1 class="palette-title">Hello, Palette!</h1> +</template> + +<style lang="scss"> +/* import variables from the plugin's palette file */ +@import "@vuepress/plugin-palette/palette"; + +/* set default value for variables */ +$color: red !default; + +/* use variables in your styles */ +.palette-title { + color: $color; +} +</style> +
Then users can customize variables in
.vuepress/styles/palette.scss
:$color: green; +
# Usage of Style
Import the plugin's style file after your theme's styles, for example, in the
clientConfigFile
:// 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 the default styles of your theme:h1 { + font-size: 2.5rem; +} +
# Options
# preset
Type:
'css' | 'sass' | 'less' | 'stylus'
Default:
'css'
Details:
Set preset for other options.
If you don't need advanced customization of the plugin, it's recommended to only set this option and omit other options.
# userPaletteFile
Type:
string
Default:
- css:
'.vuepress/styles/palette.css'
- sass:
'.vuepress/styles/palette.scss'
- less:
'.vuepress/styles/palette.less'
- stylus:
'.vuepress/styles/palette.styl'
Details:
File path of the user palette file, relative to source directory.
The default value depends on the preset option.
The 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'
- sass:
'styles/palette.scss'
- less:
'styles/palette.less'
- stylus:
'styles/palette.styl'
Details:
File path of the generated palette temp file, relative to temp directory.
The default value depends on the 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'
- sass:
'.vuepress/styles/index.scss'
- less:
'.vuepress/styles/index.less'
- stylus:
'.vuepress/styles/index.styl'
Details:
File path of the user style file, relative to source directory.
The default value depends on the preset option.
The 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'
- sass:
'styles/index.scss'
- less:
'styles/index.less'
- stylus:
'styles/index.styl'
Details:
File path of the generated style temp file, relative to temp directory.
The default value depends on the 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
`,27);function g(y,b){const i=t("NpmBadge"),n=t("ExternalLinkIcon");return o(),c("div",null,[d,a(i,{package:"@vuepress/plugin-palette"}),u,s("p",null,[e("The palette file is used for defining style variables, so it's likely to be imported at the beginning of your theme styles. For example, users can define "),s("a",h,[e("CSS variables"),a(n)]),e(", "),s("a",v,[e("SASS variables"),a(n)]),e(", "),s("a",m,[e("LESS variables"),a(n)]),e(" or "),s("a",f,[e("Stylus variables"),a(n)]),e(" in the palette, and then you can use those variables in your theme styles.")]),k])}const _=p(r,[["render",g],["__file","palette.html.vue"]]);export{_ as default}; diff --git a/assets/palette.html-5cc582af.js b/assets/palette.html-5cc582af.js new file mode 100644 index 00000000..77b14b59 --- /dev/null +++ b/assets/palette.html-5cc582af.js @@ -0,0 +1,39 @@ +import{_ as i,W as c,X as o,Y as a,$ as e,a0 as s,a1 as l,D as t}from"./framework-46b0e263.js";const r={},d=e("h1",{id:"palette",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#palette","aria-hidden":"true"},"#"),s(" palette")],-1),u=l(`
Type:
(filePath: string) => string
Default:
- css:
(filePath) => \`@import '\${filePath}';\\n\`
- sass:
(filePath) => \`@forward 'file:///\${filePath}';\\n\`
- less:
(filePath) => \`@import '\${filePath}';\\n\`
- stylus:
(filePath) => \`@require '\${filePath}';\\n\`
Details:
Function to generate import code.
The default value depends on the preset option.
This option is used for generating tempPaletteFile and tempStyleFile, and you don't need to change this option in most cases.
为你的主题提供调色板功能。
该插件主要用于开发主题,并且已经集成到默认主题中。大部分情况下你不需要直接使用它。
对于主题作者,该插件可以帮助你提供用户自定义样式的能力。
# 使用方法
npm i -D @vuepress/plugin-palette@next +
import { palettePlugin } from "@vuepress/plugin-palette"; + +export default { + plugins: [ + palettePlugin({ + // 配置项 + }), + ], +}; +
# 调色板和样式
该插件会提供一个
`,8),v={href:"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties",target:"_blank",rel:"noopener noreferrer"},k={href:"https://sass-lang.com/documentation/variables",target:"_blank",rel:"noopener noreferrer"},h={href:"http://lesscss.org/features/#variables-feature",target:"_blank",rel:"noopener noreferrer"},m={href:"https://stylus-lang.com/docs/variables.html",target:"_blank",rel:"noopener noreferrer"},g=l(`@vuepress/plugin-palette/palette
(调色板文件)和一个@vuepress/plugin-palette/style
(样式文件),用于在你的主题样式中引入。样式文件用于覆盖默认样式或添加额外样式,因此它一般会在你主题样式的末尾引入。
# 使用
在你的主题中使用该插件,假设你使用 SASS 作为 CSS 预处理器:
export default { + // ... + plugins: [palettePlugin({ preset: "sass" })], +}; +
# 使用调色板
在你主题需要使用对应变量的地方引入该插件的调色板文件,比如在
Layout.vue
中:<template> + <h1 class="palette-title">你好,调色板!</h1> +</template> + +<style lang="scss"> +/* 从该插件的调色板中引入变量 */ +@import "@vuepress/plugin-palette/palette"; + +/* 设置变量的默认值 */ +$color: red !default; + +/* 在你的样式中使用变量 */ +.palette-title { + color: $color; +} +</style> +
然后,用户就可以在
.vuepress/styles/palette.scss
中自定义变量:$color: green; +
# 使用样式
在你主题的样式之后引入该插件的样式文件,比如在
clientConfigFile
中:// 引入你主题本身的样式文件 +import "path/to/your/theme/style"; +// 引入该插件的样式文件 +import "@vuepress/plugin-palette/style"; +
然后,用户就可以在
.vuepress/styles/index.scss
中添加额外样式,并可以覆盖你主题本身的样式:h1 { + font-size: 2.5rem; +} +
# 配置项
# preset
类型:
'css' | 'sass' | 'less' | 'stylus'
默认值:
'css'
详情:
设置其他选项的预设。
如果你没有对该插件进行进阶定制化的需要,建议只设置该配置项并忽略其他选项。
# userPaletteFile
类型:
string
默认值:
- css:
'.vuepress/styles/palette.css'
- sass:
'.vuepress/styles/palette.scss'
- less:
'.vuepress/styles/palette.less'
- stylus:
'.vuepress/styles/palette.styl'
详情:
用户调色板文件的路径,是针对源文件目录的相对路径。
默认值依赖于 preset 配置项。
该文件用于用户定义样式变量,建议保持默认值作为约定的文件路径。
# tempPaletteFile
类型:
string
默认值:
- css:
'styles/palette.css'
- sass:
'styles/palette.scss'
- less:
'styles/palette.less'
- stylus:
'styles/palette.styl'
详情:
生成的调色板临时文件的路径,是针对临时文件文件目录的相对路径。
默认值依赖于 preset 配置项。
你应该使用
'@vuepress/plugin-palette/palette'
别名来引入调色板文件,因此在绝大多数情况下你不需要修改该配置项。# userStyleFile
类型:
string
默认值:
- css:
'.vuepress/styles/index.css'
- sass:
'.vuepress/styles/index.scss'
- less:
'.vuepress/styles/index.less'
- stylus:
'.vuepress/styles/index.styl'
详情:
用户样式文件的路径,是针对源文件目录的相对路径。
默认值依赖于 preset 配置项。
该文件用于用户覆盖默认样式和添加额外样式,建议保持默认值作为约定的文件路径。
# tempStyleFile
类型:
string
默认值:
- css:
'styles/index.css'
- sass:
'styles/index.scss'
- less:
'styles/index.less'
- stylus:
'styles/index.styl'
详情:
生成的样式临时文件的路径,是针对临时文件文件目录的相对路径。
默认值依赖于 preset 配置项。
你应该使用
'@vuepress/plugin-palette/style'
别名来引入样式文件,因此在绝大多数情况下你不需要修改该配置项。# importCode
`,27);function b(f,y){const p=t("NpmBadge"),n=t("ExternalLinkIcon");return c(),o("div",null,[d,a(p,{package:"@vuepress/plugin-palette"}),u,e("p",null,[s("调色板文件用于定义样式变量,因此它一般会在你主题样式的开头引入。举例来说,用户可以在调色板中定义 "),e("a",v,[s("CSS 变量"),a(n)]),s(" 、 "),e("a",k,[s("SASS 变量"),a(n)]),s(" 、 "),e("a",h,[s("LESS 变量"),a(n)]),s(" 或 "),e("a",m,[s("Stylus 变量"),a(n)]),s(" ,然后你可以在你的主题样式中使用这些变量。")]),g])}const _=i(r,[["render",b],["__file","palette.html.vue"]]);export{_ as default}; diff --git a/assets/palette.html-96b6024a.js b/assets/palette.html-96b6024a.js new file mode 100644 index 00000000..51ea1e60 --- /dev/null +++ b/assets/palette.html-96b6024a.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5fd3efae","path":"/zh/reference/plugin/palette.html","title":"palette","lang":"zh-CN","frontmatter":{"description":"为你的主题提供调色板功能。 该插件主要用于开发主题,并且已经集成到默认主题中。大部分情况下你不需要直接使用它。 对于主题作者,该插件可以帮助你提供用户自定义样式的能力。 使用方法 调色板和样式 该插件会提供一个 @vuepress/plugin-palette/palette (调色板文件)和一个 @vuepress/plugin-palette/st...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/palette.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/palette.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"palette"}],["meta",{"property":"og:description","content":"为你的主题提供调色板功能。 该插件主要用于开发主题,并且已经集成到默认主题中。大部分情况下你不需要直接使用它。 对于主题作者,该插件可以帮助你提供用户自定义样式的能力。 使用方法 调色板和样式 该插件会提供一个 @vuepress/plugin-palette/palette (调色板文件)和一个 @vuepress/plugin-palette/st..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"palette\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"调色板和样式","slug":"调色板和样式","link":"#调色板和样式","children":[]},{"level":2,"title":"使用","slug":"使用","link":"#使用","children":[{"level":3,"title":"使用调色板","slug":"使用调色板","link":"#使用调色板","children":[]},{"level":3,"title":"使用样式","slug":"使用样式","link":"#使用样式","children":[]}]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"preset","slug":"preset","link":"#preset","children":[]},{"level":3,"title":"userPaletteFile","slug":"userpalettefile","link":"#userpalettefile","children":[]},{"level":3,"title":"tempPaletteFile","slug":"temppalettefile","link":"#temppalettefile","children":[]},{"level":3,"title":"userStyleFile","slug":"userstylefile","link":"#userstylefile","children":[]},{"level":3,"title":"tempStyleFile","slug":"tempstylefile","link":"#tempstylefile","children":[]},{"level":3,"title":"importCode","slug":"importcode","link":"#importcode","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":3.55,"words":1066},"filePathRelative":"zh/reference/plugin/palette.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/palette.html-e4b95f90.js b/assets/palette.html-e4b95f90.js new file mode 100644 index 00000000..1570f40d --- /dev/null +++ b/assets/palette.html-e4b95f90.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-37c5e106","path":"/reference/plugin/palette.html","title":"palette","lang":"en-US","frontmatter":{"description":"Provide palette support for your theme. 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 c...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/palette.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/palette.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"palette"}],["meta",{"property":"og:description","content":"Provide palette support for your theme. 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 c..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"palette\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Palette and Style","slug":"palette-and-style","link":"#palette-and-style","children":[]},{"level":2,"title":"Usage","slug":"usage-1","link":"#usage-1","children":[{"level":3,"title":"Usage of Palette","slug":"usage-of-palette","link":"#usage-of-palette","children":[]},{"level":3,"title":"Usage of Style","slug":"usage-of-style","link":"#usage-of-style","children":[]}]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"preset","slug":"preset","link":"#preset","children":[]},{"level":3,"title":"userPaletteFile","slug":"userpalettefile","link":"#userpalettefile","children":[]},{"level":3,"title":"tempPaletteFile","slug":"temppalettefile","link":"#temppalettefile","children":[]},{"level":3,"title":"userStyleFile","slug":"userstylefile","link":"#userstylefile","children":[]},{"level":3,"title":"tempStyleFile","slug":"tempstylefile","link":"#tempstylefile","children":[]},{"level":3,"title":"importCode","slug":"importcode","link":"#importcode","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.44,"words":731},"filePathRelative":"reference/plugin/palette.md","localizedDate":"February 22, 2023","autoDesc":true}`);export{e as data}; diff --git a/assets/passing-data-to-client-code.html-74bf54bf.js b/assets/passing-data-to-client-code.html-74bf54bf.js new file mode 100644 index 00000000..4069e024 --- /dev/null +++ b/assets/passing-data-to-client-code.html-74bf54bf.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-10b13bae","path":"/zh/advanced/cookbook/passing-data-to-client-code.html","title":"向客户端代码传递数据","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:right-to-bracket","description":"我们知道,VuePress 插件入口和主题入口是在 Node 端处理的,但有时候你可能需要向客户端动态传递数据。例如,你希望在用户传入不同的选项时生成不同的数据。 使用 define Hook 插件 API 提供了一个 define (../../reference/plugin-api.md#define) Hook 来定义客户端代码中的全局常量。你...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/advanced/cookbook/passing-data-to-client-code.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/cookbook/passing-data-to-client-code.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"向客户端代码传递数据"}],["meta",{"property":"og:description","content":"我们知道,VuePress 插件入口和主题入口是在 Node 端处理的,但有时候你可能需要向客户端动态传递数据。例如,你希望在用户传入不同的选项时生成不同的数据。 使用 define Hook 插件 API 提供了一个 define (../../reference/plugin-api.md#define) Hook 来定义客户端代码中的全局常量。你..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"向客户端代码传递数据\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用 define Hook","slug":"使用-define-hook","link":"#使用-define-hook","children":[]},{"level":2,"title":"写入并加载临时文件","slug":"写入并加载临时文件","link":"#写入并加载临时文件","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.28,"words":384},"filePathRelative":"zh/advanced/cookbook/passing-data-to-client-code.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/passing-data-to-client-code.html-a8002c66.js b/assets/passing-data-to-client-code.html-a8002c66.js new file mode 100644 index 00000000..d19afc2b --- /dev/null +++ b/assets/passing-data-to-client-code.html-a8002c66.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3bc3633f","path":"/advanced/cookbook/passing-data-to-client-code.html","title":"Passing Data to Client Code","lang":"en-US","frontmatter":{"icon":"fa6-solid:right-to-bracket","description":"As we know, VuePress plugin entries and theme entries are processed in Node side, but sometimes you might need to pass data to client side. For example, you want to generate dif...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/cookbook/passing-data-to-client-code.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/cookbook/passing-data-to-client-code.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Passing Data to Client Code"}],["meta",{"property":"og:description","content":"As we know, VuePress plugin entries and theme entries are processed in Node side, but sometimes you might need to pass data to client side. For example, you want to generate dif..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Passing Data to Client Code\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Use define Hook","slug":"use-define-hook","link":"#use-define-hook","children":[]},{"level":2,"title":"Write and Load Temp Files","slug":"write-and-load-temp-files","link":"#write-and-load-temp-files","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.87,"words":260},"filePathRelative":"advanced/cookbook/passing-data-to-client-code.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/passing-data-to-client-code.html-e724cdf3.js b/assets/passing-data-to-client-code.html-e724cdf3.js new file mode 100644 index 00000000..1df455a4 --- /dev/null +++ b/assets/passing-data-to-client-code.html-e724cdf3.js @@ -0,0 +1,26 @@ +import{_ as o,W as c,X as i,$ as s,a0 as n,Y as e,Z as t,a1 as p,D as l}from"./framework-46b0e263.js";const u={},r=s("h1",{id:"向客户端代码传递数据",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#向客户端代码传递数据","aria-hidden":"true"},"#"),n(" 向客户端代码传递数据")],-1),d=s("p",null,"我们知道,VuePress 插件入口和主题入口是在 Node 端处理的,但有时候你可能需要向客户端动态传递数据。例如,你希望在用户传入不同的选项时生成不同的数据。",-1),k=s("h2",{id:"使用-define-hook",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#使用-define-hook","aria-hidden":"true"},"#"),n(" 使用 "),s("code",null,"define"),n(" Hook")],-1),v=p(`
类型:
(filePath: string) => string
默认值:
- css:
(filePath) => \`@import '\${filePath}';\\n\`
- sass:
(filePath) => \`@forward 'file:///\${filePath}';\\n\`
- less:
(filePath) => \`@import '\${filePath}';\\n\`
- stylus:
(filePath) => \`@require '\${filePath}';\\n\`
详情:
用于生成引入代码的函数。
默认值依赖于 preset 配置项。
该配置项用于生成 tempPaletteFile 和 tempStyleFile ,在绝大多数情况下你不需要修改该配置项。
首先,通过
define
Hook 定义一些常量:export default (options) => ({ + define: { + __FOO__: options.foo || "str", + __OBJ__: { + bar: options.bar || 123, + }, + }, +}); +
然后,在客户端代码中直接使用它们:
const foo = __FOO__; +const obj = __OBJ__; +
如果你在客户端代码中使用 TypeScript ,你可能需要手动声明这些全局常量的类型:
declare const __FOO__: string; +declare const __OBJ__: { bar: number }; +
# 写入并加载临时文件
如果你需要实现一些更复杂的功能,你可以写入临时文件,并在客户端代码中动态加载它们。
`,8),m=s("code",null,"foo.js",-1),_=p(`export default (options) => ({ + async onPrepared(app) { + // 写入临时文件 + await app.writeTemp( + "foo.js", + \`export const foo = \${JSON.stringify(options.foo)}\` + ); + }, +}); +
然后,在客户端代码中通过
@temp
别名来加载临时文件:import { foo } from "@temp/foo"; +
如果你在客户端代码中使用 TypeScript ,你可能需要手动声明这些临时模块的类型:
`,5);function b(g,f){const a=l("RouterLink");return c(),i("div",null,[r,d,k,s("p",null,[n("插件 API 提供了一个 "),e(a,{to:"/zh/reference/plugin-api.html#define"},{default:t(()=>[n("define")]),_:1}),n(" Hook 来定义客户端代码中的全局常量。你可以利用它来向客户端传递数据。")]),v,s("p",null,[n("首先,写入一个名为 "),m,n(" 的临时文件,它将会生成在 "),e(a,{to:"/zh/reference/config.html#temp"},{default:t(()=>[n("temp")]),_:1}),n(" 目录中:")]),_])}const y=o(u,[["render",b],["__file","passing-data-to-client-code.html.vue"]]);export{y as default}; diff --git a/assets/passing-data-to-client-code.html-e7881e68.js b/assets/passing-data-to-client-code.html-e7881e68.js new file mode 100644 index 00000000..b1adb376 --- /dev/null +++ b/assets/passing-data-to-client-code.html-e7881e68.js @@ -0,0 +1,26 @@ +import{_ as p,W as i,X as c,$ as s,a0 as n,Y as e,Z as t,a1 as o,D as l}from"./framework-46b0e263.js";const u={},d=s("h1",{id:"passing-data-to-client-code",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#passing-data-to-client-code","aria-hidden":"true"},"#"),n(" Passing Data to Client Code")],-1),r=s("p",null,"As we know, VuePress plugin entries and theme entries are processed in Node side, but sometimes you might need to pass data to client side. For example, you want to generate different data when users use different options.",-1),k=s("h2",{id:"use-define-hook",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#use-define-hook","aria-hidden":"true"},"#"),n(" Use "),s("code",null,"define"),n(" Hook")],-1),m=o(`declare module "@temp/foo" { + export const foo: string; +} +
First, define some constants in
define
hook:export default (options) => ({ + define: { + __FOO__: options.foo || "str", + __OBJ__: { + bar: options.bar || 123, + }, + }, +}); +
Then use them in client code directly:
const foo = __FOO__; +const obj = __OBJ__; +
If you are using TypeScript in client code, you may need to declare the types of the global constants manually:
declare const __FOO__: string; +declare const __OBJ__: { bar: number }; +
# Write and Load Temp Files
If you need to achieve some more complex features, you can write temp files and load them dynamically in client code.
`,8),v=s("code",null,"foo.js",-1),f=o(`export default (options) => ({ + async onPrepared(app) { + // write temp file + await app.writeTemp( + "foo.js", + \`export const foo = \${JSON.stringify(options.foo)}\` + ); + }, +}); +
Then, load the temp file via
@temp
alias in client code:import { foo } from "@temp/foo"; +
If you are using TypeScript in client code, you may need to declare the type of the temp module manually:
`,5);function h(b,g){const a=l("RouterLink");return i(),c("div",null,[d,r,k,s("p",null,[n("Plugin API provides a "),e(a,{to:"/reference/plugin-api.html#define"},{default:t(()=>[n("define")]),_:1}),n(" hook to define global constants for client code. You can make use of it to pass data to client.")]),m,s("p",null,[n("First, write a temp file "),v,n(", which will be generated in the "),e(a,{to:"/reference/config.html#temp"},{default:t(()=>[n("temp")]),_:1}),n(" directory:")]),f])}const _=p(u,[["render",h],["__file","passing-data-to-client-code.html.vue"]]);export{_ as default}; diff --git a/assets/photoswipe.esm-04fddac6.js b/assets/photoswipe.esm-04fddac6.js new file mode 100644 index 00000000..1a020f85 --- /dev/null +++ b/assets/photoswipe.esm-04fddac6.js @@ -0,0 +1,4 @@ +/*! + * PhotoSwipe 5.3.5 - https://photoswipe.com + * (c) 2023 Dmytro Semenov + */function m(r,t,i){const e=document.createElement(t);return r&&(e.className=r),i&&i.appendChild(e),e}function u(r,t){return r.x=t.x,r.y=t.y,t.id!==void 0&&(r.id=t.id),r}function M(r){r.x=Math.round(r.x),r.y=Math.round(r.y)}function A(r,t){const i=Math.abs(r.x-t.x),e=Math.abs(r.y-t.y);return Math.sqrt(i*i+e*e)}function x(r,t){return r.x===t.x&&r.y===t.y}function I(r,t,i){return Math.min(Math.max(r,t),i)}function b(r,t,i){let e=`translate3d(${r}px,${t||0}px,0)`;return i!==void 0&&(e+=` scale3d(${i},${i},1)`),e}function v(r,t,i,e){r.style.transform=b(t,i,e)}const U="cubic-bezier(.4,0,.22,1)";function R(r,t,i,e){r.style.transition=t?`${t} ${i}ms ${e||U}`:"none"}function L(r,t,i){r.style.width=typeof t=="number"?`${t}px`:t,r.style.height=typeof i=="number"?`${i}px`:i}function q(r){R(r)}function G(r){return"decode"in r?r.decode().catch(()=>{}):r.complete?Promise.resolve(r):new Promise((t,i)=>{r.onload=()=>t(r),r.onerror=i})}const f={IDLE:"idle",LOADING:"loading",LOADED:"loaded",ERROR:"error"};function K(r){return"button"in r&&r.button===1||r.ctrlKey||r.metaKey||r.altKey||r.shiftKey}function X(r,t,i=document){let e=[];if(r instanceof Element)e=[r];else if(r instanceof NodeList||Array.isArray(r))e=Array.from(r);else{const s=typeof r=="string"?r:t;s&&(e=Array.from(i.querySelectorAll(s)))}return e}function C(){return!!(navigator.vendor&&navigator.vendor.match(/apple/i))}let F=!1;try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:()=>{F=!0}}))}catch{}class Y{constructor(){this._pool=[]}add(t,i,e,s){this._toggleListener(t,i,e,s)}remove(t,i,e,s){this._toggleListener(t,i,e,s,!0)}removeAll(){this._pool.forEach(t=>{this._toggleListener(t.target,t.type,t.listener,t.passive,!0,!0)}),this._pool=[]}_toggleListener(t,i,e,s,n,o){if(!t)return;const a=n?"removeEventListener":"addEventListener";i.split(" ").forEach(h=>{if(h){o||(n?this._pool=this._pool.filter(d=>d.type!==h||d.listener!==e||d.target!==t):this._pool.push({target:t,type:h,listener:e,passive:s}));const c=F?{passive:s||!1}:!1;t[a](h,e,c)}})}}function B(r,t){if(r.getViewportSizeFn){const i=r.getViewportSizeFn(r,t);if(i)return i}return{x:document.documentElement.clientWidth,y:window.innerHeight}}function S(r,t,i,e,s){let n=0;if(t.paddingFn)n=t.paddingFn(i,e,s)[r];else if(t.padding)n=t.padding[r];else{const o="padding"+r[0].toUpperCase()+r.slice(1);t[o]&&(n=t[o])}return Number(n)||0}function N(r,t,i,e){return{x:t.x-S("left",r,t,i,e)-S("right",r,t,i,e),y:t.y-S("top",r,t,i,e)-S("bottom",r,t,i,e)}}class ${constructor(t){this.slide=t,this.currZoomLevel=1,this.center={x:0,y:0},this.max={x:0,y:0},this.min={x:0,y:0}}update(t){this.currZoomLevel=t,this.slide.width?(this._updateAxis("x"),this._updateAxis("y"),this.slide.pswp.dispatch("calcBounds",{slide:this.slide})):this.reset()}_updateAxis(t){const{pswp:i}=this.slide,e=this.slide[t==="x"?"width":"height"]*this.currZoomLevel,n=S(t==="x"?"left":"top",i.options,i.viewportSize,this.slide.data,this.slide.index),o=this.slide.panAreaSize[t];this.center[t]=Math.round((o-e)/2)+n,this.max[t]=e>o?Math.round(o-e)+n:this.center[t],this.min[t]=e>o?n:this.center[t]}reset(){this.center.x=0,this.center.y=0,this.max.x=0,this.max.y=0,this.min.x=0,this.min.y=0}correctPan(t,i){return I(i,this.max[t],this.min[t])}}const T=4e3;class k{constructor(t,i,e,s){this.pswp=s,this.options=t,this.itemData=i,this.index=e,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,i,e){const s={x:t,y:i};this.elementSize=s,this.panAreaSize=e;const n=e.x/s.x,o=e.y/s.y;this.fit=Math.min(1,ndeclare module "@temp/foo" { + export const foo: string; +} +
o?n:o),this.vFill=Math.min(1,o),this.initial=this._getInitial(),this.secondary=this._getSecondary(),this.max=Math.max(this.initial,this.secondary,this._getMax()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}_parseZoomLevelOption(t){const i=t+"ZoomLevel",e=this.options[i];if(e)return typeof e=="function"?e(this):e==="fill"?this.fill:e==="fit"?this.fit:Number(e)}_getSecondary(){let t=this._parseZoomLevelOption("secondary");return t||(t=Math.min(1,this.fit*3),this.elementSize&&t*this.elementSize.x>T&&(t=T/this.elementSize.x),t)}_getInitial(){return this._parseZoomLevelOption("initial")||this.fit}_getMax(){return this._parseZoomLevelOption("max")||Math.max(1,this.fit*4)}}class j{constructor(t,i,e){this.data=t,this.index=i,this.pswp=e,this.isActive=i===e.currIndex,this.currentResolution=0,this.panAreaSize={x:0,y:0},this.pan={x:0,y:0},this.isFirstSlide=this.isActive&&!e.opener.isOpen,this.zoomLevels=new k(e.options,t,i,e),this.pswp.dispatch("gettingData",{slide:this,data:this.data,index:i}),this.content=this.pswp.contentLoader.getContentBySlide(this),this.container=m("pswp__zoom-wrap","div"),this.holderElement=null,this.currZoomLevel=1,this.width=this.content.width,this.height=this.content.height,this.heavyAppended=!1,this.bounds=new $(this),this.prevDisplayedWidth=-1,this.prevDisplayedHeight=-1,this.pswp.dispatch("slideInit",{slide:this})}setIsActive(t){t&&!this.isActive?this.activate():!t&&this.isActive&&this.deactivate()}append(t){this.holderElement=t,this.container.style.transformOrigin="0 0",this.data&&(this.calculateSize(),this.load(),this.updateContentSize(),this.appendHeavy(),this.holderElement.appendChild(this.container),this.zoomAndPanToInitial(),this.pswp.dispatch("firstZoomPan",{slide:this}),this.applyCurrentZoomPan(),this.pswp.dispatch("afterSetContent",{slide:this}),this.isActive&&this.activate())}load(){this.content.load(!1),this.pswp.dispatch("slideLoad",{slide:this})}appendHeavy(){const{pswp:t}=this,i=!0;this.heavyAppended||!t.opener.isOpen||t.mainScroll.isShifted()||!this.isActive&&!i||this.pswp.dispatch("appendHeavy",{slide:this}).defaultPrevented||(this.heavyAppended=!0,this.content.append(),this.pswp.dispatch("appendHeavyContent",{slide:this}))}activate(){this.isActive=!0,this.appendHeavy(),this.content.activate(),this.pswp.dispatch("slideActivate",{slide:this})}deactivate(){this.isActive=!1,this.content.deactivate(),this.currZoomLevel!==this.zoomLevels.initial&&this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize(),this.pswp.dispatch("slideDeactivate",{slide:this})}destroy(){this.content.hasSlide=!1,this.content.remove(),this.container.remove(),this.pswp.dispatch("slideDestroy",{slide:this})}resize(){this.currZoomLevel===this.zoomLevels.initial||!this.isActive?(this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize()):(this.calculateSize(),this.bounds.update(this.currZoomLevel),this.panTo(this.pan.x,this.pan.y))}updateContentSize(t){const i=this.currentResolution||this.zoomLevels.initial;if(!i)return;const e=Math.round(this.width*i)||this.pswp.viewportSize.x,s=Math.round(this.height*i)||this.pswp.viewportSize.y;!this.sizeChanged(e,s)&&!t||this.content.setDisplayedSize(e,s)}sizeChanged(t,i){return t!==this.prevDisplayedWidth||i!==this.prevDisplayedHeight?(this.prevDisplayedWidth=t,this.prevDisplayedHeight=i,!0):!1}getPlaceholderElement(){var t;return(t=this.content.placeholder)==null?void 0:t.element}zoomTo(t,i,e,s){const{pswp:n}=this;if(!this.isZoomable()||n.mainScroll.isShifted())return;n.dispatch("beforeZoomTo",{destZoomLevel:t,centerPoint:i,transitionDuration:e}),n.animations.stopAllPan();const o=this.currZoomLevel;s||(t=I(t,this.zoomLevels.min,this.zoomLevels.max)),this.setZoomLevel(t),this.pan.x=this.calculateZoomToPanOffset("x",i,o),this.pan.y=this.calculateZoomToPanOffset("y",i,o),M(this.pan);const a=()=>{this._setResolution(t),this.applyCurrentZoomPan()};e?n.animations.startTransition({isPan:!0,name:"zoomTo",target:this.container,transform:this.getCurrentTransform(),onComplete:a,duration:e,easing:n.options.easing}):a()}toggleZoom(t){this.zoomTo(this.currZoomLevel===this.zoomLevels.initial?this.zoomLevels.secondary:this.zoomLevels.initial,t,this.pswp.options.zoomAnimationDuration)}setZoomLevel(t){this.currZoomLevel=t,this.bounds.update(this.currZoomLevel)}calculateZoomToPanOffset(t,i,e){if(this.bounds.max[t]-this.bounds.min[t]===0)return this.bounds.center[t];i||(i=this.pswp.getViewportCenterPoint()),e||(e=this.zoomLevels.initial);const n=this.currZoomLevel/e;return this.bounds.correctPan(t,(this.pan[t]-i[t])*n+i[t])}panTo(t,i){this.pan.x=this.bounds.correctPan("x",t),this.pan.y=this.bounds.correctPan("y",i),this.applyCurrentZoomPan()}isPannable(){return Boolean(this.width)&&this.currZoomLevel>this.zoomLevels.fit}isZoomable(){return Boolean(this.width)&&this.content.isZoomable()}applyCurrentZoomPan(){this._applyZoomTransform(this.pan.x,this.pan.y,this.currZoomLevel),this===this.pswp.currSlide&&this.pswp.dispatch("zoomPanUpdate",{slide:this})}zoomAndPanToInitial(){this.currZoomLevel=this.zoomLevels.initial,this.bounds.update(this.currZoomLevel),u(this.pan,this.bounds.center),this.pswp.dispatch("initialZoomPan",{slide:this})}_applyZoomTransform(t,i,e){e/=this.currentResolution||this.zoomLevels.initial,v(this.container,t,i,e)}calculateSize(){const{pswp:t}=this;u(this.panAreaSize,N(t.options,t.viewportSize,this.data,this.index)),this.zoomLevels.update(this.width,this.height,this.panAreaSize),t.dispatch("calcSlideSize",{slide:this})}getCurrentTransform(){const t=this.currZoomLevel/(this.currentResolution||this.zoomLevels.initial);return b(this.pan.x,this.pan.y,t)}_setResolution(t){t!==this.currentResolution&&(this.currentResolution=t,this.updateContentSize(),this.pswp.dispatch("resolutionChanged"))}}const Q=.35,J=.6,z=.4,O=.5;function tt(r,t){return r*t/(1-t)}class it{constructor(t){this.gestures=t,this.pswp=t.pswp,this.startPan={x:0,y:0}}start(){this.pswp.currSlide&&u(this.startPan,this.pswp.currSlide.pan),this.pswp.animations.stopAll()}change(){const{p1:t,prevP1:i,dragAxis:e}=this.gestures,{currSlide:s}=this.pswp;if(e==="y"&&this.pswp.options.closeOnVerticalDrag&&s&&s.currZoomLevel<=s.zoomLevels.fit&&!this.gestures.isMultitouch){const n=s.pan.y+(t.y-i.y);if(!this.pswp.dispatch("verticalDrag",{panY:n}).defaultPrevented){this._setPanWithFriction("y",n,J);const o=1-Math.abs(this._getVerticalDragRatio(s.pan.y));this.pswp.applyBgOpacity(o),s.applyCurrentZoomPan()}}else this._panOrMoveMainScroll("x")||(this._panOrMoveMainScroll("y"),s&&(M(s.pan),s.applyCurrentZoomPan()))}end(){const{velocity:t}=this.gestures,{mainScroll:i,currSlide:e}=this.pswp;let s=0;if(this.pswp.animations.stopAll(),i.isShifted()){const o=(i.x-i.getCurrSlideX())/this.pswp.viewportSize.x;t.x<-O&&o<0||t.x<.1&&o<-.5?(s=1,t.x=Math.min(t.x,0)):(t.x>O&&o>0||t.x>-.1&&o>.5)&&(s=-1,t.x=Math.max(t.x,0)),i.moveIndexBy(s,!0,t.x)}e&&e.currZoomLevel>e.zoomLevels.max||this.gestures.isMultitouch?this.gestures.zoomLevels.correctZoomPan(!0):(this._finishPanGestureForAxis("x"),this._finishPanGestureForAxis("y"))}_finishPanGestureForAxis(t){const{velocity:i}=this.gestures,{currSlide:e}=this.pswp;if(!e)return;const{pan:s,bounds:n}=e,o=s[t],a=this.pswp.bgOpacity<1&&t==="y",l=.995,h=o+tt(i[t],l);if(a){const g=this._getVerticalDragRatio(o),w=this._getVerticalDragRatio(h);if(g<0&&w<-z||g>0&&w>z){this.pswp.close();return}}const c=n.correctPan(t,h);if(o===c)return;const d=c===h?1:.82,p=this.pswp.bgOpacity,_=c-o;this.pswp.animations.startSpring({name:"panGesture"+t,isPan:!0,start:o,end:c,velocity:i[t],dampingRatio:d,onUpdate:g=>{if(a&&this.pswp.bgOpacity<1){const w=1-(c-g)/_;this.pswp.applyBgOpacity(I(p+(1-p)*w,0,1))}s[t]=Math.floor(g),e.applyCurrentZoomPan()}})}_panOrMoveMainScroll(t){const{p1:i,dragAxis:e,prevP1:s,isMultitouch:n}=this.gestures,{currSlide:o,mainScroll:a}=this.pswp,l=i[t]-s[t],h=a.x+l;if(!l||!o)return!1;if(t==="x"&&!o.isPannable()&&!n)return a.moveTo(h,!0),!0;const{bounds:c}=o,d=o.pan[t]+l;if(this.pswp.options.allowPanToNext&&e==="x"&&t==="x"&&!n){const p=a.getCurrSlideX(),_=a.x-p,g=l>0,w=!g;if(d>c.min[t]&&g){if(c.min[t]<=this.startPan[t])return a.moveTo(h,!0),!0;this._setPanWithFriction(t,d)}else if(d 0)return a.moveTo(Math.max(h,p),!0),!0;if(_<0)return a.moveTo(Math.min(h,p),!0),!0}else this._setPanWithFriction(t,d)}else t==="y"?!a.isShifted()&&c.min.y!==c.max.y&&this._setPanWithFriction(t,d):this._setPanWithFriction(t,d);return!1}_getVerticalDragRatio(t){var i;return(t-(((i=this.pswp.currSlide)==null?void 0:i.bounds.center.y)??0))/(this.pswp.viewportSize.y/3)}_setPanWithFriction(t,i,e){const{currSlide:s}=this.pswp;if(!s)return;const{pan:n,bounds:o}=s;if(o.correctPan(t,i)!==i||e){const l=Math.round(i-n[t]);n[t]+=l*(e||Q)}else n[t]=i}}const et=.05,st=.15;function E(r,t,i){return r.x=(t.x+i.x)/2,r.y=(t.y+i.y)/2,r}class nt{constructor(t){this.gestures=t,this._startPan={x:0,y:0},this._startZoomPoint={x:0,y:0},this._zoomPoint={x:0,y:0},this._wasOverFitZoomLevel=!1,this._startZoomLevel=1}start(){const{currSlide:t}=this.gestures.pswp;t&&(this._startZoomLevel=t.currZoomLevel,u(this._startPan,t.pan)),this.gestures.pswp.animations.stopAllPan(),this._wasOverFitZoomLevel=!1}change(){const{p1:t,startP1:i,p2:e,startP2:s,pswp:n}=this.gestures,{currSlide:o}=n;if(!o)return;const a=o.zoomLevels.min,l=o.zoomLevels.max;if(!o.isZoomable()||n.mainScroll.isShifted())return;E(this._startZoomPoint,i,s),E(this._zoomPoint,t,e);let h=1/A(i,s)*A(t,e)*this._startZoomLevel;if(h>o.zoomLevels.initial+o.zoomLevels.initial/15&&(this._wasOverFitZoomLevel=!0),hl&&(h=l+(h-l)*et);o.pan.x=this._calculatePanForZoomLevel("x",h),o.pan.y=this._calculatePanForZoomLevel("y",h),o.setZoomLevel(h),o.applyCurrentZoomPan()}end(){const{pswp:t}=this.gestures,{currSlide:i}=t;(!i||i.currZoomLevel e.zoomLevels.max?n=e.zoomLevels.max:(o=!1,n=s);const a=i.bgOpacity,l=i.bgOpacity<1,h=u({x:0,y:0},e.pan);let c=u({x:0,y:0},h);t&&(this._zoomPoint.x=0,this._zoomPoint.y=0,this._startZoomPoint.x=0,this._startZoomPoint.y=0,this._startZoomLevel=s,u(this._startPan,h)),o&&(c={x:this._calculatePanForZoomLevel("x",n),y:this._calculatePanForZoomLevel("y",n)}),e.setZoomLevel(n),c={x:e.bounds.correctPan("x",c.x),y:e.bounds.correctPan("y",c.y)},e.setZoomLevel(s);const d=!x(c,h);if(!d&&!o&&!l){e._setResolution(n),e.applyCurrentZoomPan();return}i.animations.stopAllPan(),i.animations.startSpring({isPan:!0,start:0,end:1e3,velocity:0,dampingRatio:1,naturalFrequency:40,onUpdate:p=>{if(p/=1e3,d||o){if(d&&(e.pan.x=h.x+(c.x-h.x)*p,e.pan.y=h.y+(c.y-h.y)*p),o){const _=s+(n-s)*p;e.setZoomLevel(_)}e.applyCurrentZoomPan()}l&&i.bgOpacity<1&&i.applyBgOpacity(I(a+(1-a)*p,0,1))},onComplete:()=>{e._setResolution(n),e.applyCurrentZoomPan()}})}}function Z(r){return!!r.target.closest(".pswp__container")}class ot{constructor(t){this.gestures=t}click(t,i){const e=i.target.classList,s=e.contains("pswp__img"),n=e.contains("pswp__item")||e.contains("pswp__zoom-wrap");s?this._doClickOrTapAction("imageClick",t,i):n&&this._doClickOrTapAction("bgClick",t,i)}tap(t,i){Z(i)&&this._doClickOrTapAction("tap",t,i)}doubleTap(t,i){Z(i)&&this._doClickOrTapAction("doubleTap",t,i)}_doClickOrTapAction(t,i,e){var l;const{pswp:s}=this.gestures,{currSlide:n}=s,o=t+"Action",a=s.options[o];if(!s.dispatch(o,{point:i,originalEvent:e}).defaultPrevented){if(typeof a=="function"){a.call(s,i,e);return}switch(a){case"close":case"next":s[a]();break;case"zoom":n==null||n.toggleZoom(i);break;case"zoom-or-close":n!=null&&n.isZoomable()&&n.zoomLevels.secondary!==n.zoomLevels.initial?n.toggleZoom(i):s.options.clickToCloseNonZoomable&&s.close();break;case"toggle-controls":(l=this.gestures.pswp.element)==null||l.classList.toggle("pswp--ui-visible");break}}}}const rt=10,at=300,ht=25;class lt{constructor(t){this.pswp=t,this.dragAxis=null,this.p1={x:0,y:0},this.p2={x:0,y:0},this.prevP1={x:0,y:0},this.prevP2={x:0,y:0},this.startP1={x:0,y:0},this.startP2={x:0,y:0},this.velocity={x:0,y:0},this._lastStartP1={x:0,y:0},this._intervalP1={x:0,y:0},this._numActivePoints=0,this._ongoingPointers=[],this._touchEventEnabled="ontouchstart"in window,this._pointerEventEnabled=!!window.PointerEvent,this.supportsTouch=this._touchEventEnabled||this._pointerEventEnabled&&navigator.maxTouchPoints>1,this._numActivePoints=0,this._intervalTime=0,this._velocityCalculated=!1,this.isMultitouch=!1,this.isDragging=!1,this.isZooming=!1,this.raf=null,this._tapTimer=null,this.supportsTouch||(t.options.allowPanToNext=!1),this.drag=new it(this),this.zoomLevels=new nt(this),this.tapHandler=new ot(this),t.on("bindEvents",()=>{t.events.add(t.scrollWrap,"click",this._onClick.bind(this)),this._pointerEventEnabled?this._bindEvents("pointer","down","up","cancel"):this._touchEventEnabled?(this._bindEvents("touch","start","end","cancel"),t.scrollWrap&&(t.scrollWrap.ontouchmove=()=>{},t.scrollWrap.ontouchend=()=>{})):this._bindEvents("mouse","down","up")})}_bindEvents(t,i,e,s){const{pswp:n}=this,{events:o}=n,a=s?t+s:"";o.add(n.scrollWrap,t+i,this.onPointerDown.bind(this)),o.add(window,t+"move",this.onPointerMove.bind(this)),o.add(window,t+e,this.onPointerUp.bind(this)),a&&o.add(n.scrollWrap,a,this.onPointerUp.bind(this))}onPointerDown(t){const i=t.type==="mousedown"||t.pointerType==="mouse";if(i&&t.button>0)return;const{pswp:e}=this;if(!e.opener.isOpen){t.preventDefault();return}e.dispatch("pointerDown",{originalEvent:t}).defaultPrevented||(i&&(e.mouseDetected(),this._preventPointerEventBehaviour(t)),e.animations.stopAll(),this._updatePoints(t,"down"),this._numActivePoints===1&&(this.dragAxis=null,u(this.startP1,this.p1)),this._numActivePoints>1?(this._clearTapTimer(),this.isMultitouch=!0):this.isMultitouch=!1)}onPointerMove(t){t.preventDefault(),this._numActivePoints&&(this._updatePoints(t,"move"),!this.pswp.dispatch("pointerMove",{originalEvent:t}).defaultPrevented&&(this._numActivePoints===1&&!this.isDragging?(this.dragAxis||this._calculateDragDirection(),this.dragAxis&&!this.isDragging&&(this.isZooming&&(this.isZooming=!1,this.zoomLevels.end()),this.isDragging=!0,this._clearTapTimer(),this._updateStartPoints(),this._intervalTime=Date.now(),this._velocityCalculated=!1,u(this._intervalP1,this.p1),this.velocity.x=0,this.velocity.y=0,this.drag.start(),this._rafStopLoop(),this._rafRenderLoop())):this._numActivePoints>1&&!this.isZooming&&(this._finishDrag(),this.isZooming=!0,this._updateStartPoints(),this.zoomLevels.start(),this._rafStopLoop(),this._rafRenderLoop())))}_finishDrag(){this.isDragging&&(this.isDragging=!1,this._velocityCalculated||this._updateVelocity(!0),this.drag.end(),this.dragAxis=null)}onPointerUp(t){this._numActivePoints&&(this._updatePoints(t,"up"),!this.pswp.dispatch("pointerUp",{originalEvent:t}).defaultPrevented&&(this._numActivePoints===0&&(this._rafStopLoop(),this.isDragging?this._finishDrag():!this.isZooming&&!this.isMultitouch&&this._finishTap(t)),this._numActivePoints<2&&this.isZooming&&(this.isZooming=!1,this.zoomLevels.end(),this._numActivePoints===1&&(this.dragAxis=null,this._updateStartPoints()))))}_rafRenderLoop(){(this.isDragging||this.isZooming)&&(this._updateVelocity(),this.isDragging?x(this.p1,this.prevP1)||this.drag.change():(!x(this.p1,this.prevP1)||!x(this.p2,this.prevP2))&&this.zoomLevels.change(),this._updatePrevPoints(),this.raf=requestAnimationFrame(this._rafRenderLoop.bind(this)))}_updateVelocity(t){const i=Date.now(),e=i-this._intervalTime;e<50&&!t||(this.velocity.x=this._getVelocity("x",e),this.velocity.y=this._getVelocity("y",e),this._intervalTime=i,u(this._intervalP1,this.p1),this._velocityCalculated=!0)}_finishTap(t){const{mainScroll:i}=this.pswp;if(i.isShifted()){i.moveIndexBy(0,!0);return}if(t.type.indexOf("cancel")>0)return;if(t.type==="mouseup"||t.pointerType==="mouse"){this.tapHandler.click(this.startP1,t);return}const e=this.pswp.options.doubleTapAction?at:0;this._tapTimer?(this._clearTapTimer(),A(this._lastStartP1,this.startP1) {this.tapHandler.tap(this.startP1,t),this._clearTapTimer()},e))}_clearTapTimer(){this._tapTimer&&(clearTimeout(this._tapTimer),this._tapTimer=null)}_getVelocity(t,i){const e=this.p1[t]-this._intervalP1[t];return Math.abs(e)>1&&i>5?e/i:0}_rafStopLoop(){this.raf&&(cancelAnimationFrame(this.raf),this.raf=null)}_preventPointerEventBehaviour(t){t.preventDefault()}_updatePoints(t,i){if(this._pointerEventEnabled){const e=t,s=this._ongoingPointers.findIndex(n=>n.id===e.pointerId);i==="up"&&s>-1?this._ongoingPointers.splice(s,1):i==="down"&&s===-1?this._ongoingPointers.push(this._convertEventPosToPoint(e,{x:0,y:0})):s>-1&&this._convertEventPosToPoint(e,this._ongoingPointers[s]),this._numActivePoints=this._ongoingPointers.length,this._numActivePoints>0&&u(this.p1,this._ongoingPointers[0]),this._numActivePoints>1&&u(this.p2,this._ongoingPointers[1])}else{const e=t;this._numActivePoints=0,e.type.indexOf("touch")>-1?e.touches&&e.touches.length>0&&(this._convertEventPosToPoint(e.touches[0],this.p1),this._numActivePoints++,e.touches.length>1&&(this._convertEventPosToPoint(e.touches[1],this.p2),this._numActivePoints++)):(this._convertEventPosToPoint(t,this.p1),i==="up"?this._numActivePoints=0:this._numActivePoints++)}}_updatePrevPoints(){u(this.prevP1,this.p1),u(this.prevP2,this.p2)}_updateStartPoints(){u(this.startP1,this.p1),u(this.startP2,this.p2),this._updatePrevPoints()}_calculateDragDirection(){if(this.pswp.mainScroll.isShifted())this.dragAxis="x";else{const t=Math.abs(this.p1.x-this.startP1.x)-Math.abs(this.p1.y-this.startP1.y);if(t!==0){const i=t>0?"x":"y";Math.abs(this.p1[i]-this.startP1[i])>=rt&&(this.dragAxis=i)}}}_convertEventPosToPoint(t,i){return i.x=t.pageX-this.pswp.offset.x,i.y=t.pageY-this.pswp.offset.y,"pointerId"in t?i.id=t.pointerId:t.identifier!==void 0&&(i.id=t.identifier),i}_onClick(t){this.pswp.mainScroll.isShifted()&&(t.preventDefault(),t.stopPropagation())}}const ct=.35;class dt{constructor(t){this.pswp=t,this.x=0,this.slideWidth=0,this._currPositionIndex=0,this._prevPositionIndex=0,this._containerShiftIndex=-1,this.itemHolders=[]}resize(t){const{pswp:i}=this,e=Math.round(i.viewportSize.x+i.viewportSize.x*i.options.spacing),s=e!==this.slideWidth;s&&(this.slideWidth=e,this.moveTo(this.getCurrSlideX())),this.itemHolders.forEach((n,o)=>{s&&v(n.el,(o+this._containerShiftIndex)*this.slideWidth),t&&n.slide&&n.slide.resize()})}resetPosition(){this._currPositionIndex=0,this._prevPositionIndex=0,this.slideWidth=0,this._containerShiftIndex=-1}appendHolders(){this.itemHolders=[];for(let t=0;t<3;t++){const i=m("pswp__item","div",this.pswp.container);i.setAttribute("role","group"),i.setAttribute("aria-roledescription","slide"),i.setAttribute("aria-hidden","true"),i.style.display=t===1?"block":"none",this.itemHolders.push({el:i})}}canBeSwiped(){return this.pswp.getNumItems()>1}moveIndexBy(t,i,e){const{pswp:s}=this;let n=s.potentialIndex+t;const o=s.getNumItems();if(s.canLoop()){n=s.getLoopedIndex(n);const l=(t+o)%o;l<=o/2?t=l:t=l-o}else n<0?n=0:n>=o&&(n=o-1),t=n-s.potentialIndex;s.potentialIndex=n,this._currPositionIndex-=t,s.animations.stopMainScroll();const a=this.getCurrSlideX();if(!i)this.moveTo(a),this.updateCurrItem();else{s.animations.startSpring({isMainScroll:!0,start:this.x,end:a,velocity:e||0,naturalFrequency:30,dampingRatio:1,onUpdate:h=>{this.moveTo(h)},onComplete:()=>{this.updateCurrItem(),s.appendHeavy()}});let l=s.potentialIndex-s.currIndex;if(s.canLoop()){const h=(l+o)%o;h<=o/2?l=h:l=h-o}Math.abs(l)>1&&this.updateCurrItem()}return Boolean(t)}getCurrSlideX(){return this.slideWidth*this._currPositionIndex}isShifted(){return this.x!==this.getCurrSlideX()}updateCurrItem(){var n;const{pswp:t}=this,i=this._prevPositionIndex-this._currPositionIndex;if(!i)return;this._prevPositionIndex=this._currPositionIndex,t.currIndex=t.potentialIndex;let e=Math.abs(i),s;e>=3&&(this._containerShiftIndex+=i+(i>0?-3:3),e=3);for(let o=0;o 0?(s=this.itemHolders.shift(),s&&(this.itemHolders[2]=s,this._containerShiftIndex++,v(s.el,(this._containerShiftIndex+2)*this.slideWidth),t.setContent(s,t.currIndex-e+o+2))):(s=this.itemHolders.pop(),s&&(this.itemHolders.unshift(s),this._containerShiftIndex--,v(s.el,this._containerShiftIndex*this.slideWidth),t.setContent(s,t.currIndex+e-o-2)));Math.abs(this._containerShiftIndex)>50&&!this.isShifted()&&(this.resetPosition(),this.resize()),t.animations.stopAllPan(),this.itemHolders.forEach((o,a)=>{o.slide&&o.slide.setIsActive(a===1)}),t.currSlide=(n=this.itemHolders[1])==null?void 0:n.slide,t.contentLoader.updateLazy(i),t.currSlide&&t.currSlide.applyCurrentZoomPan(),t.dispatch("change")}moveTo(t,i){if(!this.pswp.canLoop()&&i){let e=(this.slideWidth*this._currPositionIndex-t)/this.slideWidth;e+=this.pswp.currIndex;const s=Math.round(t-this.x);(e<0&&s>0||e>=this.pswp.getNumItems()-1&&s<0)&&(t=this.x+s*ct)}this.x=t,this.pswp.container&&v(this.pswp.container,t),this.pswp.dispatch("moveMainScroll",{x:t,dragging:i??!1})}}const pt={Escape:27,z:90,ArrowLeft:37,ArrowUp:38,ArrowRight:39,ArrowDown:40,Tab:9},y=(r,t)=>t?r:pt[r];class ut{constructor(t){this.pswp=t,this._wasFocused=!1,t.on("bindEvents",()=>{t.options.initialPointerPos||this._focusRoot(),t.events.add(document,"focusin",this._onFocusIn.bind(this)),t.events.add(document,"keydown",this._onKeyDown.bind(this))});const i=document.activeElement;t.on("destroy",()=>{t.options.returnFocus&&i&&this._wasFocused&&i.focus()})}_focusRoot(){!this._wasFocused&&this.pswp.element&&(this.pswp.element.focus(),this._wasFocused=!0)}_onKeyDown(t){const{pswp:i}=this;if(i.dispatch("keydown",{originalEvent:t}).defaultPrevented||K(t))return;let e,s,n=!1;const o="key"in t;switch(o?t.key:t.keyCode){case y("Escape",o):i.options.escKey&&(e="close");break;case y("z",o):e="toggleZoom";break;case y("ArrowLeft",o):s="x";break;case y("ArrowUp",o):s="y";break;case y("ArrowRight",o):s="x",n=!0;break;case y("ArrowDown",o):n=!0,s="y";break;case y("Tab",o):this._focusRoot();break}if(s){t.preventDefault();const{currSlide:a}=i;i.options.arrowKeys&&s==="x"&&i.getNumItems()>1?e=n?"next":"prev":a&&a.currZoomLevel>a.zoomLevels.fit&&(a.pan[s]+=n?-80:80,a.panTo(a.pan.x,a.pan.y))}e&&(t.preventDefault(),i[e]())}_onFocusIn(t){const{template:i}=this.pswp;i&&document!==t.target&&i!==t.target&&!i.contains(t.target)&&i.focus()}}const mt="cubic-bezier(.4,0,.22,1)";class ft{constructor(t){this.props=t;const{target:i,onComplete:e,transform:s,onFinish:n=()=>{},duration:o=333,easing:a=mt}=t;this.onFinish=n;const l=s?"transform":"opacity",h=t[l]??"";this._target=i,this._onComplete=e,this._finished=!1,this._onTransitionEnd=this._onTransitionEnd.bind(this),this._helperTimeout=setTimeout(()=>{R(i,l,o,a),this._helperTimeout=setTimeout(()=>{i.addEventListener("transitionend",this._onTransitionEnd,!1),i.addEventListener("transitioncancel",this._onTransitionEnd,!1),this._helperTimeout=setTimeout(()=>{this._finalizeAnimation()},o+500),i.style[l]=h},30)},0)}_onTransitionEnd(t){t.target===this._target&&this._finalizeAnimation()}_finalizeAnimation(){this._finished||(this._finished=!0,this.onFinish(),this._onComplete&&this._onComplete())}destroy(){this._helperTimeout&&clearTimeout(this._helperTimeout),q(this._target),this._target.removeEventListener("transitionend",this._onTransitionEnd,!1),this._target.removeEventListener("transitioncancel",this._onTransitionEnd,!1),this._finished||this._finalizeAnimation()}}const _t=12,gt=.75;class yt{constructor(t,i,e){this.velocity=t*1e3,this._dampingRatio=i||gt,this._naturalFrequency=e||_t,this._dampedFrequency=this._naturalFrequency,this._dampingRatio<1&&(this._dampedFrequency*=Math.sqrt(1-this._dampingRatio*this._dampingRatio))}easeFrame(t,i){let e=0,s;i/=1e3;const n=Math.E**(-this._dampingRatio*this._naturalFrequency*i);if(this._dampingRatio===1)s=this.velocity+this._naturalFrequency*t,e=(t+s*i)*n,this.velocity=e*-this._naturalFrequency+s*n;else if(this._dampingRatio<1){s=1/this._dampedFrequency*(this._dampingRatio*this._naturalFrequency*t+this.velocity);const o=Math.cos(this._dampedFrequency*i),a=Math.sin(this._dampedFrequency*i);e=n*(t*o+s*a),this.velocity=e*-this._naturalFrequency*this._dampingRatio+n*(-this._dampedFrequency*t*a+this._dampedFrequency*s*o)}return e}}class vt{constructor(t){this.props=t,this._raf=0;const{start:i,end:e,velocity:s,onUpdate:n,onComplete:o,onFinish:a=()=>{},dampingRatio:l,naturalFrequency:h}=t;this.onFinish=a;const c=new yt(s,l,h);let d=Date.now(),p=i-e;const _=()=>{this._raf&&(p=c.easeFrame(p,Date.now()-d),Math.abs(p)<1&&Math.abs(c.velocity)<50?(n(e),o&&o(),this.onFinish()):(d=Date.now(),n(p+e),this._raf=requestAnimationFrame(_)))};this._raf=requestAnimationFrame(_)}destroy(){this._raf>=0&&cancelAnimationFrame(this._raf),this._raf=0}}class wt{constructor(){this.activeAnimations=[]}startSpring(t){this._start(t,!0)}startTransition(t){this._start(t)}_start(t,i){const e=i?new vt(t):new ft(t);return this.activeAnimations.push(e),e.onFinish=()=>this.stop(e),e}stop(t){t.destroy();const i=this.activeAnimations.indexOf(t);i>-1&&this.activeAnimations.splice(i,1)}stopAll(){this.activeAnimations.forEach(t=>{t.destroy()}),this.activeAnimations=[]}stopAllPan(){this.activeAnimations=this.activeAnimations.filter(t=>t.props.isPan?(t.destroy(),!1):!0)}stopMainScroll(){this.activeAnimations=this.activeAnimations.filter(t=>t.props.isMainScroll?(t.destroy(),!1):!0)}isPanRunning(){return this.activeAnimations.some(t=>t.props.isPan)}}class Pt{constructor(t){this.pswp=t,t.events.add(t.element,"wheel",this._onWheel.bind(this))}_onWheel(t){t.preventDefault();const{currSlide:i}=this.pswp;let{deltaX:e,deltaY:s}=t;if(i&&!this.pswp.dispatch("wheel",{originalEvent:t}).defaultPrevented)if(t.ctrlKey||this.pswp.options.wheelToZoom){if(i.isZoomable()){let n=-s;t.deltaMode===1?n*=.05:n*=t.deltaMode?1:.002,n=2**n;const o=i.currZoomLevel*n;i.zoomTo(o,{x:t.clientX,y:t.clientY})}}else i.isPannable()&&(t.deltaMode===1&&(e*=18,s*=18),i.panTo(i.pan.x-e,i.pan.y-s))}}function St(r){if(typeof r=="string")return r;if(!r||!r.isCustomSVG)return"";const t=r;let i='",i}class xt{constructor(t,i){const e=i.name||i.className;let s=i.html;if(t.options[e]===!1)return;typeof t.options[e+"SVG"]=="string"&&(s=t.options[e+"SVG"]),t.dispatch("uiElementCreate",{data:i});let n="";i.isButton?(n+="pswp__button ",n+=i.className||`pswp__button--${i.name}`):n+=i.className||`pswp__${i.name}`;let o=i.isButton?i.tagName||"button":i.tagName||"div";o=o.toLowerCase();const a=m(n,o);if(i.isButton){o==="button"&&(a.type="button");let{title:c}=i;const{ariaLabel:d}=i;typeof t.options[e+"Title"]=="string"&&(c=t.options[e+"Title"]),c&&(a.title=c);const p=d||c;p&&a.setAttribute("aria-label",p)}a.innerHTML=St(s),i.onInit&&i.onInit(a,t),i.onClick&&(a.onclick=c=>{typeof i.onClick=="string"?t[i.onClick]():typeof i.onClick=="function"&&i.onClick(c,a,t)});const l=i.appendTo||"bar";let h=t.element;l==="bar"?(t.topBar||(t.topBar=m("pswp__top-bar pswp__hide-on-close","div",t.scrollWrap)),h=t.topBar):(a.classList.add("pswp__hide-on-close"),l==="wrapper"&&(h=t.scrollWrap)),h==null||h.appendChild(t.applyFilters("uiElement",a,i))}}function H(r,t,i){r.classList.add("pswp__button--arrow"),r.setAttribute("aria-controls","pswp__items"),t.on("change",()=>{t.options.loop||(i?r.disabled=!(t.currIndex 0))})}const bt={name:"arrowPrev",className:"pswp__button--arrow--prev",title:"Previous",order:10,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:' ',outlineID:"pswp__icn-arrow"},onClick:"prev",onInit:H},It={name:"arrowNext",className:"pswp__button--arrow--next",title:"Next",order:11,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'',outlineID:"pswp__icn-arrow"},onClick:"next",onInit:(r,t)=>{H(r,t,!0)}},At={name:"close",title:"Close",order:20,isButton:!0,html:{isCustomSVG:!0,inner:' ',outlineID:"pswp__icn-close"},onClick:"close"},Lt={name:"zoom",title:"Zoom",order:10,isButton:!0,html:{isCustomSVG:!0,inner:' ',outlineID:"pswp__icn-zoom"},onClick:"toggleZoom"},Ct={name:"preloader",appendTo:"bar",order:7,html:{isCustomSVG:!0,inner:' ',outlineID:"pswp__icn-loading"},onInit:(r,t)=>{let i,e=null;const s=(a,l)=>{r.classList[l?"add":"remove"]("pswp__preloader--"+a)},n=a=>{i!==a&&(i=a,s("active",a))},o=()=>{var a;if(!((a=t.currSlide)!=null&&a.content.isLoading())){n(!1),e&&(clearTimeout(e),e=null);return}e||(e=setTimeout(()=>{var l;n(Boolean((l=t.currSlide)==null?void 0:l.content.isLoading())),e=null},t.options.preloaderDelay))};t.on("change",o),t.on("loadComplete",a=>{t.currSlide===a.slide&&o()}),t.ui&&(t.ui.updatePreloaderVisibility=o)}},Tt={name:"counter",order:5,onInit:(r,t)=>{t.on("change",()=>{r.innerText=t.currIndex+1+t.options.indexIndicatorSep+t.getNumItems()})}};function D(r,t){r.classList[t?"add":"remove"]("pswp--zoomed-in")}class zt{constructor(t){this.pswp=t,this.isRegistered=!1,this.uiElementsData=[],this.items=[],this.updatePreloaderVisibility=()=>{},this._lastUpdatedZoomLevel=void 0}init(){const{pswp:t}=this;this.isRegistered=!1,this.uiElementsData=[At,bt,It,Lt,Ct,Tt],t.dispatch("uiRegister"),this.uiElementsData.sort((i,e)=>(i.order||0)-(e.order||0)),this.items=[],this.isRegistered=!0,this.uiElementsData.forEach(i=>{this.registerElement(i)}),t.on("change",()=>{var i;(i=t.element)==null||i.classList[t.getNumItems()===1?"add":"remove"]("pswp--one-slide")}),t.on("zoomPanUpdate",()=>this._onZoomPanUpdate())}registerElement(t){this.isRegistered?this.items.push(new xt(this.pswp,t)):this.uiElementsData.push(t)}_onZoomPanUpdate(){const{template:t,currSlide:i,options:e}=this.pswp;if(this.pswp.opener.isClosing||!t||!i)return;let{currZoomLevel:s}=i;if(this.pswp.opener.isOpen||(s=i.zoomLevels.initial),s===this._lastUpdatedZoomLevel)return;this._lastUpdatedZoomLevel=s;const n=i.zoomLevels.initial-i.zoomLevels.secondary;if(Math.abs(n)<.01||!i.isZoomable()){D(t,!1),t.classList.remove("pswp--zoom-allowed");return}t.classList.add("pswp--zoom-allowed");const o=s===i.zoomLevels.initial?i.zoomLevels.secondary:i.zoomLevels.initial;D(t,o<=s),(e.imageClickAction==="zoom"||e.imageClickAction==="zoom-or-close")&&t.classList.add("pswp--click-to-zoom")}}function Ot(r){const t=r.getBoundingClientRect();return{x:t.left,y:t.top,w:t.width}}function Et(r,t,i){const e=r.getBoundingClientRect(),s=e.width/t,n=e.height/i,o=s>n?s:n,a=(e.width-t*o)/2,l=(e.height-i*o)/2,h={x:e.left+a,y:e.top+l,w:t*o};return h.innerRect={w:e.width,h:e.height,x:a,y:l},h}function Zt(r,t,i){const e=i.dispatch("thumbBounds",{index:r,itemData:t,instance:i});if(e.thumbBounds)return e.thumbBounds;const{element:s}=t;let n,o;if(s&&i.options.thumbSelector!==!1){const a=i.options.thumbSelector||"img";o=s.matches(a)?s:s.querySelector(a)}return o=i.applyFilters("thumbEl",o,t,r),o&&(t.thumbCropped?n=Et(o,t.width||t.w||0,t.height||t.h||0):n=Ot(o)),i.applyFilters("thumbBounds",n,t,r)}class Dt{constructor(t,i){this.type=t,this.defaultPrevented=!1,i&&Object.assign(this,i)}preventDefault(){this.defaultPrevented=!0}}class Mt{constructor(){this._listeners={},this._filters={},this.pswp=void 0,this.options=void 0}addFilter(t,i,e=100){var s,n,o;this._filters[t]||(this._filters[t]=[]),(s=this._filters[t])==null||s.push({fn:i,priority:e}),(n=this._filters[t])==null||n.sort((a,l)=>a.priority-l.priority),(o=this.pswp)==null||o.addFilter(t,i,e)}removeFilter(t,i){this._filters[t]&&(this._filters[t]=this._filters[t].filter(e=>e.fn!==i)),this.pswp&&this.pswp.removeFilter(t,i)}applyFilters(t,...i){var e;return(e=this._filters[t])==null||e.forEach(s=>{i[0]=s.fn.apply(this,i)}),i[0]}on(t,i){var e,s;this._listeners[t]||(this._listeners[t]=[]),(e=this._listeners[t])==null||e.push(i),(s=this.pswp)==null||s.on(t,i)}off(t,i){var e;this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(s=>i!==s)),(e=this.pswp)==null||e.off(t,i)}dispatch(t,i){var s;if(this.pswp)return this.pswp.dispatch(t,i);const e=new Dt(t,i);return(s=this._listeners[t])==null||s.forEach(n=>{n.call(this,e)}),e}}class Rt{constructor(t,i){if(this.element=m("pswp__img pswp__img--placeholder",t?"img":"div",i),t){const e=this.element;e.decoding="async",e.alt="",e.src=t,e.setAttribute("role","presentation")}this.element.setAttribute("aria-hidden","true")}setDisplayedSize(t,i){this.element&&(this.element.tagName==="IMG"?(L(this.element,250,"auto"),this.element.style.transformOrigin="0 0",this.element.style.transform=b(0,0,t/250)):L(this.element,t,i))}destroy(){var t;(t=this.element)!=null&&t.parentNode&&this.element.remove(),this.element=null}}class Ft{constructor(t,i,e){this.instance=i,this.data=t,this.index=e,this.element=void 0,this.placeholder=void 0,this.slide=void 0,this.displayedImageWidth=0,this.displayedImageHeight=0,this.width=Number(this.data.w)||Number(this.data.width)||0,this.height=Number(this.data.h)||Number(this.data.height)||0,this.isAttached=!1,this.hasSlide=!1,this.isDecoding=!1,this.state=f.IDLE,this.data.type?this.type=this.data.type:this.data.src?this.type="image":this.type="html",this.instance.dispatch("contentInit",{content:this})}removePlaceholder(){this.placeholder&&!this.keepPlaceholder()&&setTimeout(()=>{this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0)},1e3)}load(t,i){if(this.slide&&this.usePlaceholder())if(this.placeholder){const e=this.placeholder.element;e&&!e.parentElement&&this.slide.container.prepend(e)}else{const e=this.instance.applyFilters("placeholderSrc",this.data.msrc&&this.slide.isFirstSlide?this.data.msrc:!1,this);this.placeholder=new Rt(e,this.slide.container)}this.element&&!i||this.instance.dispatch("contentLoad",{content:this,isLazy:t}).defaultPrevented||(this.isImageContent()?(this.element=m("pswp__img","img"),this.displayedImageWidth&&this.loadImage(t)):(this.element=m("pswp__content","div"),this.element.innerHTML=this.data.html||""),i&&this.slide&&this.slide.updateContentSize(!0))}loadImage(t){if(!this.isImageContent()||!this.element||this.instance.dispatch("contentLoadImage",{content:this,isLazy:t}).defaultPrevented)return;const i=this.element;this.updateSrcsetSizes(),this.data.srcset&&(i.srcset=this.data.srcset),i.src=this.data.src??"",i.alt=this.data.alt??"",this.state=f.LOADING,i.complete?this.onLoaded():(i.onload=()=>{this.onLoaded()},i.onerror=()=>{this.onError()})}setSlide(t){this.slide=t,this.hasSlide=!0,this.instance=t.pswp}onLoaded(){this.state=f.LOADED,this.slide&&this.element&&(this.instance.dispatch("loadComplete",{slide:this.slide,content:this}),this.slide.isActive&&this.slide.heavyAppended&&!this.element.parentNode&&(this.append(),this.slide.updateContentSize(!0)),(this.state===f.LOADED||this.state===f.ERROR)&&this.removePlaceholder())}onError(){this.state=f.ERROR,this.slide&&(this.displayError(),this.instance.dispatch("loadComplete",{slide:this.slide,isError:!0,content:this}),this.instance.dispatch("loadError",{slide:this.slide,content:this}))}isLoading(){return this.instance.applyFilters("isContentLoading",this.state===f.LOADING,this)}isError(){return this.state===f.ERROR}isImageContent(){return this.type==="image"}setDisplayedSize(t,i){if(this.element&&(this.placeholder&&this.placeholder.setDisplayedSize(t,i),!this.instance.dispatch("contentResize",{content:this,width:t,height:i}).defaultPrevented&&(L(this.element,t,i),this.isImageContent()&&!this.isError()))){const e=!this.displayedImageWidth&&t;this.displayedImageWidth=t,this.displayedImageHeight=i,e?this.loadImage(!1):this.updateSrcsetSizes(),this.slide&&this.instance.dispatch("imageSizeChange",{slide:this.slide,width:t,height:i,content:this})}}isZoomable(){return this.instance.applyFilters("isContentZoomable",this.isImageContent()&&this.state!==f.ERROR,this)}updateSrcsetSizes(){if(!this.isImageContent()||!this.element||!this.data.srcset)return;const t=this.element,i=this.instance.applyFilters("srcsetSizesWidth",this.displayedImageWidth,this);(!t.dataset.largestUsedSize||i>parseInt(t.dataset.largestUsedSize,10))&&(t.sizes=i+"px",t.dataset.largestUsedSize=String(i))}usePlaceholder(){return this.instance.applyFilters("useContentPlaceholder",this.isImageContent(),this)}lazyLoad(){this.instance.dispatch("contentLazyLoad",{content:this}).defaultPrevented||this.load(!0)}keepPlaceholder(){return this.instance.applyFilters("isKeepingPlaceholder",this.isLoading(),this)}destroy(){this.hasSlide=!1,this.slide=void 0,!this.instance.dispatch("contentDestroy",{content:this}).defaultPrevented&&(this.remove(),this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0),this.isImageContent()&&this.element&&(this.element.onload=null,this.element.onerror=null,this.element=void 0))}displayError(){var t;if(this.slide){let i=m("pswp__error-msg","div");i.innerText=((t=this.instance.options)==null?void 0:t.errorMsg)??"",i=this.instance.applyFilters("contentErrorElement",i,this),this.element=m("pswp__content pswp__error-msg-container","div"),this.element.appendChild(i),this.slide.container.innerText="",this.slide.container.appendChild(this.element),this.slide.updateContentSize(!0),this.removePlaceholder()}}append(){if(this.isAttached||!this.element)return;if(this.isAttached=!0,this.state===f.ERROR){this.displayError();return}if(this.instance.dispatch("contentAppend",{content:this}).defaultPrevented)return;const t="decode"in this.element;this.isImageContent()?t&&this.slide&&(!this.slide.isActive||C())?(this.isDecoding=!0,this.element.decode().catch(()=>{}).finally(()=>{this.isDecoding=!1,this.appendImage()})):this.appendImage():this.slide&&!this.element.parentNode&&this.slide.container.appendChild(this.element)}activate(){this.instance.dispatch("contentActivate",{content:this}).defaultPrevented||!this.slide||(this.isImageContent()&&this.isDecoding&&!C()?this.appendImage():this.isError()&&this.load(!1,!0),this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","false"))}deactivate(){this.instance.dispatch("contentDeactivate",{content:this}),this.slide&&this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","true")}remove(){this.isAttached=!1,!this.instance.dispatch("contentRemove",{content:this}).defaultPrevented&&(this.element&&this.element.parentNode&&this.element.remove(),this.placeholder&&this.placeholder.element&&this.placeholder.element.remove())}appendImage(){this.isAttached&&(this.instance.dispatch("contentAppendImage",{content:this}).defaultPrevented||(this.slide&&this.element&&!this.element.parentNode&&this.slide.container.appendChild(this.element),(this.state===f.LOADED||this.state===f.ERROR)&&this.removePlaceholder()))}}const Bt=5;function W(r,t,i){const e=t.createContentFromData(r,i);let s;const{options:n}=t;if(n&&(s=new k(n,r,-1),t.pswp)){const o=t.pswp.viewportSize||B(n,t.pswp),a=N(n,o,r,i);s.update(e.width,e.height,a)}return e.lazyLoad(),s&&e.setDisplayedSize(Math.ceil(e.width*s.initial),Math.ceil(e.height*s.initial)),e}function Nt(r,t){const i=t.getItemData(r);if(!t.dispatch("lazyLoadSlide",{index:r,itemData:i}).defaultPrevented)return W(i,t,r)}class kt{constructor(t){this.pswp=t,this.limit=Math.max(t.options.preload[0]+t.options.preload[1]+1,Bt),this._cachedItems=[]}updateLazy(t){const{pswp:i}=this;if(i.dispatch("lazyLoad").defaultPrevented)return;const{preload:e}=i.options,s=t===void 0?!0:t>=0;let n;for(n=0;n<=e[1];n++)this.loadSlideByIndex(i.currIndex+(s?n:-n));for(n=1;n<=e[0];n++)this.loadSlideByIndex(i.currIndex+(s?-n:n))}loadSlideByIndex(t){const i=this.pswp.getLoopedIndex(t);let e=this.getContentByIndex(i);e||(e=Nt(i,this.pswp),e&&this.addToCache(e))}getContentBySlide(t){let i=this.getContentByIndex(t.index);return i||(i=this.pswp.createContentFromData(t.data,t.index),this.addToCache(i)),i.setSlide(t),i}addToCache(t){if(this.removeByIndex(t.index),this._cachedItems.push(t),this._cachedItems.length>this.limit){const i=this._cachedItems.findIndex(e=>!e.isAttached&&!e.hasSlide);i!==-1&&this._cachedItems.splice(i,1)[0].destroy()}}removeByIndex(t){const i=this._cachedItems.findIndex(e=>e.index===t);i!==-1&&this._cachedItems.splice(i,1)}getContentByIndex(t){return this._cachedItems.find(i=>i.index===t)}destroy(){this._cachedItems.forEach(t=>t.destroy()),this._cachedItems=[]}}class Ht extends Mt{getNumItems(){var s;let t=0;const i=(s=this.options)==null?void 0:s.dataSource;i&&"length"in i?t=i.length:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),i.items&&(t=i.items.length));const e=this.dispatch("numItems",{dataSource:i,numItems:t});return this.applyFilters("numItems",e.numItems,i)}createContentFromData(t,i){return new Ft(t,this,i)}getItemData(t){var o;const i=(o=this.options)==null?void 0:o.dataSource;let e={};Array.isArray(i)?e=i[t]:i&&"gallery"in i&&(i.items||(i.items=this._getGalleryDOMElements(i.gallery)),e=i.items[t]);let s=e;s instanceof Element&&(s=this._domElementToItemData(s));const n=this.dispatch("itemData",{itemData:s||{},index:t});return this.applyFilters("itemData",n.itemData,t)}_getGalleryDOMElements(t){var i,e;return(i=this.options)!=null&&i.children||(e=this.options)!=null&&e.childSelector?X(this.options.children,this.options.childSelector,t)||[]:[t]}_domElementToItemData(t){const i={element:t},e=t.tagName==="A"?t:t.querySelector("a");if(e){i.src=e.dataset.pswpSrc||e.href,e.dataset.pswpSrcset&&(i.srcset=e.dataset.pswpSrcset),i.width=e.dataset.pswpWidth?parseInt(e.dataset.pswpWidth,10):0,i.height=e.dataset.pswpHeight?parseInt(e.dataset.pswpHeight,10):0,i.w=i.width,i.h=i.height,e.dataset.pswpType&&(i.type=e.dataset.pswpType);const s=t.querySelector("img");s&&(i.msrc=s.currentSrc||s.src,i.alt=s.getAttribute("alt")??""),(e.dataset.pswpCropped||e.dataset.cropped)&&(i.thumbCropped=!0)}return this.applyFilters("domItemData",i,t,e)}lazyLoadData(t,i){return W(t,this,i)}}const P=.003;class Wt{constructor(t){this.pswp=t,this.isClosed=!0,this.isOpen=!1,this.isClosing=!1,this.isOpening=!1,this._duration=void 0,this._useAnimation=!1,this._croppedZoom=!1,this._animateRootOpacity=!1,this._animateBgOpacity=!1,this._placeholder=void 0,this._opacityElement=void 0,this._cropContainer1=void 0,this._cropContainer2=void 0,this._thumbBounds=void 0,this._prepareOpen=this._prepareOpen.bind(this),t.on("firstZoomPan",this._prepareOpen)}open(){this._prepareOpen(),this._start()}close(){if(this.isClosed||this.isClosing||this.isOpening)return;const t=this.pswp.currSlide;this.isOpen=!1,this.isOpening=!1,this.isClosing=!0,this._duration=this.pswp.options.hideAnimationDuration,t&&t.currZoomLevel*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps(),setTimeout(()=>{this._start()},this._croppedZoom?30:0)}_prepareOpen(){if(this.pswp.off("firstZoomPan",this._prepareOpen),!this.isOpening){const t=this.pswp.currSlide;this.isOpening=!0,this.isClosing=!1,this._duration=this.pswp.options.showAnimationDuration,t&&t.zoomLevels.initial*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps()}}_applyStartProps(){var s;const{pswp:t}=this,i=this.pswp.currSlide,{options:e}=t;if(e.showHideAnimationType==="fade"?(e.showHideOpacity=!0,this._thumbBounds=void 0):e.showHideAnimationType==="none"?(e.showHideOpacity=!1,this._duration=0,this._thumbBounds=void 0):this.isOpening&&t._initialThumbBounds?this._thumbBounds=t._initialThumbBounds:this._thumbBounds=this.pswp.getThumbBounds(),this._placeholder=i==null?void 0:i.getPlaceholderElement(),t.animations.stopAll(),this._useAnimation=Boolean(this._duration&&this._duration>50),this._animateZoom=Boolean(this._thumbBounds)&&(i==null?void 0:i.content.usePlaceholder())&&(!this.isClosing||!t.mainScroll.isShifted()),this._animateZoom?this._animateRootOpacity=e.showHideOpacity??!1:(this._animateRootOpacity=!0,this.isOpening&&i&&(i.zoomAndPanToInitial(),i.applyCurrentZoomPan())),this._animateBgOpacity=!this._animateRootOpacity&&this.pswp.options.bgOpacity>P,this._opacityElement=this._animateRootOpacity?t.element:t.bg,!this._useAnimation){this._duration=0,this._animateZoom=!1,this._animateBgOpacity=!1,this._animateRootOpacity=!0,this.isOpening&&(t.element&&(t.element.style.opacity=String(P)),t.applyBgOpacity(1));return}this._animateZoom&&this._thumbBounds&&this._thumbBounds.innerRect?(this._croppedZoom=!0,this._cropContainer1=this.pswp.container,this._cropContainer2=(s=this.pswp.currSlide)==null?void 0:s.holderElement,t.container&&(t.container.style.overflow="hidden",t.container.style.width=t.viewportSize.x+"px")):this._croppedZoom=!1,this.isOpening?(this._animateRootOpacity?(t.element&&(t.element.style.opacity=String(P)),t.applyBgOpacity(1)):(this._animateBgOpacity&&t.bg&&(t.bg.style.opacity=String(P)),t.element&&(t.element.style.opacity="1")),this._animateZoom&&(this._setClosedStateZoomPan(),this._placeholder&&(this._placeholder.style.willChange="transform",this._placeholder.style.opacity=String(P)))):this.isClosing&&(t.mainScroll.itemHolders[0]&&(t.mainScroll.itemHolders[0].el.style.display="none"),t.mainScroll.itemHolders[2]&&(t.mainScroll.itemHolders[2].el.style.display="none"),this._croppedZoom&&t.mainScroll.x!==0&&(t.mainScroll.resetPosition(),t.mainScroll.resize()))}_start(){this.isOpening&&this._useAnimation&&this._placeholder&&this._placeholder.tagName==="IMG"?new Promise(t=>{let i=!1,e=!0;G(this._placeholder).finally(()=>{i=!0,e||t(!0)}),setTimeout(()=>{e=!1,i&&t(!0)},50),setTimeout(t,250)}).finally(()=>this._initiate()):this._initiate()}_initiate(){var t,i;(t=this.pswp.element)==null||t.style.setProperty("--pswp-transition-duration",this._duration+"ms"),this.pswp.dispatch(this.isOpening?"openingAnimationStart":"closingAnimationStart"),this.pswp.dispatch("initialZoom"+(this.isOpening?"In":"Out")),(i=this.pswp.element)==null||i.classList[this.isOpening?"add":"remove"]("pswp--ui-visible"),this.isOpening?(this._placeholder&&(this._placeholder.style.opacity="1"),this._animateToOpenState()):this.isClosing&&this._animateToClosedState(),this._useAnimation||this._onAnimationComplete()}_onAnimationComplete(){var i;const{pswp:t}=this;this.isOpen=this.isOpening,this.isClosed=this.isClosing,this.isOpening=!1,this.isClosing=!1,t.dispatch(this.isOpen?"openingAnimationEnd":"closingAnimationEnd"),t.dispatch("initialZoom"+(this.isOpen?"InEnd":"OutEnd")),this.isClosed?t.destroy():this.isOpen&&(this._animateZoom&&t.container&&(t.container.style.overflow="visible",t.container.style.width="100%"),(i=t.currSlide)==null||i.applyCurrentZoomPan())}_animateToOpenState(){const{pswp:t}=this;this._animateZoom&&(this._croppedZoom&&this._cropContainer1&&this._cropContainer2&&(this._animateTo(this._cropContainer1,"transform","translate3d(0,0,0)"),this._animateTo(this._cropContainer2,"transform","none")),t.currSlide&&(t.currSlide.zoomAndPanToInitial(),this._animateTo(t.currSlide.container,"transform",t.currSlide.getCurrentTransform()))),this._animateBgOpacity&&t.bg&&this._animateTo(t.bg,"opacity",String(t.options.bgOpacity)),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","1")}_animateToClosedState(){const{pswp:t}=this;this._animateZoom&&this._setClosedStateZoomPan(!0),this._animateBgOpacity&&t.bgOpacity>.01&&t.bg&&this._animateTo(t.bg,"opacity","0"),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","0")}_setClosedStateZoomPan(t){if(!this._thumbBounds)return;const{pswp:i}=this,{innerRect:e}=this._thumbBounds,{currSlide:s,viewportSize:n}=i;if(this._croppedZoom&&e&&this._cropContainer1&&this._cropContainer2){const o=-n.x+(this._thumbBounds.x-e.x)+e.w,a=-n.y+(this._thumbBounds.y-e.y)+e.h,l=n.x-e.w,h=n.y-e.h;t?(this._animateTo(this._cropContainer1,"transform",b(o,a)),this._animateTo(this._cropContainer2,"transform",b(l,h))):(v(this._cropContainer1,o,a),v(this._cropContainer2,l,h))}s&&(u(s.pan,e||this._thumbBounds),s.currZoomLevel=this._thumbBounds.w/s.width,t?this._animateTo(s.container,"transform",s.getCurrentTransform()):s.applyCurrentZoomPan())}_animateTo(t,i,e){if(!this._duration){t.style[i]=e;return}const{animations:s}=this.pswp,n={duration:this._duration,easing:this.pswp.options.easing,onComplete:()=>{s.activeAnimations.length||this._onAnimationComplete()},target:t};n[i]=e,s.startTransition(n)}}const Vt={allowPanToNext:!0,spacing:.1,loop:!0,pinchToClose:!0,closeOnVerticalDrag:!0,hideAnimationDuration:333,showAnimationDuration:333,zoomAnimationDuration:333,escKey:!0,arrowKeys:!0,returnFocus:!0,maxWidthToAnimate:4e3,clickToCloseNonZoomable:!0,imageClickAction:"zoom-or-close",bgClickAction:"close",tapAction:"toggle-controls",doubleTapAction:"zoom",indexIndicatorSep:" / ",preloaderDelay:2e3,bgOpacity:.8,index:0,errorMsg:"The image cannot be loaded",preload:[1,2],easing:"cubic-bezier(.4,0,.22,1)"};class Ut extends Ht{constructor(t){super(),this.options=this._prepareOptions(t||{}),this.offset={x:0,y:0},this._prevViewportSize={x:0,y:0},this.viewportSize={x:0,y:0},this.bgOpacity=1,this.currIndex=0,this.potentialIndex=0,this.isOpen=!1,this.isDestroying=!1,this.hasMouse=!1,this._initialItemData={},this._initialThumbBounds=void 0,this.topBar=void 0,this.element=void 0,this.template=void 0,this.container=void 0,this.scrollWrap=void 0,this.currSlide=void 0,this.events=new Y,this.animations=new wt,this.mainScroll=new dt(this),this.gestures=new lt(this),this.opener=new Wt(this),this.keyboard=new ut(this),this.contentLoader=new kt(this)}init(){if(this.isOpen||this.isDestroying)return!1;this.isOpen=!0,this.dispatch("init"),this.dispatch("beforeOpen"),this._createMainStructure();let t="pswp--open";return this.gestures.supportsTouch&&(t+=" pswp--touch"),this.options.mainClass&&(t+=" "+this.options.mainClass),this.element&&(this.element.className+=" "+t),this.currIndex=this.options.index||0,this.potentialIndex=this.currIndex,this.dispatch("firstUpdate"),this.scrollWheel=new Pt(this),(Number.isNaN(this.currIndex)||this.currIndex<0||this.currIndex>=this.getNumItems())&&(this.currIndex=0),this.gestures.supportsTouch||this.mouseDetected(),this.updateSize(),this.offset.y=window.pageYOffset,this._initialItemData=this.getItemData(this.currIndex),this.dispatch("gettingData",{index:this.currIndex,data:this._initialItemData,slide:void 0}),this._initialThumbBounds=this.getThumbBounds(),this.dispatch("initialLayout"),this.on("openingAnimationEnd",()=>{const{itemHolders:i}=this.mainScroll;i[0]&&(i[0].el.style.display="block",this.setContent(i[0],this.currIndex-1)),i[2]&&(i[2].el.style.display="block",this.setContent(i[2],this.currIndex+1)),this.appendHeavy(),this.contentLoader.updateLazy(),this.events.add(window,"resize",this._handlePageResize.bind(this)),this.events.add(window,"scroll",this._updatePageScrollOffset.bind(this)),this.dispatch("bindEvents")}),this.mainScroll.itemHolders[1]&&this.setContent(this.mainScroll.itemHolders[1],this.currIndex),this.dispatch("change"),this.opener.open(),this.dispatch("afterInit"),!0}getLoopedIndex(t){const i=this.getNumItems();return this.options.loop&&(t>i-1&&(t-=i),t<0&&(t+=i)),I(t,0,i-1)}appendHeavy(){this.mainScroll.itemHolders.forEach(t=>{var i;(i=t.slide)==null||i.appendHeavy()})}goTo(t){this.mainScroll.moveIndexBy(this.getLoopedIndex(t)-this.potentialIndex)}next(){this.goTo(this.potentialIndex+1)}prev(){this.goTo(this.potentialIndex-1)}zoomTo(...t){var i;(i=this.currSlide)==null||i.zoomTo(...t)}toggleZoom(){var t;(t=this.currSlide)==null||t.toggleZoom()}close(){!this.opener.isOpen||this.isDestroying||(this.isDestroying=!0,this.dispatch("close"),this.events.removeAll(),this.opener.close())}destroy(){var t;if(!this.isDestroying){this.options.showHideAnimationType="none",this.close();return}this.dispatch("destroy"),this._listeners={},this.scrollWrap&&(this.scrollWrap.ontouchmove=null,this.scrollWrap.ontouchend=null),(t=this.element)==null||t.remove(),this.mainScroll.itemHolders.forEach(i=>{var e;(e=i.slide)==null||e.destroy()}),this.contentLoader.destroy(),this.events.removeAll()}refreshSlideContent(t){this.contentLoader.removeByIndex(t),this.mainScroll.itemHolders.forEach((i,e)=>{var n,o;let s=(((n=this.currSlide)==null?void 0:n.index)??0)-1+e;this.canLoop()&&(s=this.getLoopedIndex(s)),s===t&&(this.setContent(i,t,!0),e===1&&(this.currSlide=i.slide,(o=i.slide)==null||o.setIsActive(!0)))}),this.dispatch("change")}setContent(t,i,e){if(this.canLoop()&&(i=this.getLoopedIndex(i)),t.slide){if(t.slide.index===i&&!e)return;t.slide.destroy(),t.slide=void 0}if(!this.canLoop()&&(i<0||i>=this.getNumItems()))return;const s=this.getItemData(i);t.slide=new j(s,i,this),i===this.currIndex&&(this.currSlide=t.slide),t.slide.append(t.el)}getViewportCenterPoint(){return{x:this.viewportSize.x/2,y:this.viewportSize.y/2}}updateSize(t){if(this.isDestroying)return;const i=B(this.options,this);!t&&x(i,this._prevViewportSize)||(u(this._prevViewportSize,i),this.dispatch("beforeResize"),u(this.viewportSize,this._prevViewportSize),this._updatePageScrollOffset(),this.dispatch("viewportSize"),this.mainScroll.resize(this.opener.isOpen),!this.hasMouse&&window.matchMedia("(any-hover: hover)").matches&&this.mouseDetected(),this.dispatch("resize"))}applyBgOpacity(t){this.bgOpacity=Math.max(t,0),this.bg&&(this.bg.style.opacity=String(this.bgOpacity*this.options.bgOpacity))}mouseDetected(){var t;this.hasMouse||(this.hasMouse=!0,(t=this.element)==null||t.classList.add("pswp--has_mouse"))}_handlePageResize(){this.updateSize(),/iPhone|iPad|iPod/i.test(window.navigator.userAgent)&&setTimeout(()=>{this.updateSize()},500)}_updatePageScrollOffset(){this.setScrollOffset(0,window.pageYOffset)}setScrollOffset(t,i){this.offset.x=t,this.offset.y=i,this.dispatch("updateScrollOffset")}_createMainStructure(){this.element=m("pswp","div"),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.template=this.element,this.bg=m("pswp__bg","div",this.element),this.scrollWrap=m("pswp__scroll-wrap","section",this.element),this.container=m("pswp__container","div",this.scrollWrap),this.scrollWrap.setAttribute("aria-roledescription","carousel"),this.container.setAttribute("aria-live","off"),this.container.setAttribute("id","pswp__items"),this.mainScroll.appendHolders(),this.ui=new zt(this),this.ui.init(),(this.options.appendToEl||document.body).appendChild(this.element)}getThumbBounds(){return Zt(this.currIndex,this.currSlide?this.currSlide.data:this._initialItemData,this)}canLoop(){return this.options.loop&&this.getNumItems()>2}_prepareOptions(t){return window.matchMedia("(prefers-reduced-motion), (update: slow)").matches&&(t.showHideAnimationType="none",t.zoomAnimationDuration=0),{...Vt,...t}}}export{Ut as default}; diff --git a/assets/plugin-api.html-48f54d30.js b/assets/plugin-api.html-48f54d30.js new file mode 100644 index 00000000..562855a2 --- /dev/null +++ b/assets/plugin-api.html-48f54d30.js @@ -0,0 +1,91 @@ +import{_ as c,W as u,X as r,Y as a,$ as n,a0 as s,Z as t,a1 as p,D as i}from"./framework-46b0e263.js";const d={},k=n("h1",{id:"plugin-api",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#plugin-api","aria-hidden":"true"},"#"),s(" Plugin API")],-1),h={href:"https://www.npmjs.com/package/@vuepress/core",target:"_blank",rel:"noopener noreferrer"},m=p(' # Overview
Plugins should be used before initialization. The basic options will be handled once the plugin is used:
The following hooks will be processed when initializing app:
The following hooks will be processed when preparing files:
The following hooks will be processed in dev / build:
',9),v=p(`# Basic Options
# name
Type:
string
Details:
Name of the plugin.
It will be used for identifying plugins to avoid using a same plugin multiple times, so make sure to use a unique plugin name.
It should follow the naming convention:
- Non-scoped:
vuepress-plugin-foo
- Scoped:
@org/vuepress-plugin-foo
Also see:
# multiple
Type:
boolean
Default:
false
Details:
Declare whether the plugin can be used multiple times.
If set to
false
, when using plugins with the same name, the one used previously will be replaced by the one used later.If set to
true
, plugins with the same name could be used multiple times and won't be replaced.Also see:
# Development Hooks
# alias
Type:
Record<string, any> | ((app: App, isServer: boolean) => Record<string, any>)
Details:
Path aliases definition.
This hook accepts an object or a function that returns an object.
Example:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + alias: { + "@alias": path.resolve(__dirname, "./path/to/alias"), + }, +}; +
# clientConfigFile
Type:
string | ((app: App) => string | Promise<string>)
Details:
Path of client config file.
This hook accepts an absolute file path, or a function that returns the path.
Example:
`,12),g=p(`import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + clientConfigFile: path.resolve(__dirname, "./path/to/clientConfig.js"), +}; +
# define
Type:
Record<string, any> | ((app: App, isServer: boolean) => Record<string, any>)
Details:
Define global constants replacements.
This hook accepts an object or a function that returns an object.
This can be useful for passing variables to client files. Note that the values will be automatically processed by
JSON.stringify()
.Example:
export default { + define: { + __GLOBAL_BOOLEAN__: true, + __GLOBAL_STRING__: "foobar", + __GLOBAL_OBJECT__: { foo: "bar" }, + }, +}; +
# extendsBundlerOptions
`,5),b={href:"https://vuejs.org/api/application.html#app-config-compileroptions",target:"_blank",rel:"noopener noreferrer"},f=p(`
Type:
(options: BundlerOptions, app: App) => void | Promise<void>
Details:
Bundler options extension.
This hook accepts a function that will receive the bundler options.
This hook can be used for modifying bundler options.
You could determine which bundler the user is using by
app.options.bundler.name
.Example:
`,1),w=p(`export default { + extendsBundlerOptions: (bundlerOptions, app) => { + // extends options of @vuepress/bundler-vite + if (app.options.bundler.name === "@vuepress/bundler-vite") { + bundlerOptions.vuePluginOptions ??= {}; + bundlerOptions.vuePluginOptions.template ??= {}; + bundlerOptions.vuePluginOptions.template.compilerOptions ??= {}; + const isCustomElement = + bundlerOptions.vuePluginOptions.template.compilerOptions + .isCustomElement; + bundlerOptions.vuePluginOptions.template.compilerOptions.isCustomElement = + (tag) => { + if (isCustomElement?.(tag)) return true; + if (tag === "my-custom-element") return true; + }; + } + + // extends options of @vuepress/bundler-webpack + if (app.options.bundler.name === "@vuepress/bundler-webpack") { + bundlerOptions.vue ??= {}; + bundlerOptions.vue.compilerOptions ??= {}; + const isCustomElement = + bundlerOptions.vue.compilerOptions.isCustomElement; + bundlerOptions.vue.compilerOptions.isCustomElement = (tag) => { + if (isCustomElement?.(tag)) return true; + if (tag === "my-custom-element") return true; + }; + } + }, +}; +
# extendsMarkdownOptions
Type:
(options: MarkdownOptions, app: App) => void | Promise<void>
Details:
Markdown options extension.
This hook accepts a function that will receive the markdown options.
This hook can be used for modifying markdown options.
Example:
Modifying the default header levels that going to be extracted:
`,4),y=n("h3",{id:"extendsmarkdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#extendsmarkdown","aria-hidden":"true"},"#"),s(" extendsMarkdown")],-1),_=n("li",null,[n("p",null,[s("Type: "),n("code",null,"(md: Markdown, app: App) => void | Promiseexport default { + extendsMarkdownOptions: (markdownOptions, app) => { + if (markdownOptions.headers === false) return; + markdownOptions.headers ??= {}; + if (markdownOptions.headers.level) return; + markdownOptions.headers.level = [2, 3, 4, 5, 6]; + }, +}; +
")])],-1),x=n("p",null,"Details:",-1),P=n("p",null,"Markdown enhancement.",-1),O=n("code",null,"Markdown",-1),T={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},A=n("p",null,"This hook can be used for using extra markdown-it plugins and implementing customizations.",-1),q=n("li",null,[n("p",null,"Example:")],-1),C=p(` export default { + extendsMarkdown: (md) => { + md.use(plugin1); + md.linkify.set({ fuzzyEmail: false }); + }, +}; +
# extendsPageOptions
Type:
(options: PageOptions, app: App) => void | Promise<void>
Details:
Page options extension.
This hook accepts a function that will receive the options of
createPage
.This hook can be used for modifying page options
Example:
Set permalink pattern for pages in
_posts
directory:`,5),D=p(`export default { + extendsPageOptions: (pageOptions, app) => { + if (pageOptions.filePath?.startsWith(app.dir.source("_posts/"))) { + pageOptions.frontmatter = pageOptions.frontmatter ?? {}; + pageOptions.frontmatter.permalinkPattern = + "/:year/:month/:day/:slug.html"; + } + }, +}; +
# extendsPage
Type:
(page: Page, app: App) => void | Promise<void>
Details:
Page extension.
This hook accepts a function that will receive a
Page
instance.This hook can be used for adding extra properties or modifying current properties on
Page
object.Notice that changes to
page.data
andpage.routeMeta
can be used in client side code.Example:
export default { + extendsPage: (page) => { + page.foo = "foo"; + page.data.bar = "bar"; + }, +}; +
In client component:
`,5),E=p('import { usePageData } from "@vuepress/client"; + +export default { + setup() { + const page = usePageData(); + console.log(page.value.bar); // bar + }, +}; +
# Lifecycle Hooks
# onInitialized
Type:
(app: App) => void | Promise<void>
Details:
This hook will be invoked once VuePress app has been initialized.
# onPrepared
Type:
(app: App) => void | Promise<void>
Details:
This hook will be invoked once VuePress app has finished preparation.
# onWatched
Type:
(app: App, watchers: Closable[], restart: () => Promise<void>) => void | Promise<void>
Details:
This hook will be invoked once VuePress app has started dev-server and watched files change.
The
watchers
is an array of file watchers. When changing config file, the dev command will be restarted and those watchers will be closed. If you are adding new watchers in this hook, you should push your watchers to thewatchers
array, so that they can be closed correctly when restarting.The
restart
is a method to restart the dev command. When calling this method, thewatchers
array will be closed automatically.# onGenerated
',9);function I(B,N){const l=i("NpmBadge"),o=i("ExternalLinkIcon"),e=i("RouterLink");return u(),r("div",null,[k,a(l,{package:"@vuepress/core"}),n("p",null,[s("Plugin API is supported by "),n("a",h,[s("@vuepress/core"),a(o)]),s(" package. You could check out "),a(e,{to:"/reference/node-api.html"},{default:t(()=>[s("Node API")]),_:1}),s(" for how to use the VuePress app instance in plugin hooks.")]),m,n("blockquote",null,[n("p",null,[s("Check out "),a(e,{to:"/advanced/architecture.html#core-process-and-hooks"},{default:t(()=>[s("Advanced > Architecture > Core Process and Hooks")]),_:1}),s(" to understand the process better.")])]),v,n("ul",null,[n("li",null,[s("Also see: "),n("ul",null,[n("li",null,[a(e,{to:"/reference/client-api.html#defineclientconfig"},{default:t(()=>[s("Client API > defineClientConfig")]),_:1})]),n("li",null,[a(e,{to:"/advanced/cookbook/usage-of-client-config.html"},{default:t(()=>[s("Advanced > Cookbook > Usage of Client Config")]),_:1})])])])]),g,n("p",null,[s("Adding default "),n("a",b,[s("app.compilerOptions.isCustomElement"),a(o)]),s(" option:")]),f,n("ul",null,[n("li",null,[s("Also see: "),n("ul",null,[n("li",null,[a(e,{to:"/reference/bundler/vite.html"},{default:t(()=>[s("Bundlers > Vite")]),_:1})]),n("li",null,[a(e,{to:"/reference/bundler/webpack.html"},{default:t(()=>[s("Bundlers > Webpack")]),_:1})])])])]),w,n("ul",null,[n("li",null,[s("Also see: "),n("ul",null,[n("li",null,[a(e,{to:"/reference/config.html#markdown"},{default:t(()=>[s("Config > markdown")]),_:1})])])])]),y,n("ul",null,[_,n("li",null,[x,P,n("p",null,[s("This hook accepts a function that will receive an instance of "),O,s(" powered by "),n("a",T,[s("markdown-it"),a(o)]),s(" in its arguments.")]),A]),q]),C,n("ul",null,[n("li",null,[s("Also see: "),n("ul",null,[n("li",null,[a(e,{to:"/reference/node-api.html#createpage"},{default:t(()=>[s("Node API > Page > createPage")]),_:1})])])])]),D,n("ul",null,[n("li",null,[s("Also see: "),n("ul",null,[n("li",null,[a(e,{to:"/reference/client-api.html#usepagedata"},{default:t(()=>[s("Client API > usePageData")]),_:1})]),n("li",null,[a(e,{to:"/reference/node-api.html#data"},{default:t(()=>[s("Node API > Page Properties > data")]),_:1})]),n("li",null,[a(e,{to:"/reference/node-api.html#routemeta"},{default:t(()=>[s("Node API > Page Properties > routeMeta")]),_:1})])])])]),E])}const L=c(d,[["render",I],["__file","plugin-api.html.vue"]]);export{L as default}; diff --git a/assets/plugin-api.html-5e3b2303.js b/assets/plugin-api.html-5e3b2303.js new file mode 100644 index 00000000..2c08584f --- /dev/null +++ b/assets/plugin-api.html-5e3b2303.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5e9d516d","path":"/zh/reference/plugin-api.html","title":"插件 API","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:plug","description":"插件 API 是由 @vuepress/core (https://www.npmjs.com/package/@vuepress/core) 包支持的。你可以查看 Node API (./node-api.md) 来了解如何使用插件 Hooks 中的 VuePress App 实例。 概览 插件需要在初始化之前使用。基础配置项会在使用插件时立即被处理...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"插件 API"}],["meta",{"property":"og:description","content":"插件 API 是由 @vuepress/core (https://www.npmjs.com/package/@vuepress/core) 包支持的。你可以查看 Node API (./node-api.md) 来了解如何使用插件 Hooks 中的 VuePress App 实例。 概览 插件需要在初始化之前使用。基础配置项会在使用插件时立即被处理..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"插件 API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"概览","slug":"概览","link":"#概览","children":[]},{"level":2,"title":"基础配置项","slug":"基础配置项","link":"#基础配置项","children":[{"level":3,"title":"name","slug":"name","link":"#name","children":[]},{"level":3,"title":"multiple","slug":"multiple","link":"#multiple","children":[]}]},{"level":2,"title":"开发 Hooks","slug":"开发-hooks","link":"#开发-hooks","children":[{"level":3,"title":"alias","slug":"alias","link":"#alias","children":[]},{"level":3,"title":"clientConfigFile","slug":"clientconfigfile","link":"#clientconfigfile","children":[]},{"level":3,"title":"define","slug":"define","link":"#define","children":[]},{"level":3,"title":"extendsBundlerOptions","slug":"extendsbundleroptions","link":"#extendsbundleroptions","children":[]},{"level":3,"title":"extendsMarkdownOptions","slug":"extendsmarkdownoptions","link":"#extendsmarkdownoptions","children":[]},{"level":3,"title":"extendsMarkdown","slug":"extendsmarkdown","link":"#extendsmarkdown","children":[]},{"level":3,"title":"extendsPageOptions","slug":"extendspageoptions","link":"#extendspageoptions","children":[]},{"level":3,"title":"extendsPage","slug":"extendspage","link":"#extendspage","children":[]}]},{"level":2,"title":"生命周期 Hooks","slug":"生命周期-hooks","link":"#生命周期-hooks","children":[{"level":3,"title":"onInitialized","slug":"oninitialized","link":"#oninitialized","children":[]},{"level":3,"title":"onPrepared","slug":"onprepared","link":"#onprepared","children":[]},{"level":3,"title":"onWatched","slug":"onwatched","link":"#onwatched","children":[]},{"level":3,"title":"onGenerated","slug":"ongenerated","link":"#ongenerated","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":5,"words":1501},"filePathRelative":"zh/reference/plugin-api.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/plugin-api.html-c8d9418d.js b/assets/plugin-api.html-c8d9418d.js new file mode 100644 index 00000000..2b0e88f1 --- /dev/null +++ b/assets/plugin-api.html-c8d9418d.js @@ -0,0 +1,91 @@ +import{_ as c,W as u,X as r,Y as s,$ as n,a0 as a,Z as t,a1 as p,D as i}from"./framework-46b0e263.js";const d={},k=n("h1",{id:"插件-api",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#插件-api","aria-hidden":"true"},"#"),a(" 插件 API")],-1),v={href:"https://www.npmjs.com/package/@vuepress/core",target:"_blank",rel:"noopener noreferrer"},m=p('
Type:
(app: App) => void | Promise<void>
Details:
This hook will be invoked once VuePress app has generated static files.
# 概览
插件需要在初始化之前使用。基础配置项会在使用插件时立即被处理:
下列 Hooks 会在初始化 App 时处理:
下列 Hooks 会在准备文件时处理:
下列 Hooks 会在 dev / build 时处理:
',9),h=p(`# 基础配置项
# name
类型:
string
详情:
插件的名称。
它会被用来识别插件,以避免多次使用同一个插件,因此应确保你的插件名称是独一无二的。
它应遵从如下命名约定:
- 非 Scoped:
vuepress-plugin-foo
- Scoped:
@org/vuepress-plugin-foo
参考:
# multiple
类型:
boolean
默认值:
false
详情:
插件是否能够被多次使用。
如果设置为
false
,当有相同名称的插件被使用时,先使用的会被后使用的替换掉。如果设置为
true
,相同名称的插件可以被多次使用且不会被替换。参考:
# 开发 Hooks
# alias
类型:
Record<string, any> | ((app: App, isServer: boolean) => Record<string, any>)
详情:
定义路径别名。
该 Hook 接收一个对象,或者一个返回对象的函数。
示例:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + alias: { + "@alias": path.resolve(__dirname, "./path/to/alias"), + }, +}; +
# clientConfigFile
类型:
string | ((app: App) => string | Promise<string>)
详情:
客户端配置文件路径。
该 Hook 接收文件绝对路径,或者一个返回路径的函数。
示例:
`,12),b=p(`import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + clientConfigFile: path.resolve(__dirname, "./path/to/clientConfig.js"), +}; +
# define
类型:
Record<string, any> | ((app: App, isServer: boolean) => Record<string, any>)
详情:
定义全局常量。
该 Hook 接收一个对象,或者一个返回对象的函数。
它可以被用于向客户端文件传递变量。注意这里的值都会自动被
JSON.stringify()
处理。示例:
export default { + define: { + __GLOBAL_BOOLEAN__: true, + __GLOBAL_STRING__: "foobar", + __GLOBAL_OBJECT__: { foo: "bar" }, + }, +}; +
# extendsBundlerOptions
`,5),g={href:"https://vuejs.org/api/application.html#app-config-compileroptions",target:"_blank",rel:"noopener noreferrer"},f=p(`
类型:
(options: BundlerOptions, app: App) => void | Promise<void>
详情:
Bundler 配置项扩展。
该 Hook 接收一个函数,在参数中会收到 Bundler 配置项。
该 Hook 可以用于修改 Bundler 配置项。
你可以通过
app.options.bundler.name
判断用户当前使用的 Bundler。示例:
`,1),_=p(`export default { + extendsBundlerOptions: (bundlerOptions, app) => { + // 修改 @vuepress/bundler-vite 的配置项 + if (app.options.bundler.name === "@vuepress/bundler-vite") { + bundlerOptions.vuePluginOptions ??= {}; + bundlerOptions.vuePluginOptions.template ??= {}; + bundlerOptions.vuePluginOptions.template.compilerOptions ??= {}; + const isCustomElement = + bundlerOptions.vuePluginOptions.template.compilerOptions + .isCustomElement; + bundlerOptions.vuePluginOptions.template.compilerOptions.isCustomElement = + (tag) => { + if (isCustomElement?.(tag)) return true; + if (tag === "my-custom-element") return true; + }; + } + + // 修改 @vuepress/bundler-webpack 的配置项 + if (app.options.bundler.name === "@vuepress/bundler-webpack") { + bundlerOptions.vue ??= {}; + bundlerOptions.vue.compilerOptions ??= {}; + const isCustomElement = + bundlerOptions.vue.compilerOptions.isCustomElement; + bundlerOptions.vue.compilerOptions.isCustomElement = (tag) => { + if (isCustomElement?.(tag)) return true; + if (tag === "my-custom-element") return true; + }; + } + }, +}; +
# extendsMarkdownOptions
类型:
(options: MarkdownOptions, app: App) => void | Promise<void>
详情:
Markdown 配置项扩展。
该 Hook 接收一个函数,在参数中会收到 Markdown 配置项。
该 Hook 可以用于修改 Markdown 配置项。
示例:
修改默认提取的子标题层级:
`,4),w=n("h3",{id:"extendsmarkdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#extendsmarkdown","aria-hidden":"true"},"#"),a(" extendsMarkdown")],-1),y=n("li",null,[n("p",null,[a("类型: "),n("code",null,"(md: Markdown, app: App) => void | Promiseexport default { + extendsMarkdownOptions: (markdownOptions, app) => { + if (markdownOptions.headers === false) return; + markdownOptions.headers ??= {}; + if (markdownOptions.headers.level) return; + markdownOptions.headers.level = [2, 3, 4, 5, 6]; + }, +}; +
")])],-1),x=n("p",null,"详情:",-1),P=n("p",null,"Markdown 增强。",-1),O={href:"https://github.com/markdown-it/markdown-it",target:"_blank",rel:"noopener noreferrer"},A=n("code",null,"Markdown",-1),E=n("p",null,"该 Hook 可以用来添加额外的 markdown-it 插件、应用额外的自定义功能。",-1),q=n("li",null,[n("p",null,"示例:")],-1),B=p(` export default { + extendsMarkdown: (md) => { + md.use(plugin1); + md.linkify.set({ fuzzyEmail: false }); + }, +}; +
# extendsPageOptions
类型:
(options: PageOptions, app: App) => void | Promise<void>
详情:
页面配置项扩展。
该 Hook 接收一个函数,在参数中会收到
createPage
传入的配置项。该 Hook 可以用于修改页面配置项。
示例:
为
_posts
目录下的页面设置永久链接 Pattern :`,5),H=p(`export default { + extendsPageOptions: (pageOptions, app) => { + if (pageOptions.filePath?.startsWith(app.dir.source("_posts/"))) { + pageOptions.frontmatter = pageOptions.frontmatter ?? {}; + pageOptions.frontmatter.permalinkPattern = + "/:year/:month/:day/:slug.html"; + } + }, +}; +
# extendsPage
类型:
(page: Page, app: App) => void | Promise<void>
详情:
页面扩展。
该 Hook 接收一个函数,在参数中会收到一个
Page
实例。该 Hook 可以用来在 Page 对象上添加额外的属性,或修改现有的属性等。
值得一提的是,针对
page.data
和page.routeMeta
的改动可以在客户端代码中使用。示例:
export default { + extendsPage: (page) => { + page.foo = "foo"; + page.data.bar = "bar"; + }, +}; +
在客户端组件中:
`,5),C=p('import { usePageData } from "@vuepress/client"; + +export default { + setup() { + const page = usePageData(); + console.log(page.value.bar); // bar + }, +}; +
# 生命周期 Hooks
# onInitialized
类型:
(app: App) => void | Promise<void>
详情:
该 Hook 会在 VuePress App 初始化后被立即调用。
# onPrepared
类型:
(app: App) => void | Promise<void>
详情:
该 Hook 会在 VuePress App 完成文件准备后被立即调用。
# onWatched
类型:
(app: App, watchers: Closable[], restart: () => Promise<void>) => void | Promise<void>
详情:
该 Hook 会在 VuePress App 启动开发服务器并开始监听文件修改后被调用。
watchers
是一个文件监听器的数组。在修改配置文件导致重启 dev 命令时,这些监听器会被自动关闭。如果你在当前 Hook 中添加了新的监听器,你应该把它们也加入到这个数组中,确保在重启 dev 命令时它们能被正确关闭。
restart
方法用来重启 dev 命令。调用该方法时,watchers
数组中的监听器也会被自动关闭。# onGenerated
',9);function z(I,M){const l=i("NpmBadge"),o=i("ExternalLinkIcon"),e=i("RouterLink");return u(),r("div",null,[k,s(l,{package:"@vuepress/core"}),n("p",null,[a("插件 API 是由 "),n("a",v,[a("@vuepress/core"),s(o)]),a(" 包支持的。你可以查看 "),s(e,{to:"/zh/reference/node-api.html"},{default:t(()=>[a("Node API")]),_:1}),a(" 来了解如何使用插件 Hooks 中的 VuePress App 实例。")]),m,n("blockquote",null,[n("p",null,[a("查看 "),s(e,{to:"/zh/advanced/architecture.html#%E6%A0%B8%E5%BF%83%E6%B5%81%E7%A8%8B%E4%B8%8E-hooks"},{default:t(()=>[a("深入 > 架构 > 核心流程与 Hooks")]),_:1}),a(" 来更好地理解该流程。")])]),h,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/client-api.html#defineclientconfig"},{default:t(()=>[a("客户端 API > defineClientConfig")]),_:1})]),n("li",null,[s(e,{to:"/zh/advanced/cookbook/usage-of-client-config.html"},{default:t(()=>[a("深入 > Cookbook > 客户端配置的使用方法")]),_:1})])])])]),b,n("p",null,[a("添加默认的 "),n("a",g,[a("app.compilerOptions.isCustomElement"),s(o)]),a(" 配置:")]),f,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/bundler/vite.html"},{default:t(()=>[a("打包工具 > Vite")]),_:1})]),n("li",null,[s(e,{to:"/zh/reference/bundler/webpack.html"},{default:t(()=>[a("打包工具 > Webpack")]),_:1})])])])]),_,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/config.html#markdown"},{default:t(()=>[a("配置 > markdown")]),_:1})])])])]),w,n("ul",null,[y,n("li",null,[x,P,n("p",null,[a("该 Hook 接收一个函数,在参数中会收到一个由 "),n("a",O,[a("markdown-it"),s(o)]),a(" 提供的 "),A,a(" 实例。")]),E]),q]),B,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/node-api.html#createPage"},{default:t(()=>[a("Node API > Page > createPage")]),_:1})])])])]),H,n("ul",null,[n("li",null,[a("参考: "),n("ul",null,[n("li",null,[s(e,{to:"/zh/reference/client-api.html#usepagedata"},{default:t(()=>[a("客户端 API > usePageData")]),_:1})]),n("li",null,[s(e,{to:"/zh/reference/node-api.html#data"},{default:t(()=>[a("Node API > Page 属性 > data")]),_:1})]),n("li",null,[s(e,{to:"/zh/reference/node-api.html#routemeta"},{default:t(()=>[a("Node API > Page 属性 > routeMeta")]),_:1})])])])]),C])}const D=c(d,[["render",z],["__file","plugin-api.html.vue"]]);export{D as default}; diff --git a/assets/plugin-api.html-e5d3923f.js b/assets/plugin-api.html-e5d3923f.js new file mode 100644 index 00000000..93662515 --- /dev/null +++ b/assets/plugin-api.html-e5d3923f.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-51569e88","path":"/reference/plugin-api.html","title":"Plugin API","lang":"en-US","frontmatter":{"icon":"fa6-solid:plug","description":"Plugin API is supported by @vuepress/core (https://www.npmjs.com/package/@vuepress/core) package. You could check out Node API (./node-api.md) for how to use the VuePress app in...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Plugin API"}],["meta",{"property":"og:description","content":"Plugin API is supported by @vuepress/core (https://www.npmjs.com/package/@vuepress/core) package. You could check out Node API (./node-api.md) for how to use the VuePress app in..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Plugin API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Overview","slug":"overview","link":"#overview","children":[]},{"level":2,"title":"Basic Options","slug":"basic-options","link":"#basic-options","children":[{"level":3,"title":"name","slug":"name","link":"#name","children":[]},{"level":3,"title":"multiple","slug":"multiple","link":"#multiple","children":[]}]},{"level":2,"title":"Development Hooks","slug":"development-hooks","link":"#development-hooks","children":[{"level":3,"title":"alias","slug":"alias","link":"#alias","children":[]},{"level":3,"title":"clientConfigFile","slug":"clientconfigfile","link":"#clientconfigfile","children":[]},{"level":3,"title":"define","slug":"define","link":"#define","children":[]},{"level":3,"title":"extendsBundlerOptions","slug":"extendsbundleroptions","link":"#extendsbundleroptions","children":[]},{"level":3,"title":"extendsMarkdownOptions","slug":"extendsmarkdownoptions","link":"#extendsmarkdownoptions","children":[]},{"level":3,"title":"extendsMarkdown","slug":"extendsmarkdown","link":"#extendsmarkdown","children":[]},{"level":3,"title":"extendsPageOptions","slug":"extendspageoptions","link":"#extendspageoptions","children":[]},{"level":3,"title":"extendsPage","slug":"extendspage","link":"#extendspage","children":[]}]},{"level":2,"title":"Lifecycle Hooks","slug":"lifecycle-hooks","link":"#lifecycle-hooks","children":[{"level":3,"title":"onInitialized","slug":"oninitialized","link":"#oninitialized","children":[]},{"level":3,"title":"onPrepared","slug":"onprepared","link":"#onprepared","children":[]},{"level":3,"title":"onWatched","slug":"onwatched","link":"#onwatched","children":[]},{"level":3,"title":"onGenerated","slug":"ongenerated","link":"#ongenerated","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":3.68,"words":1104},"filePathRelative":"reference/plugin-api.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/plugin.html-6b68f3b2.js b/assets/plugin.html-6b68f3b2.js new file mode 100644 index 00000000..4579a61f --- /dev/null +++ b/assets/plugin.html-6b68f3b2.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-574aac41","path":"/zh/advanced/plugin.html","title":"开发插件","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:plug","description":"在阅读该指南之前,你最好先了解一下 VuePress 的 架构 (./architecture.md) 。 创建一个插件 插件是一个符合 插件 API (../reference/plugin-api.md) 的普通 JavaScript 对象,称之为 插件对象 : 插件还可以是一个接收 App 实例 (../reference/node-api.md...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/advanced/plugin.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/plugin.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"开发插件"}],["meta",{"property":"og:description","content":"在阅读该指南之前,你最好先了解一下 VuePress 的 架构 (./architecture.md) 。 创建一个插件 插件是一个符合 插件 API (../reference/plugin-api.md) 的普通 JavaScript 对象,称之为 插件对象 : 插件还可以是一个接收 App 实例 (../reference/node-api.md..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"开发插件\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"创建一个插件","slug":"创建一个插件","link":"#创建一个插件","children":[]},{"level":2,"title":"发布到 NPM","slug":"发布到-npm","link":"#发布到-npm","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.15,"words":345},"filePathRelative":"zh/advanced/plugin.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/plugin.html-70d14bec.js b/assets/plugin.html-70d14bec.js new file mode 100644 index 00000000..e0798385 --- /dev/null +++ b/assets/plugin.html-70d14bec.js @@ -0,0 +1,30 @@ +import{_ as l,W as c,X as u,$ as s,a0 as n,Y as a,Z as t,a1 as o,D as i}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"writing-a-plugin",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#writing-a-plugin","aria-hidden":"true"},"#"),n(" Writing a Plugin")],-1),v={class:"hint-container tip"},k=s("p",{class:"hint-container-title"},"Tips",-1),m=s("h2",{id:"create-a-plugin",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#create-a-plugin","aria-hidden":"true"},"#"),n(" Create a Plugin")],-1),h=s("em",null,"Plugin Object",-1),g=o(`
类型:
(app: App) => void | Promise<void>
详情:
该 Hook 会在 VuePress App 完成静态文件生成后被立即调用。
`,1),b=s("em",null,"Plugin Object",-1),_=s("em",null,"Plugin Function",-1),f=o(`const fooPlugin = { + name: "vuepress-plugin-foo", + // ... +}; +
const barPlugin = (app) => { + return { + name: "vuepress-plugin-bar", + // ... + }; +}; +
A plugin usually needs to allow user options, so we typically provide users with a function to receive options, and returns a Plugin Object or a Plugin Function. Then your plugin should be converted like this:
const fooPlugin = (options) => { + return { + name: "vuepress-plugin-foo", + // ... + }; +}; + +const barPlugin = (options) => { + return (app) => { + return { + name: "vuepress-plugin-bar", + // ... + }; + }; +}; +
# Publish to NPM
`,4),y={href:"https://docs.npmjs.com/cli/v8/configuring-npm/package-json",target:"_blank",rel:"noopener noreferrer"},w=o(``,1),x=s("code",null,"name",-1),P=s("code",null,"vuepress-plugin-xxx",-1),q=s("code",null,"@org/vuepress-plugin-xxx",-1),j=s("em",null,"Plugin Object",-1),N=s("li",null,[n("Set "),s("code",null,"keywords"),n(" to include "),s("code",null,"vuepress-plugin"),n(", so that users can search your plugin on NPM.")],-1);function A(V,B){const e=i("RouterLink"),p=i("ExternalLinkIcon");return c(),u("div",null,[d,s("div",v,[k,s("p",null,[n("Before reading this guide, you'd better learn the VuePress "),a(e,{to:"/advanced/architecture.html"},{default:t(()=>[n("architecture")]),_:1}),n(" first.")])]),m,s("p",null,[n("A plugin should be a plain JavaScript object that satisfies the "),a(e,{to:"/reference/plugin-api.html"},{default:t(()=>[n("Plugin API")]),_:1}),n(", which is called a "),h,n(":")]),g,s("p",null,[n("A plugin could also be a function that receives the "),a(e,{to:"/reference/node-api.html#app"},{default:t(()=>[n("app instance")]),_:1}),n(" as the param and returns a "),b,n(", which is called a "),_,n(":")]),f,s("p",null,[n("After creating a plugin, you should follow some conventions in the "),s("a",y,[n("package.json"),a(p)]),n(" file before publishing it to NPM:")]),w,s("ul",null,[s("li",null,[n("Set "),x,n(" to follow the naming convention, i.e. "),P,n(" or "),q,n(", which should be consistent with the "),a(e,{to:"/reference/plugin-api.html#name"},{default:t(()=>[n("name")]),_:1}),n(" field of the "),j,n(".")]),N])])}const O=l(r,[["render",A],["__file","plugin.html.vue"]]);export{O as default}; diff --git a/assets/plugin.html-7408e888.js b/assets/plugin.html-7408e888.js new file mode 100644 index 00000000..b3b227e6 --- /dev/null +++ b/assets/plugin.html-7408e888.js @@ -0,0 +1,30 @@ +import{_ as c,W as l,X as u,$ as s,a0 as n,Y as a,Z as t,a1 as o,D as p}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"开发插件",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#开发插件","aria-hidden":"true"},"#"),n(" 开发插件")],-1),k={class:"hint-container tip"},v=s("p",{class:"hint-container-title"},"提示",-1),m=s("h2",{id:"创建一个插件",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#创建一个插件","aria-hidden":"true"},"#"),n(" 创建一个插件")],-1),h=s("em",null,"插件对象",-1),_=o(`{ + "name": "vuepress-plugin-foo", + "keywords": ["vuepress-plugin"] +} +
`,1),g=s("em",null,"插件对象",-1),b=s("em",null,"插件函数",-1),f=o(`const fooPlugin = { + name: "vuepress-plugin-foo", + // ... +}; +
const barPlugin = (app) => { + return { + name: "vuepress-plugin-bar", + // ... + }; +}; +
插件通常需要允许用户传入配置,因此我们一般都会提供给用户一个函数来接收配置,然后将 插件对象 或者 插件函数 作为返回值。于是,你的插件应该转换成这样的形式:
const fooPlugin = (options) => { + return { + name: "vuepress-plugin-foo", + // ... + }; +}; + +const barPlugin = (options) => { + return (app) => { + return { + name: "vuepress-plugin-bar", + // ... + }; + }; +}; +
# 发布到 NPM
`,4),x={href:"https://docs.npmjs.com/cli/v8/configuring-npm/package-json",target:"_blank",rel:"noopener noreferrer"},y=o(``,1),q=s("code",null,"name",-1),w=s("code",null,"vuepress-plugin-xxx",-1),P=s("code",null,"@org/vuepress-plugin-xxx",-1),N=s("em",null,"插件对象",-1),j=s("li",null,[n("在 "),s("code",null,"keywords"),n(" 中包含 "),s("code",null,"vuepress-plugin"),n(" ,这样用户可以在 NPM 上搜索到你的插件。")],-1);function V(z,L){const e=p("RouterLink"),i=p("ExternalLinkIcon");return l(),u("div",null,[d,s("div",k,[v,s("p",null,[n("在阅读该指南之前,你最好先了解一下 VuePress 的 "),a(e,{to:"/zh/advanced/architecture.html"},{default:t(()=>[n("架构")]),_:1}),n(" 。")])]),m,s("p",null,[n("插件是一个符合 "),a(e,{to:"/zh/reference/plugin-api.html"},{default:t(()=>[n("插件 API")]),_:1}),n(" 的普通 JavaScript 对象,称之为 "),h,n(" :")]),_,s("p",null,[n("插件还可以是一个接收 "),a(e,{to:"/zh/reference/node-api.html#app"},{default:t(()=>[n("App 实例")]),_:1}),n(" 作为参数,且返回值为 "),g,n(" 的函数,称之为 "),b,n(" :")]),f,s("p",null,[n("在创建了插件之后,你需要在 "),s("a",x,[n("package.json"),a(i)]),n(" 文件中遵循一定的约定,然后再将其发布到 NPM 上:")]),y,s("ul",null,[s("li",null,[n("将 "),q,n(" 按照约定命名,即 "),w,n(" 或 "),P,n(" ,它应该和 "),N,n(" 的 "),a(e,{to:"/zh/reference/plugin-api.html#name"},{default:t(()=>[n("name")]),_:1}),n(" 字段保持一致。")]),j])])}const E=c(r,[["render",V],["__file","plugin.html.vue"]]);export{E as default}; diff --git a/assets/plugin.html-95fad35f.js b/assets/plugin.html-95fad35f.js new file mode 100644 index 00000000..7083db28 --- /dev/null +++ b/assets/plugin.html-95fad35f.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-1d14d5cc","path":"/guide/plugin.html","title":"Plugin","lang":"en-US","frontmatter":{"icon":"fa6-solid:plug","description":"With the help of Plugin API (../reference/plugin-api.md), VuePress plugin can provide different features for you. Community Plugin Community users have created lots of plugins a...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/plugin.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/plugin.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Plugin"}],["meta",{"property":"og:description","content":"With the help of Plugin API (../reference/plugin-api.md), VuePress plugin can provide different features for you. Community Plugin Community users have created lots of plugins a..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Plugin\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Community Plugin","slug":"community-plugin","link":"#community-plugin","children":[]},{"level":2,"title":"Local Plugin","slug":"local-plugin","link":"#local-plugin","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.03,"words":309},"filePathRelative":"guide/plugin.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/plugin.html-b89655ab.js b/assets/plugin.html-b89655ab.js new file mode 100644 index 00000000..2807fef5 --- /dev/null +++ b/assets/plugin.html-b89655ab.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-9043126a","path":"/zh/guide/plugin.html","title":"插件","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:plug","description":"借助于 插件 API (../reference/plugin-api.md) , VuePress 插件可以为你提供各种不同的功能。 社区插件 社区用户创建了很多插件,并将它们发布到了 NPM (https://www.npmjs.com/search?q=keywords:vuepress-plugin) 上。 VuePress 团队也在 @vue...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/plugin.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/plugin.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"插件"}],["meta",{"property":"og:description","content":"借助于 插件 API (../reference/plugin-api.md) , VuePress 插件可以为你提供各种不同的功能。 社区插件 社区用户创建了很多插件,并将它们发布到了 NPM (https://www.npmjs.com/search?q=keywords:vuepress-plugin) 上。 VuePress 团队也在 @vue..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"插件\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"社区插件","slug":"社区插件","link":"#社区插件","children":[]},{"level":2,"title":"本地插件","slug":"本地插件","link":"#本地插件","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.48,"words":444},"filePathRelative":"zh/guide/plugin.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/plugin.html-bed3198b.js b/assets/plugin.html-bed3198b.js new file mode 100644 index 00000000..b04e8c0d --- /dev/null +++ b/assets/plugin.html-bed3198b.js @@ -0,0 +1,15 @@ +import{_ as u,W as p,X as c,$ as e,a0 as n,Y as s,Z as t,a1 as l,D as i}from"./framework-46b0e263.js";const r={},d=e("h1",{id:"plugin",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#plugin","aria-hidden":"true"},"#"),n(" Plugin")],-1),g=e("h2",{id:"community-plugin",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#community-plugin","aria-hidden":"true"},"#"),n(" Community Plugin")],-1),h={href:"https://www.npmjs.com/search?q=keywords:vuepress-plugin",target:"_blank",rel:"noopener noreferrer"},m={href:"https://www.npmjs.com/search?q=%40vuepress%20keywords%3Aplugin",target:"_blank",rel:"noopener noreferrer"},f=l(`{ + "name": "vuepress-plugin-foo", + "keywords": ["vuepress-plugin"] +} +
`,1),k={class:"hint-container tip"},v=e("p",{class:"hint-container-title"},"Tips",-1),_=e("p",null,"Most plugins can only be used once. If the same plugin is used multiple times, only the last one will take effect.",-1),y=e("h2",{id:"local-plugin",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#local-plugin","aria-hidden":"true"},"#"),n(" Local Plugin")],-1),b=e("p",null,"If you want to use your own plugin but don't want to publish it, you can create a local plugin.",-1),w=l(`import { googleAnalyticsPlugin } from "@vuepress/plugin-google-analytics"; + +export default { + plugins: [ + googleAnalyticsPlugin({ + id: "G-XXXXXXXXXX", + }), + ], +}; +
But if you have too many things to do in your config file, you can consider to extract them into separate plugins, and use them in your config file:
`,2);function x(P,X){const a=i("RouterLink"),o=i("ExternalLinkIcon");return p(),c("div",null,[d,e("p",null,[n("With the help of "),s(a,{to:"/reference/plugin-api.html"},{default:t(()=>[n("Plugin API")]),_:1}),n(", VuePress plugin can provide different features for you.")]),g,e("p",null,[n("Community users have created lots of plugins and published them to "),e("a",h,[n("NPM"),s(o)]),n(". VuePress team also maintains some official plugins under the "),e("a",m,[n("@vuepress"),s(o)]),n(" scope. You should check the plugin's own documentation for detailed guide.")]),e("p",null,[n("In general, you need to import the plugin and use it in your config file via the "),s(a,{to:"/reference/config.html#plugins"},{default:t(()=>[n("plugins")]),_:1}),n(" option. For example, use the "),s(a,{to:"/reference/plugin/google-analytics.html"},{default:t(()=>[n("@vuepress/plugin-google-analytics")]),_:1}),n(" to integrate Google Analytics:")]),f,e("div",k,[v,_,e("p",null,[n("However, some plugins can be used multiple times (e.g. "),s(a,{to:"/reference/plugin/container.html"},{default:t(()=>[n("@vuepress/plugin-container")]),_:1}),n("), and you should check the documentation of the plugin itself for detailed guide.")])]),y,b,e("p",null,[n("It is recommended to use the "),s(a,{to:"/guide/configuration.html#config-file"},{default:t(()=>[n("Config File")]),_:1}),n(" directly as a plugin, because "),s(a,{to:"/reference/config.html#plugin-api"},{default:t(()=>[n("almost all of the Plugin APIs are available")]),_:1}),n(", which would be more convenient in most cases.")]),w,e("p",null,[n("You can refer to "),s(a,{to:"/advanced/plugin.html"},{default:t(()=>[n("Advanced > Writing a Plugin")]),_:1}),n(" for how to write your own plugin.")])])}const I=u(r,[["render",x],["__file","plugin.html.vue"]]);export{I as default}; diff --git a/assets/plugin.html-d44754d7.js b/assets/plugin.html-d44754d7.js new file mode 100644 index 00000000..8268b620 --- /dev/null +++ b/assets/plugin.html-d44754d7.js @@ -0,0 +1,15 @@ +import{_ as l,W as c,X as u,$ as s,a0 as n,Y as a,Z as t,a1 as i,D as p}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"插件",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#插件","aria-hidden":"true"},"#"),n(" 插件")],-1),k=s("h2",{id:"社区插件",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#社区插件","aria-hidden":"true"},"#"),n(" 社区插件")],-1),h={href:"https://www.npmjs.com/search?q=keywords:vuepress-plugin",target:"_blank",rel:"noopener noreferrer"},g={href:"https://www.npmjs.com/search?q=%40vuepress%20keywords%3Aplugin",target:"_blank",rel:"noopener noreferrer"},m=i(`import myPlugin from "./path/to/my-plugin.js"; + +export default { + plugins: [myPlugin()], +}; +
`,1),v={class:"hint-container tip"},_=s("p",{class:"hint-container-title"},"提示",-1),f=s("p",null,"大部分插件只能使用一次,如果同一个插件被多次使用,那么只有最后一次会生效。",-1),b=s("h2",{id:"本地插件",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#本地插件","aria-hidden":"true"},"#"),n(" 本地插件")],-1),y=s("p",null,"如果你想要使用自己的插件,但是又不想发布它,你可以创建一个本地插件。",-1),w=i(`import { googleAnalyticsPlugin } from "@vuepress/plugin-google-analytics"; + +export default { + plugins: [ + googleAnalyticsPlugin({ + id: "G-XXXXXXXXXX", + }), + ], +}; +
但是如果你在配置文件中要做的事情太多了,你可以考虑将它们提取到单独的插件中,然后在你的配置文件中使用它们:
`,2);function x(X,B){const e=p("RouterLink"),o=p("ExternalLinkIcon");return c(),u("div",null,[d,s("p",null,[n("借助于 "),a(e,{to:"/zh/reference/plugin-api.html"},{default:t(()=>[n("插件 API")]),_:1}),n(" , VuePress 插件可以为你提供各种不同的功能。")]),k,s("p",null,[n("社区用户创建了很多插件,并将它们发布到了 "),s("a",h,[n("NPM"),a(o)]),n(" 上。 VuePress 团队也在 "),s("a",g,[n("@vuepress"),a(o)]),n(" Scope 下维护了一些官方插件。查看插件本身的文档可以获取更详细的指引。")]),s("p",null,[n("一般而言,你需要导入插件并通过配置文件的 "),a(e,{to:"/zh/reference/config.html#plugins"},{default:t(()=>[n("plugins")]),_:1}),n(" 配置项来使用它。举例来说,你可以使用 "),a(e,{to:"/zh/reference/plugin/google-analytics.html"},{default:t(()=>[n("@vuepress/plugin-google-analytics")]),_:1}),n(" 来使用 Google Analytics :")]),m,s("div",v,[_,f,s("p",null,[n("然而,部分插件是可以被多次使用的(例如 "),a(e,{to:"/zh/reference/plugin/container.html"},{default:t(()=>[n("@vuepress/plugin-container")]),_:1}),n("),你应该查看插件本身的文档来获取详细指引。")])]),b,y,s("p",null,[n("我们推荐你直接将 "),a(e,{to:"/zh/guide/configuration.html#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"},{default:t(()=>[n("配置文件")]),_:1}),n(" 作为插件使用,因为 "),a(e,{to:"/zh/reference/config.html#%E6%8F%92%E4%BB%B6-api"},{default:t(()=>[n("几乎所有的插件 API 都可以在配置文件中使用")]),_:1}),n(",这在绝大多数场景下都更为方便。")]),w,s("p",null,[n("前往 "),a(e,{to:"/zh/advanced/plugin.html"},{default:t(()=>[n("深入 > 开发插件")]),_:1}),n(" 学习如何开发你自己的插件。")])])}const P=l(r,[["render",x],["__file","plugin.html.vue"]]);export{P as default}; diff --git a/assets/plugin.html-ebe09bff.js b/assets/plugin.html-ebe09bff.js new file mode 100644 index 00000000..ec26cc41 --- /dev/null +++ b/assets/plugin.html-ebe09bff.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-301ab792","path":"/advanced/plugin.html","title":"Writing a Plugin","lang":"en-US","frontmatter":{"icon":"fa6-solid:plug","description":"Before reading this guide, you'd better learn the VuePress architecture (./architecture.md) first. Create a Plugin A plugin should be a plain JavaScript object that satisfies th...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/plugin.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/plugin.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Writing a Plugin"}],["meta",{"property":"og:description","content":"Before reading this guide, you'd better learn the VuePress architecture (./architecture.md) first. Create a Plugin A plugin should be a plain JavaScript object that satisfies th..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Writing a Plugin\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Create a Plugin","slug":"create-a-plugin","link":"#create-a-plugin","children":[]},{"level":2,"title":"Publish to NPM","slug":"publish-to-npm","link":"#publish-to-npm","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.82,"words":247},"filePathRelative":"advanced/plugin.md","localizedDate":"February 22, 2023","autoDesc":true}`);export{e as data}; diff --git a/assets/prismjs.html-1adf5589.js b/assets/prismjs.html-1adf5589.js new file mode 100644 index 00000000..70af9ae7 --- /dev/null +++ b/assets/prismjs.html-1adf5589.js @@ -0,0 +1,11 @@ +import{_ as l,W as o,X as p,Y as a,$ as n,a0 as s,a1 as r,D as t}from"./framework-46b0e263.js";const c={},d=n("h1",{id:"prismjs",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#prismjs","aria-hidden":"true"},"#"),s(" prismjs")],-1),u={href:"https://prismjs.com/",target:"_blank",rel:"noopener noreferrer"},m=r(`import myPlugin from "./path/to/my-plugin.js"; + +export default { + plugins: [myPlugin()], +}; +
该插件已经集成到默认主题中。
需要注意的是,该插件仅会给代码块添加 HTML 标记,而不会添加样式。当你在一个自定义主题中使用它时,可能需要自己选择并引入 Prism.js 样式主题。
# 使用方法
npm i -D @vuepress/plugin-prismjs@next +
import { prismjsPlugin } from "@vuepress/plugin-prismjs"; + +export default { + plugins: [ + prismjsPlugin({ + // 配置项 + }), + ], +}; +
# 配置项
# preloadLanguages
`,7),h=n("li",null,[n("p",null,[s("类型: "),n("code",null,"string[]")])],-1),k=n("li",null,[n("p",null,[s("默认值: "),n("code",null,"['markdown', 'jsdoc', 'yaml']")])],-1),_=n("p",null,"详情:",-1),v=n("p",null,"需要预加载的语言。",-1),g=n("p",null,"默认情况下,语言会在解析 Markdown 文件时按需加载。",-1),b={href:"https://github.com/PrismJS/prism/issues/2716",target:"_blank",rel:"noopener noreferrer"};function f(j,x){const i=t("NpmBadge"),e=t("ExternalLinkIcon");return o(),p("div",null,[d,a(i,{package:"@vuepress/plugin-prismjs"}),n("p",null,[s("该插件使用 "),n("a",u,[s("Prism.js"),a(e)]),s(" 来为 Markdown 代码块启用代码高亮。")]),m,n("ul",null,[h,k,n("li",null,[_,v,g,n("p",null,[s("然而, Prism.js 在动态加载语言时可能会遇到 "),n("a",b,[s("一些潜在的问题"),a(e)]),s(" 。为了避免这些问题,你可以使用该配置项来预加载一些语言。")])])])])}const y=l(c,[["render",f],["__file","prismjs.html.vue"]]);export{y as default}; diff --git a/assets/prismjs.html-22d9c496.js b/assets/prismjs.html-22d9c496.js new file mode 100644 index 00000000..829f7dd0 --- /dev/null +++ b/assets/prismjs.html-22d9c496.js @@ -0,0 +1,11 @@ +import{_ as o,W as l,X as p,Y as e,$ as n,a0 as s,a1 as r,D as t}from"./framework-46b0e263.js";const c={},d=n("h1",{id:"prismjs",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#prismjs","aria-hidden":"true"},"#"),s(" prismjs")],-1),u={href:"https://prismjs.com/",target:"_blank",rel:"noopener noreferrer"},h=r(`This plugin has been integrated into the default theme.
Notice that this plugin would only tokenize the code fence without adding styles. When using it with a custom theme, you may need to choose and import Prism.js style theme yourself.
# Usage
npm i -D @vuepress/plugin-prismjs@next +
import { prismjsPlugin } from "@vuepress/plugin-prismjs"; + +export default { + plugins: [ + prismjsPlugin({ + // options + }), + ], +}; +
# Options
# preloadLanguages
`,7),m=n("li",null,[n("p",null,[s("Type: "),n("code",null,"string[]")])],-1),g=n("li",null,[n("p",null,[s("Default: "),n("code",null,"['markdown', 'jsdoc', 'yaml']")])],-1),k=n("p",null,"Details:",-1),v=n("p",null,"Languages to preload.",-1),_=n("p",null,"By default, languages will be loaded on demand when parsing markdown files.",-1),b={href:"https://github.com/PrismJS/prism/issues/2716",target:"_blank",rel:"noopener noreferrer"};function f(y,j){const i=t("NpmBadge"),a=t("ExternalLinkIcon");return l(),p("div",null,[d,e(i,{package:"@vuepress/plugin-prismjs"}),n("p",null,[s("This plugin will enable syntax highlighting for markdown code fence with "),n("a",u,[s("Prism.js"),e(a)]),s(".")]),h,n("ul",null,[m,g,n("li",null,[k,v,_,n("p",null,[s("However, Prism.js has "),n("a",b,[s("some potential issues"),e(a)]),s(" about loading languages dynamically. To avoid them, you can preload languages via this option.")])])])])}const x=o(c,[["render",f],["__file","prismjs.html.vue"]]);export{x as default}; diff --git a/assets/prismjs.html-b41398b8.js b/assets/prismjs.html-b41398b8.js new file mode 100644 index 00000000..2e11ff83 --- /dev/null +++ b/assets/prismjs.html-b41398b8.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-9cba4982","path":"/zh/reference/plugin/prismjs.html","title":"prismjs","lang":"zh-CN","frontmatter":{"description":"该插件使用 Prism.js (https://prismjs.com/) 来为 Markdown 代码块启用代码高亮。 该插件已经集成到默认主题中。 需要注意的是,该插件仅会给代码块添加 HTML 标记,而不会添加样式。当你在一个自定义主题中使用它时,可能需要自己选择并引入 Prism.js 样式主题。 使用方法 配置项 preloadLanguag...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/prismjs.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/prismjs.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"prismjs"}],["meta",{"property":"og:description","content":"该插件使用 Prism.js (https://prismjs.com/) 来为 Markdown 代码块启用代码高亮。 该插件已经集成到默认主题中。 需要注意的是,该插件仅会给代码块添加 HTML 标记,而不会添加样式。当你在一个自定义主题中使用它时,可能需要自己选择并引入 Prism.js 样式主题。 使用方法 配置项 preloadLanguag..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"prismjs\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"preloadLanguages","slug":"preloadlanguages","link":"#preloadlanguages","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.74,"words":223},"filePathRelative":"zh/reference/plugin/prismjs.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/prismjs.html-c9458bed.js b/assets/prismjs.html-c9458bed.js new file mode 100644 index 00000000..f7016f92 --- /dev/null +++ b/assets/prismjs.html-c9458bed.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-35ebfb0e","path":"/reference/plugin/prismjs.html","title":"prismjs","lang":"en-US","frontmatter":{"description":"This plugin will enable syntax highlighting for markdown code fence with Prism.js (https://prismjs.com/). This plugin has been integrated into the default theme. Notice that thi...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/prismjs.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/prismjs.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"prismjs"}],["meta",{"property":"og:description","content":"This plugin will enable syntax highlighting for markdown code fence with Prism.js (https://prismjs.com/). This plugin has been integrated into the default theme. Notice that thi..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"prismjs\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"preloadLanguages","slug":"preloadlanguages","link":"#preloadlanguages","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.45,"words":136},"filePathRelative":"reference/plugin/prismjs.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/pwa-popup.html-7ff33522.js b/assets/pwa-popup.html-7ff33522.js new file mode 100644 index 00000000..eb835a99 --- /dev/null +++ b/assets/pwa-popup.html-7ff33522.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6df47ee0","path":"/zh/reference/plugin/pwa-popup.html","title":"pwa-popup","lang":"zh-CN","frontmatter":{"description":"提供一个弹窗组件,允许用户手动刷新 PWA Service Worker 。 该插件必须和 pwa 插件 (./pwa.md) 一起使用,并且 skipWaiting 配置项不能设置为 true 。 当新的 Service Worker 就绪时,会在页面右下角出现一个弹窗,询问用户是否需要激活处于 Waiting 状态的 Service Worker ...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/pwa-popup.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/pwa-popup.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"pwa-popup"}],["meta",{"property":"og:description","content":"提供一个弹窗组件,允许用户手动刷新 PWA Service Worker 。 该插件必须和 pwa 插件 (./pwa.md) 一起使用,并且 skipWaiting 配置项不能设置为 true 。 当新的 Service Worker 就绪时,会在页面右下角出现一个弹窗,询问用户是否需要激活处于 Waiting 状态的 Service Worker ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"pwa-popup\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"locales","slug":"locales","link":"#locales","children":[]}]},{"level":2,"title":"样式","slug":"样式","link":"#样式","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.85,"words":255},"filePathRelative":"zh/reference/plugin/pwa-popup.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/pwa-popup.html-a135b6f9.js b/assets/pwa-popup.html-a135b6f9.js new file mode 100644 index 00000000..28dc8b46 --- /dev/null +++ b/assets/pwa-popup.html-a135b6f9.js @@ -0,0 +1,30 @@ +import{_ as l,W as c,X as u,Y as a,$ as n,a0 as s,Z as p,a1 as o,D as t}from"./framework-46b0e263.js";const r={},d=n("h1",{id:"pwa-popup",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pwa-popup","aria-hidden":"true"},"#"),s(" pwa-popup")],-1),k=n("p",null,"提供一个弹窗组件,允许用户手动刷新 PWA Service Worker 。",-1),v=n("code",null,"skipWaiting",-1),m=n("code",null,"true",-1),h=o(`当新的 Service Worker 就绪时,会在页面右下角出现一个弹窗,询问用户是否需要激活处于 Waiting 状态的 Service Worker 。
# 使用方法
npm i -D @vuepress/plugin-pwa-popup@next +
import { pwaPlugin } from "@vuepress/plugin-pwa"; +import { pwaPopupPlugin } from "@vuepress/plugin-pwa-popup"; + +export default { + plugins: [ + pwaPlugin(), + pwaPopupPlugin({ + // 配置项 + }), + ], +}; +
# 配置项
# locales
类型:
Record<string, { message: string, buttonText: string }>
详情:
弹窗在不同 locales 下的信息。
如果没有指定该配置项,它会降级使用默认信息。
示例:
`,8),g=o('export default { + plugins: [ + pwaPlugin(), + pwaPopupPlugin({ + locales: { + "/": { + message: "New content is available.", + buttonText: "Refresh", + }, + "/zh/": { + message: "发现新内容可用", + buttonText: "刷新", + }, + }, + }), + ], +}; +
# 样式
你可以通过 CSS 变量来自定义弹窗的样式:
',3);function b(_,w){const i=t("NpmBadge"),e=t("RouterLink");return c(),u("div",null,[d,a(i,{package:"@vuepress/plugin-pwa-popup"}),k,n("p",null,[s("该插件必须和 "),a(e,{to:"/zh/reference/plugin/pwa.html"},{default:p(()=>[s("pwa 插件")]),_:1}),s(" 一起使用,并且 "),v,s(" 配置项不能设置为 "),m,s(" 。")]),h,n("ul",null,[n("li",null,[s("参考: "),n("ul",null,[n("li",null,[a(e,{to:"/zh/guide/i18n.html"},{default:p(()=>[s("指南 > 多语言支持")]),_:1})])])])]),g])}const x=l(r,[["render",b],["__file","pwa-popup.html.vue"]]);export{x as default}; diff --git a/assets/pwa-popup.html-bb82625d.js b/assets/pwa-popup.html-bb82625d.js new file mode 100644 index 00000000..74f85f78 --- /dev/null +++ b/assets/pwa-popup.html-bb82625d.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5f86289f","path":"/reference/plugin/pwa-popup.html","title":"pwa-popup","lang":"en-US","frontmatter":{"description":"Provide a popup component for users to activate the new PWA service worker manually. This plugin must be used together with pwa plugin (./pwa.md), and the skipWaiting option mus...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/pwa-popup.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/pwa-popup.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"pwa-popup"}],["meta",{"property":"og:description","content":"Provide a popup component for users to activate the new PWA service worker manually. This plugin must be used together with pwa plugin (./pwa.md), and the skipWaiting option mus..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"pwa-popup\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"locales","slug":"locales","link":"#locales","children":[]}]},{"level":2,"title":"Styles","slug":"styles","link":"#styles","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.67,"words":202},"filePathRelative":"reference/plugin/pwa-popup.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/pwa-popup.html-f245bee2.js b/assets/pwa-popup.html-f245bee2.js new file mode 100644 index 00000000..bb8d6f9f --- /dev/null +++ b/assets/pwa-popup.html-f245bee2.js @@ -0,0 +1,30 @@ +import{_ as l,W as c,X as u,Y as a,$ as n,a0 as s,Z as t,a1 as o,D as p}from"./framework-46b0e263.js";const r={},d=n("h1",{id:"pwa-popup",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pwa-popup","aria-hidden":"true"},"#"),s(" pwa-popup")],-1),k=n("p",null,"Provide a popup component for users to activate the new PWA service worker manually.",-1),v=n("code",null,"skipWaiting",-1),m=n("code",null,"true",-1),h=o(`File not found
When the new service worker is ready, a popup will appear in the right bottom of the page to ask users to activate the waiting service worker.
# Usage
npm i -D @vuepress/plugin-pwa-popup@next +
import { pwaPlugin } from "@vuepress/plugin-pwa"; +import { pwaPopupPlugin } from "@vuepress/plugin-pwa-popup"; + +export default { + plugins: [ + pwaPlugin(), + pwaPopupPlugin({ + // options + }), + ], +}; +
# Options
# locales
Type:
Record<string, { message: string, buttonText: string }>
Details:
The messages of the popup in different locales.
If this option is not specified, it will fallback to default messages.
Example:
`,8),g=o('export default { + plugins: [ + pwaPlugin(), + pwaPopupPlugin({ + locales: { + "/": { + message: "New content is available.", + buttonText: "Refresh", + }, + "/zh/": { + message: "发现新内容可用", + buttonText: "刷新", + }, + }, + }), + ], +}; +
# Styles
You can customize the style of the popup via CSS variables:
',3);function b(f,w){const i=p("NpmBadge"),e=p("RouterLink");return c(),u("div",null,[d,a(i,{package:"@vuepress/plugin-pwa-popup"}),k,n("p",null,[s("This plugin must be used together with "),a(e,{to:"/reference/plugin/pwa.html"},{default:t(()=>[s("pwa plugin")]),_:1}),s(", and the "),v,s(" option must not be set to "),m,s(".")]),h,n("ul",null,[n("li",null,[s("Also see: "),n("ul",null,[n("li",null,[a(e,{to:"/guide/i18n.html"},{default:t(()=>[s("Guide > I18n")]),_:1})])])])]),g])}const y=l(r,[["render",b],["__file","pwa-popup.html.vue"]]);export{y as default}; diff --git a/assets/pwa.html-48090ed1.js b/assets/pwa.html-48090ed1.js new file mode 100644 index 00000000..68c0dd95 --- /dev/null +++ b/assets/pwa.html-48090ed1.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-01fcaa4f","path":"/zh/reference/plugin/pwa.html","title":"pwa","lang":"zh-CN","frontmatter":{"description":"使你的 VuePress 站点成为一个 渐进式 Web 应用 (PWA) (https://developer.mozilla.org/zh-CN/docs/Web/Progressivewebapps). 该插件使用 workbox-build (https://developers.google.com/web/tools/workbox/modu...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/pwa.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/pwa.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"pwa"}],["meta",{"property":"og:description","content":"使你的 VuePress 站点成为一个 渐进式 Web 应用 (PWA) (https://developer.mozilla.org/zh-CN/docs/Web/Progressivewebapps). 该插件使用 workbox-build (https://developers.google.com/web/tools/workbox/modu..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"pwa\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"Web App Manifests","slug":"web-app-manifests","link":"#web-app-manifests","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"serviceWorkerFilename","slug":"serviceworkerfilename","link":"#serviceworkerfilename","children":[]}]},{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"usePwaEvent","slug":"usepwaevent","link":"#usepwaevent","children":[]},{"level":3,"title":"useSkipWaiting","slug":"useskipwaiting","link":"#useskipwaiting","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.68,"words":803},"filePathRelative":"zh/reference/plugin/pwa.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/pwa.html-4dcccf61.js b/assets/pwa.html-4dcccf61.js new file mode 100644 index 00000000..ee8edb89 --- /dev/null +++ b/assets/pwa.html-4dcccf61.js @@ -0,0 +1,68 @@ +import{_ as c,W as u,X as r,Y as a,$ as n,a0 as s,Z as p,a1 as t,D as i}from"./framework-46b0e263.js";const d={},k=n("h1",{id:"pwa",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pwa","aria-hidden":"true"},"#"),s(" pwa")],-1),v={href:"https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps",target:"_blank",rel:"noopener noreferrer"},m={href:"https://developers.google.com/web/tools/workbox/modules/workbox-build",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/yyx990803/register-service-worker",target:"_blank",rel:"noopener noreferrer"},g=t(`File not found
# Usage
npm i -D @vuepress/plugin-pwa@next +
import { pwaPlugin } from "@vuepress/plugin-pwa"; + +export default { + plugins: [ + pwaPlugin({ + // options + }), + ], +}; +
# Web App Manifests
`,4),b={href:"https://developer.mozilla.org/en-US/docs/Web/Manifest",target:"_blank",rel:"noopener noreferrer"},f=n("code",null,".vuepress/public",-1),_=t(`
- Create manifest file
Typically
.vuepress/public/manifest.webmanifest
:{ + "name": "VuePress", + "short_name": "VuePress", + "description": "Vue-powered Static Site Generator", + "start_url": "/index.html", + "display": "standalone", + "background_color": "#fff", + "theme_color": "#3eaf7c", + "icons": [ + { + "src": "/images/icons/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/images/icons/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ] +} +
- Generate PWA icons
To make your PWA more accessible, you need to generate some icons, and put them inside the public directory.
Make sure the path of icons matches the
icons
field in your manifest file:`,7),w={class:"hint-container tip"},y=n("p",{class:"hint-container-title"},"Tips",-1),q={href:"https://realfavicongenerator.net/",target:"_blank",rel:"noopener noreferrer"},x=n("ol",{start:"3"},[n("li",null,"Set tags in head")],-1),W={href:"https://developer.mozilla.org/en-US/docs/Web/Manifest#deploying_a_manifest_with_the_link_tag",target:"_blank",rel:"noopener noreferrer"},P=t(`
.vuepress/public/images/icons/android-chrome-192x192.png
.vuepress/public/images/icons/android-chrome-384x384.png
export default { + head: [ + ["link", { rel: "manifest", href: "/manifest.webmanifest" }], + ["meta", { name: "theme-color", content: "#3eaf7c" }], + // ...other tags + ], +}; +
# Options
`,2),S={href:"https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.generateSW",target:"_blank",rel:"noopener noreferrer"},T=n("code",null,"globDirectory",-1),A=n("code",null,"swDest",-1),E=t(`For example, you can set
skipWaiting: true
to auto activate the new service worker once it is ready:export default { + plugins: [ + pwaPlugin({ + skipWaiting: true, + }), + ], +}; +
But if you omit
`,3),D=n("li",null,[s("For developers, you can use our "),n("a",{href:"#composition-api"},"composition API"),s(" to take control of the service worker behavior.")],-1),V=n("h3",{id:"serviceworkerfilename",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#serviceworkerfilename","aria-hidden":"true"},"#"),s(" serviceWorkerFilename")],-1),F=n("li",null,[n("p",null,[s("Type: "),n("code",null,"string")])],-1),z=n("li",null,[n("p",null,[s("Default: "),n("code",null,"'service-worker.js'")])],-1),B=n("p",null,"Details:",-1),I=n("p",null,[s("The service worker file will only be generated in "),n("code",null,"build"),s(" mode.")],-1),N=n("h2",{id:"composition-api",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#composition-api","aria-hidden":"true"},"#"),s(" Composition API")],-1),C=n("h3",{id:"usepwaevent",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#usepwaevent","aria-hidden":"true"},"#"),s(" usePwaEvent")],-1),M=n("p",null,"Details:",-1),U=n("p",null,"Returns the event emitter of this plugin.",-1),j={href:"https://github.com/yyx990803/register-service-worker",target:"_blank",rel:"noopener noreferrer"},G=n("li",null,[n("p",null,"Example:")],-1),L=t(`skipWaiting
or set it tofalse
, you have to activate the new service worker manually:import { usePwaEvent } from "@vuepress/plugin-pwa/client"; + +export default { + setup() { + const event = usePwaEvent(); + event.on("ready", (registration) => { + console.log("Service worker is active."); + }); + }, +}; +
# useSkipWaiting
- Parameters:
`,4),R=n("p",null,"Details:",-1),Y={href:"https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting",target:"_blank",rel:"noopener noreferrer"},O=n("li",null,[n("p",null,"Example:")],-1),X=t(`
Parameter Type Description registration ServiceWorkerRegistration
The registration of the service worker you want activate `,1);function Z($,H){const l=i("NpmBadge"),e=i("ExternalLinkIcon"),o=i("RouterLink");return u(),r("div",null,[k,a(l,{package:"@vuepress/plugin-pwa"}),n("p",null,[s("Make your VuePress site a "),n("a",v,[s("Progressive Web Application (PWA)"),a(e)]),s(".")]),n("p",null,[s("This plugin uses "),n("a",m,[s("workbox-build"),a(e)]),s(" to generate service worker file, and uses "),n("a",h,[s("register-service-worker"),a(e)]),s(" to register service worker.")]),g,n("p",null,[s("To make your website fully compliant with PWA, you need to create a "),n("a",b,[s("Web app manifests"),a(e)]),s(" file and set the icons, colors, etc. for your PWA.")]),n("p",null,[s("You need to put your manifest file and icons into the "),a(o,{to:"/guide/assets.html#public-files"},{default:p(()=>[s("public files directory")]),_:1}),s(". In the following example, we assume that you are using the default public directory "),f,s(".")]),_,n("div",w,[y,n("p",null,[s("Some tools can help to do that. For example, "),n("a",q,[s("Favicon Generator"),a(e)]),s(" would help you to generate icons together with a sample manifest file.")])]),x,n("p",null,[s("You also need to set some tags via "),a(o,{to:"/reference/config.html#head"},{default:p(()=>[s("head")]),_:1}),s(" option to "),n("a",W,[s("deploy the manifest"),a(e)]),s(":")]),P,n("p",null,[s("This plugin accepts all parameters of workbox-build's "),n("a",S,[s("generateSW method"),a(e)]),s(" in its options, except "),T,s(" and "),A,s(".")]),E,n("ul",null,[n("li",null,[s("For users, you can use our "),a(o,{to:"/reference/plugin/pwa-popup.html"},{default:p(()=>[s("pwa-popup")]),_:1}),s(" plugin together.")]),D]),V,n("ul",null,[F,z,n("li",null,[B,n("p",null,[s("File path of the generated service worker file, which is relative to the "),a(o,{to:"/reference/config.html#dest"},{default:p(()=>[s("dest")]),_:1}),s(" directory.")]),I])]),N,C,n("ul",null,[n("li",null,[M,U,n("p",null,[s("You can add listener function to events that provided by "),n("a",j,[s("register-service-worker"),a(e)]),s(".")])]),G]),L,n("ul",null,[n("li",null,[R,n("p",null,[s("Call "),n("a",Y,[s("skipWaiting()"),a(e)]),s(" to activate the waiting service worker.")])]),O]),X])}const K=c(d,[["render",Z],["__file","pwa.html.vue"]]);export{K as default}; diff --git a/assets/pwa.html-80ca55ab.js b/assets/pwa.html-80ca55ab.js new file mode 100644 index 00000000..3a14c87f --- /dev/null +++ b/assets/pwa.html-80ca55ab.js @@ -0,0 +1,68 @@ +import{_ as l,W as u,X as r,Y as a,$ as n,a0 as s,Z as p,a1 as t,D as i}from"./framework-46b0e263.js";const d={},k=n("h1",{id:"pwa",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pwa","aria-hidden":"true"},"#"),s(" pwa")],-1),v={href:"https://developer.mozilla.org/zh-CN/docs/Web/Progressive_web_apps",target:"_blank",rel:"noopener noreferrer"},m={href:"https://developers.google.com/web/tools/workbox/modules/workbox-build",target:"_blank",rel:"noopener noreferrer"},h={href:"https://github.com/yyx990803/register-service-worker",target:"_blank",rel:"noopener noreferrer"},b=t(`import { usePwaEvent, useSkipWaiting } from "@vuepress/plugin-pwa/client"; + +export default { + setup() { + const event = usePwaEvent(); + event.on("updated", (registration) => { + console.log("The waiting service worker is available."); + // activate the waiting service worker + useSkipWaiting(registration); + }); + }, +}; +
# 使用方法
npm i -D @vuepress/plugin-pwa@next +
import { pwaPlugin } from "@vuepress/plugin-pwa"; + +export default { + plugins: [ + pwaPlugin({ + // 配置项 + }), + ], +}; +
# Web App Manifests
`,4),g={href:"https://developer.mozilla.org/zh-CN/docs/Web/Manifest",target:"_blank",rel:"noopener noreferrer"},_=n("code",null,".vuepress/public",-1),f=t(`
- 创建 Manifest 文件
通常是
.vuepress/public/manifest.webmanifest
:{ + "name": "VuePress", + "short_name": "VuePress", + "description": "Vue-powered Static Site Generator", + "start_url": "/index.html", + "display": "standalone", + "background_color": "#fff", + "theme_color": "#3eaf7c", + "icons": [ + { + "src": "/images/icons/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/images/icons/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ] +} +
- 生成 PWA 图标
为了提高你的 PWA 的可用性,你需要生成一些图标,并将它们放置在 Public 目录下。
确保图标的路径匹配 Manifest 文件中的
icons
字段:`,7),q={class:"hint-container tip"},w=n("p",{class:"hint-container-title"},"提示",-1),y={href:"https://realfavicongenerator.net/",target:"_blank",rel:"noopener noreferrer"},x=n("ol",{start:"3"},[n("li",null,"设置 Head 中的标签")],-1),W={href:"https://developer.mozilla.org/en-US/docs/Web/Manifest#deploying_a_manifest_with_the_link_tag",target:"_blank",rel:"noopener noreferrer"},S=t(`
.vuepress/public/images/icons/android-chrome-192x192.png
.vuepress/public/images/icons/android-chrome-384x384.png
export default { + head: [ + ["link", { rel: "manifest", href: "/manifest.webmanifest" }], + ["meta", { name: "theme-color", content: "#3eaf7c" }], + // ...其他标签 + ], +}; +
# 配置项
`,2),P={href:"https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.generateSW",target:"_blank",rel:"noopener noreferrer"},z=n("code",null,"globDirectory",-1),E=n("code",null,"swDest",-1),A=t(`比如,你可以设置
skipWaiting: true
,这将在新的 Service Worker 就绪之后立即激活它:export default { + plugins: [ + pwaPlugin({ + skipWaiting: true, + }), + ], +}; +
但是如果你不设置
`,3),B=n("li",null,[s("对于开发者,你可以使用该插件提供的 "),n("a",{href:"#composition-api"},"Composition API"),s(" 来控制 Service Worker 的行为。")],-1),M=n("h3",{id:"serviceworkerfilename",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#serviceworkerfilename","aria-hidden":"true"},"#"),s(" serviceWorkerFilename")],-1),N=n("li",null,[n("p",null,[s("类型: "),n("code",null,"string")])],-1),V=n("li",null,[n("p",null,[s("默认值: "),n("code",null,"'service-worker.js'")])],-1),C=n("p",null,"详情:",-1),I=n("p",null,[s("Service Worker 文件只会在 "),n("code",null,"build"),s(" 模式下生成。")],-1),j=n("h2",{id:"composition-api",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#composition-api","aria-hidden":"true"},"#"),s(" Composition API")],-1),D=n("h3",{id:"usepwaevent",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#usepwaevent","aria-hidden":"true"},"#"),s(" usePwaEvent")],-1),L=n("p",null,"详情:",-1),R=n("p",null,"返回该插件的 Event Emitter 。",-1),G={href:"https://github.com/yyx990803/register-service-worker",target:"_blank",rel:"noopener noreferrer"},F=n("li",null,[n("p",null,"示例:")],-1),U=t(`skipWaiting
或设置为false
,你就需要手动激活新的 Service Worker 。import { usePwaEvent } from "@vuepress/plugin-pwa/client"; + +export default { + setup() { + const event = usePwaEvent(); + event.on("ready", (registration) => { + console.log("Service worker 已经生效。"); + }); + }, +}; +
# useSkipWaiting
- 参数:
`,4),H=n("p",null,"详情:",-1),T={href:"https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting",target:"_blank",rel:"noopener noreferrer"},X=n("li",null,[n("p",null,"示例:")],-1),Y=t(`
参数 类型 描述 registration ServiceWorkerRegistration
你想要激活的 Service Worker 的 Registration `,1);function Z($,J){const c=i("NpmBadge"),e=i("ExternalLinkIcon"),o=i("RouterLink");return u(),r("div",null,[k,a(c,{package:"@vuepress/plugin-pwa"}),n("p",null,[s("使你的 VuePress 站点成为一个 "),n("a",v,[s("渐进式 Web 应用 (PWA)"),a(e)]),s(".")]),n("p",null,[s("该插件使用 "),n("a",m,[s("workbox-build"),a(e)]),s(" 来生成 Service Worker 文件,并通过 "),n("a",h,[s("register-service-worker"),a(e)]),s(" 来注册 Service Worker 。")]),b,n("p",null,[s("为了使你的网站符合 PWA 的要求,你需要创建一个 "),n("a",g,[s("Web app manifests"),a(e)]),s(" 文件,并且为你的 PWA 设置图标、颜色等信息。")]),n("p",null,[s("你需要将你的 Manifest 文件和图标放置在 "),a(o,{to:"/zh/guide/assets.html#public-%E6%96%87%E4%BB%B6"},{default:p(()=>[s("Public 目录")]),_:1}),s(" 下。在下述的示例中,我们假设你正在使用默认的 Public 目录 "),_,s(" 。")]),f,n("div",q,[w,n("p",null,[s("一些工具可以帮助你做这些事。比如 "),n("a",y,[s("Favicon Generator"),a(e)]),s(" 可以帮助你生成图片以及一个 Manifest 文件样例。")])]),x,n("p",null,[s("你还需要通过 "),a(o,{to:"/zh/reference/config.html#head"},{default:p(()=>[s("head")]),_:1}),s(" 配置项来设置一些标签,用来 "),n("a",W,[s("部署你的 Manifest 文件"),a(e)]),s(" 。")]),S,n("p",null,[s("该插件的配置项可以接收 workbox-build 中 "),n("a",P,[s("generateSW 方法"),a(e)]),s(" 除了 "),z,s(" 和 "),E,s(" 以外的所有参数。")]),A,n("ul",null,[n("li",null,[s("对于用户,你可以配合我们提供的 "),a(o,{to:"/zh/reference/plugin/pwa-popup.html"},{default:p(()=>[s("pwa-popup")]),_:1}),s(" 插件一起使用。")]),B]),M,n("ul",null,[N,V,n("li",null,[C,n("p",null,[s("生成的 Service Worker 文件路径,该路径是 "),a(o,{to:"/zh/reference/config.html#dest"},{default:p(()=>[s("dest")]),_:1}),s(" 目录的相对路径。")]),I])]),j,D,n("ul",null,[n("li",null,[L,R,n("p",null,[s("你可以为 "),n("a",G,[s("register-service-worker"),a(e)]),s(" 提供的事件添加事件监听器。")])]),F]),U,n("ul",null,[n("li",null,[H,n("p",null,[s("调用 "),n("a",T,[s("skipWaiting()"),a(e)]),s(" 来激活处于 Waiting 状态的 Service Worker 。")])]),X]),Y])}const O=l(d,[["render",Z],["__file","pwa.html.vue"]]);export{O as default}; diff --git a/assets/pwa.html-a8bc73bb.js b/assets/pwa.html-a8bc73bb.js new file mode 100644 index 00000000..3486bb27 --- /dev/null +++ b/assets/pwa.html-a8bc73bb.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7ab4099e","path":"/reference/plugin/pwa.html","title":"pwa","lang":"en-US","frontmatter":{"description":"Make your VuePress site a Progressive Web Application (PWA) (https://developer.mozilla.org/en-US/docs/Web/Progressivewebapps). This plugin uses workbox-build (https://developers...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/pwa.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/pwa.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"pwa"}],["meta",{"property":"og:description","content":"Make your VuePress site a Progressive Web Application (PWA) (https://developer.mozilla.org/en-US/docs/Web/Progressivewebapps). This plugin uses workbox-build (https://developers..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"pwa\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Web App Manifests","slug":"web-app-manifests","link":"#web-app-manifests","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"serviceWorkerFilename","slug":"serviceworkerfilename","link":"#serviceworkerfilename","children":[]}]},{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"usePwaEvent","slug":"usepwaevent","link":"#usepwaevent","children":[]},{"level":3,"title":"useSkipWaiting","slug":"useskipwaiting","link":"#useskipwaiting","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.06,"words":617},"filePathRelative":"reference/plugin/pwa.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/register-components.html-3824e3d5.js b/assets/register-components.html-3824e3d5.js new file mode 100644 index 00000000..f220489a --- /dev/null +++ b/assets/register-components.html-3824e3d5.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7f8fee18","path":"/reference/plugin/register-components.html","title":"register-components","lang":"en-US","frontmatter":{"description":"Register Vue components from component files or directory automatically. Usage Options components Type: Record; Default: {}; Details:; An object that defines name of components ...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/register-components.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/register-components.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"register-components"}],["meta",{"property":"og:description","content":"Register Vue components from component files or directory automatically. Usage Options components Type: Record; Default: {}; Details:; An object that defines name of components ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"register-components\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"components","slug":"components","link":"#components","children":[]},{"level":3,"title":"componentsDir","slug":"componentsdir","link":"#componentsdir","children":[]},{"level":3,"title":"componentsPatterns","slug":"componentspatterns","link":"#componentspatterns","children":[]},{"level":3,"title":"getComponentName","slug":"getcomponentname","link":"#getcomponentname","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.98,"words":295},"filePathRelative":"reference/plugin/register-components.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/register-components.html-7bbc9716.js b/assets/register-components.html-7bbc9716.js new file mode 100644 index 00000000..8625a7a0 --- /dev/null +++ b/assets/register-components.html-7bbc9716.js @@ -0,0 +1,49 @@ +import{_ as i,W as c,X as l,Y as a,$ as n,a0 as s,a1 as t,D as e}from"./framework-46b0e263.js";const u={},r=n("h1",{id:"register-components",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#register-components","aria-hidden":"true"},"#"),s(" register-components")],-1),d=t(`import { usePwaEvent, useSkipWaiting } from "@vuepress/plugin-pwa/client"; + +export default { + setup() { + const event = usePwaEvent(); + event.on("updated", (registration) => { + console.log("在 Waiting 状态的 Service Worker 已经就绪。"); + // 激活 Waiting 状态的 Service Worker + useSkipWaiting(registration); + }); + }, +}; +
Register Vue components from component files or directory automatically.
# Usage
npm i -D @vuepress/plugin-register-components@next +
import { registerComponentsPlugin } from "@vuepress/plugin-register-components"; + +export default { + plugins: [ + registerComponentsPlugin({ + // options + }), + ], +}; +
# Options
# components
Type:
Record<string, string>
Default:
{}
Details:
An object that defines name of components and their corresponding file path.
The key will be used as the component name, and the value is an absolute path of the component file.
If the component name from this option conflicts with componentsDir option, this option will have a higher priority.
Example:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + plugins: [ + registerComponentsPlugin({ + components: { + FooBar: path.resolve(__dirname, "./components/FooBar.vue"), + }, + }), + ], +}; +
# componentsDir
Type:
string | null
Default:
null
Details:
Absolute path to the components directory.
Files in this directory which are matched with componentsPatterns will be registered as Vue components automatically.
Example:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + plugins: [ + registerComponentsPlugin({ + componentsDir: path.resolve(__dirname, "./components"), + }), + ], +}; +
Components directory:
components +├─ FooBar.vue +└─ Baz.vue +
Components will be registered like this:
import { defineAsyncComponent } from "vue"; + +app.component( + "FooBar", + defineAsyncComponent(() => import("/path/to/components/FooBar.vue")) +); + +app.component( + "Baz", + defineAsyncComponent(() => import("/path/to/components/Baz.vue")) +); +
# componentsPatterns
`,16),m=n("li",null,[n("p",null,[s("Type: "),n("code",null,"string[]")])],-1),k=n("li",null,[n("p",null,[s("Default: "),n("code",null,"['**/*.vue']")])],-1),v=n("p",null,"Details:",-1),h={href:"https://github.com/sindresorhus/globby",target:"_blank",rel:"noopener noreferrer"},g=n("p",null,[s("The patterns are relative to "),n("a",{href:"#componentsdir"},"componentsDir"),s(".")],-1),b=t('# getComponentName
',2);function f(y,_){const p=e("NpmBadge"),o=e("ExternalLinkIcon");return c(),l("div",null,[r,a(p,{package:"@vuepress/plugin-register-components"}),d,n("ul",null,[m,k,n("li",null,[v,n("p",null,[s("Patterns to match component files using "),n("a",h,[s("globby"),a(o)]),s(".")]),g])]),b])}const x=i(u,[["render",f],["__file","register-components.html.vue"]]);export{x as default}; diff --git a/assets/register-components.html-865034f7.js b/assets/register-components.html-865034f7.js new file mode 100644 index 00000000..8d6da62a --- /dev/null +++ b/assets/register-components.html-865034f7.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-670b0cc9","path":"/zh/reference/plugin/register-components.html","title":"register-components","lang":"zh-CN","frontmatter":{"description":"根据组件文件或目录自动注册 Vue 组件。 使用方法 配置项 components 类型: Record; 默认值: {}; 详情:; 一个定义了组件名称和其对应文件路径的对象。 键会被用作组件名称,值是组件文件的绝对路径。 如果该配置项中的组件名称和 componentsDir (#componentsdir) 配置项发生冲突,那么该配置项会有更高的...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/register-components.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/register-components.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"register-components"}],["meta",{"property":"og:description","content":"根据组件文件或目录自动注册 Vue 组件。 使用方法 配置项 components 类型: Record; 默认值: {}; 详情:; 一个定义了组件名称和其对应文件路径的对象。 键会被用作组件名称,值是组件文件的绝对路径。 如果该配置项中的组件名称和 componentsDir (#componentsdir) 配置项发生冲突,那么该配置项会有更高的..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"register-components\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"components","slug":"components","link":"#components","children":[]},{"level":3,"title":"componentsDir","slug":"componentsdir","link":"#componentsdir","children":[]},{"level":3,"title":"componentsPatterns","slug":"componentspatterns","link":"#componentspatterns","children":[]},{"level":3,"title":"getComponentName","slug":"getcomponentname","link":"#getcomponentname","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.28,"words":385},"filePathRelative":"zh/reference/plugin/register-components.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/register-components.html-f40c1c68.js b/assets/register-components.html-f40c1c68.js new file mode 100644 index 00000000..70a424c7 --- /dev/null +++ b/assets/register-components.html-f40c1c68.js @@ -0,0 +1,49 @@ +import{_ as i,W as c,X as l,Y as a,$ as n,a0 as s,a1 as t,D as e}from"./framework-46b0e263.js";const u={},r=n("h1",{id:"register-components",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#register-components","aria-hidden":"true"},"#"),s(" register-components")],-1),d=t(`
Type:
(filename: string) => string
Default:
(filename) => path.trimExt(filename.replace(/\\/|\\\\/g, '-'))
Details:
A function to get component name from the filename.
It will only take effect on the files in the componentsDir which are matched with the componentsPatterns.
Notice that the
filename
is a filepath relative to componentsDir.根据组件文件或目录自动注册 Vue 组件。
# 使用方法
npm i -D @vuepress/plugin-register-components@next +
import { registerComponentsPlugin } from "@vuepress/plugin-register-components"; + +export default { + plugins: [ + registerComponentsPlugin({ + // 配置项 + }), + ], +}; +
# 配置项
# components
类型:
Record<string, string>
默认值:
{}
详情:
一个定义了组件名称和其对应文件路径的对象。
键会被用作组件名称,值是组件文件的绝对路径。
如果该配置项中的组件名称和 componentsDir 配置项发生冲突,那么该配置项会有更高的优先级。
示例:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + plugins: [ + registerComponentsPlugin({ + components: { + FooBar: path.resolve(__dirname, "./components/FooBar.vue"), + }, + }), + ], +}; +
# componentsDir
类型:
string | null
默认值:
null
详情:
组件目录的绝对路径。
该目录下匹配 componentsPatterns 的文件会被自动注册为 Vue 组件。
示例:
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + plugins: [ + registerComponentsPlugin({ + componentsDir: path.resolve(__dirname, "./components"), + }), + ], +}; +
组件目录:
components +├─ FooBar.vue +└─ Baz.vue +
组件会像这样被注册:
import { defineAsyncComponent } from "vue"; + +app.component( + "FooBar", + defineAsyncComponent(() => import("/path/to/components/FooBar.vue")) +); + +app.component( + "Baz", + defineAsyncComponent(() => import("/path/to/components/Baz.vue")) +); +
# componentsPatterns
`,16),k=n("li",null,[n("p",null,[s("类型: "),n("code",null,"string[]")])],-1),m=n("li",null,[n("p",null,[s("默认值: "),n("code",null,"['**/*.vue']")])],-1),v=n("p",null,"详情:",-1),g={href:"https://github.com/sindresorhus/globby",target:"_blank",rel:"noopener noreferrer"},h=n("p",null,[s("该 Patterns 是相对于 "),n("a",{href:"#componentsdir"},"componentsDir"),s(" 目录的。")],-1),b=t('# getComponentName
',2);function f(_,y){const p=e("NpmBadge"),o=e("ExternalLinkIcon");return c(),l("div",null,[r,a(p,{package:"@vuepress/plugin-register-components"}),d,n("ul",null,[k,m,n("li",null,[v,n("p",null,[s("使用 "),n("a",g,[s("globby"),a(o)]),s(" 来匹配组件文件的 Patterns 。")]),h])]),b])}const q=i(u,[["render",f],["__file","register-components.html.vue"]]);export{q as default}; diff --git a/assets/search.html-41912ea0.js b/assets/search.html-41912ea0.js new file mode 100644 index 00000000..dedb55a1 --- /dev/null +++ b/assets/search.html-41912ea0.js @@ -0,0 +1,41 @@ +import{_ as c,W as u,X as r,Y as a,$ as n,a0 as s,Z as o,a1 as e,D as t}from"./framework-46b0e263.js";const d={},h=n("h1",{id:"search",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#search","aria-hidden":"true"},"#"),s(" search")],-1),k=e(`
类型:
(filename: string) => string
默认值:
(filename) => path.trimExt(filename.replace(/\\/|\\\\/g, '-'))
详情:
用于从文件名获取对应组件名称的函数。
它只会对 componentsDir 目录下匹配了 componentsPatterns 的文件生效。
注意,这里的
filename
是相对于 componentsPatterns 目录的文件路径。Provide local search to your documentation site.
Tips
Default theme will add search box to the navbar once you configure this plugin correctly.
This plugin may not be used directly in other themes, so you'd better refer to the documentation of your theme for more details.
# Usage
npm i -D @vuepress/plugin-search@next +
import { searchPlugin } from "@vuepress/plugin-search"; + +export default { + plugins: [ + searchPlugin({ + // options + }), + ], +}; +
# Local Search Index
This plugin will generate search index from your pages locally, and load the search index file when users enter your site. In other words, this is a lightweight built-in search which does not require any external requests.
`,7),v=e(`# Options
# locales
Type:
Record<string, { placeholder: string }>
Details:
The text of the search box in different locales.
If this option is not specified, it will fallback to default text.
Example:
`,4),m=e('export default { + plugins: [ + searchPlugin({ + locales: { + "/": { + placeholder: "Search", + }, + "/zh/": { + placeholder: "搜索", + }, + }, + }), + ], +}; +
# hotKeys
- Type:
(string | HotKeyOptions)[]
',3),g=n("li",null,[n("p",null,[s("Default: "),n("code",null,"['s', '/']")])],-1),b=n("p",null,"Details:",-1),f={href:"http://keycode.info/",target:"_blank",rel:"noopener noreferrer"},y=n("p",null,"When hotkeys are pressed, the search box input will be focused.",-1),x=n("p",null,"Set to an empty array to disable hotkeys.",-1),_=e(`File not found
# maxSuggestions
Type:
number
Default:
5
Details:
Specify the maximum number of search results.
# isSearchable
Type:
(page: Page) => boolean
Default:
() => true
Details:
A function to determine whether a page should be included in the search index.
- Return
true
to include the page.- Return
false
to exclude the page.Example:
export default { + plugins: [ + searchPlugin({ + // exclude the homepage + isSearchable: (page) => page.path !== "/", + }), + ], +}; +
# getExtraFields
Type:
(page: Page) => string[]
Default:
() => []
Details:
A function to add extra fields to the search index of a page.
By default, this plugin will use page title and headers as the search index. This option could help you to add more searchable fields.
Example:
export default { + plugins: [ + searchPlugin({ + // allow searching the \`tags\` frontmatter + getExtraFields: (page) => page.frontmatter.tags ?? [], + }), + ], +}; +
# Styles
You can customize the style of the search box via CSS variables:
File not found
# Components
# SearchBox
Details:
This plugin will register a
<SearchBox />
component globally, and you can use it without any props.Put this component to where you want to place the search box. For example, default theme puts this component to the end of the navbar.
`,15);function w(q,S){const p=t("NpmBadge"),i=t("RouterLink"),l=t("ExternalLinkIcon");return u(),r("div",null,[h,a(p,{package:"@vuepress/plugin-search"}),k,n("p",null,[s("However, when your site has a large number of pages, the size of search index file would be very large, which could slow down the page loading speed. In this case, we recommend you to use a more professional solution - "),a(i,{to:"/reference/plugin/docsearch.html"},{default:o(()=>[s("docsearch")]),_:1}),s(".")]),v,n("ul",null,[n("li",null,[s("Also see: "),n("ul",null,[n("li",null,[a(i,{to:"/guide/i18n.html"},{default:o(()=>[s("Guide > I18n")]),_:1})])])])]),m,n("ul",null,[g,n("li",null,[b,n("p",null,[s("Specify the "),n("a",f,[s("event.key"),a(l)]),s(" of the hotkeys.")]),y,x])]),_])}const D=c(d,[["render",w],["__file","search.html.vue"]]);export{D as default}; diff --git a/assets/search.html-52d32298.js b/assets/search.html-52d32298.js new file mode 100644 index 00000000..2f47a7a0 --- /dev/null +++ b/assets/search.html-52d32298.js @@ -0,0 +1,41 @@ +import{_ as o,W as u,X as r,Y as a,$ as n,a0 as s,Z as i,a1 as e,D as t}from"./framework-46b0e263.js";const d={},h=n("h1",{id:"search",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#search","aria-hidden":"true"},"#"),s(" search")],-1),k=e(`Tips
This component is mainly used for theme development. You don't need to use it directly in most cases.
为你的文档网站提供本地搜索能力。
提示
当你正确配置该插件后,默认主题会把搜索框添加到导航栏。
该插件不一定能在其他主题中直接使用,因此你应参考主题本身的文档来获取更多信息。
# 使用方法
npm i -D @vuepress/plugin-search@next +
import { searchPlugin } from "@vuepress/plugin-search"; + +export default { + plugins: [ + searchPlugin({ + // 配置项 + }), + ], +}; +
# 本地搜索索引
该插件会根据你的页面,在本地生成搜索索引,然后在用户访问站点时加载搜索索引文件。换句话说,这是一个轻量级的内置搜索能力,不会进行任何外部请求。
`,7),v=e(`# 配置项
# locales
类型:
Record<string, { placeholder: string }>
详情:
搜索框在不同 locales 下的文字。
如果没有指定该配置项,它会降级使用默认文字。
示例:
`,4),m=e('export default { + plugins: [ + searchPlugin({ + locales: { + "/": { + placeholder: "Search", + }, + "/zh/": { + placeholder: "搜索", + }, + }, + }), + ], +}; +
# hotKeys
- 类型:
(string | HotKeyOptions)[]
',3),g=n("li",null,[n("p",null,[s("默认值: "),n("code",null,"['s', '/']")])],-1),b=n("p",null,"详情:",-1),f={href:"http://keycode.info/",target:"_blank",rel:"noopener noreferrer"},x=n("p",null,"当按下热键时,搜索框会被聚焦。",-1),_=n("p",null,"将该配置项设为空数组可以禁用热键功能。",-1),y=e(`File not found
# maxSuggestions
类型:
number
默认值:
5
详情:
指定搜索结果的最大条数。
# isSearchable
类型:
(page: Page) => boolean
默认值:
() => true
详情:
一个函数,用于判断一个页面是否应该被包含在搜索索引中。
- 返回
true
来包含该页面。- 返回
false
来排除该页面。示例:
export default { + plugins: [ + searchPlugin({ + // 排除首页 + isSearchable: (page) => page.path !== "/", + }), + ], +}; +
# getExtraFields
类型:
(page: Page) => string[]
默认值:
() => []
详情:
一个函数,用于在页面的搜索索引中添加额外字段。
默认情况下,该插件会将页面标题和小标题作为搜索索引。该配置项可以帮助你添加更多的可搜索字段。
示例:
export default { + plugins: [ + searchPlugin({ + // 允许搜索 Frontmatter 中的 \`tags\` + getExtraFields: (page) => page.frontmatter.tags ?? [], + }), + ], +}; +
# 样式
你可以通过 CSS 变量来自定义搜索框的样式:
File not found
# 组件
# SearchBox
详情:
该插件会全局注册一个
<SearchBox />
组件,你可以不传入任何 Props 来使用它。将该组件放置在你想要显示搜索框的地方。例如,默认主题将这个组件放在了导航栏的末尾。
`,15);function q(w,S){const l=t("NpmBadge"),p=t("RouterLink"),c=t("ExternalLinkIcon");return u(),r("div",null,[h,a(l,{package:"@vuepress/plugin-search"}),k,n("p",null,[s("然而,当你的站点包含大量页面时,搜索索引文件也会变得非常大,它可能会拖慢你的页面加载速度。在这种情况下,我们建议你使用更成熟的解决方案 - "),a(p,{to:"/zh/reference/plugin/docsearch.html"},{default:i(()=>[s("docsearch")]),_:1}),s(" 。")]),v,n("ul",null,[n("li",null,[s("参考: "),n("ul",null,[n("li",null,[a(p,{to:"/zh/guide/i18n.html"},{default:i(()=>[s("指南 > 多语言支持")]),_:1})])])])]),m,n("ul",null,[g,n("li",null,[b,n("p",null,[s("指定热键的 "),n("a",f,[s("event.key"),a(c)]),s(" 。")]),x,_])]),y])}const B=o(d,[["render",q],["__file","search.html.vue"]]);export{B as default}; diff --git a/assets/search.html-61d47ae9.js b/assets/search.html-61d47ae9.js new file mode 100644 index 00000000..9cdb4990 --- /dev/null +++ b/assets/search.html-61d47ae9.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-42d1e5c1","path":"/zh/reference/plugin/search.html","title":"search","lang":"zh-CN","frontmatter":{"description":"为你的文档网站提供本地搜索能力。 当你正确配置该插件后,默认主题会把搜索框添加到导航栏。 该插件不一定能在其他主题中直接使用,因此你应参考主题本身的文档来获取更多信息。 使用方法 本地搜索索引 该插件会根据你的页面,在本地生成搜索索引,然后在用户访问站点时加载搜索索引文件。换句话说,这是一个轻量级的内置搜索能力,不会进行任何外部请求。 然而,当你的站点...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/search.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/search.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"search"}],["meta",{"property":"og:description","content":"为你的文档网站提供本地搜索能力。 当你正确配置该插件后,默认主题会把搜索框添加到导航栏。 该插件不一定能在其他主题中直接使用,因此你应参考主题本身的文档来获取更多信息。 使用方法 本地搜索索引 该插件会根据你的页面,在本地生成搜索索引,然后在用户访问站点时加载搜索索引文件。换句话说,这是一个轻量级的内置搜索能力,不会进行任何外部请求。 然而,当你的站点..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"search\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"本地搜索索引","slug":"本地搜索索引","link":"#本地搜索索引","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"locales","slug":"locales","link":"#locales","children":[]},{"level":3,"title":"hotKeys","slug":"hotkeys","link":"#hotkeys","children":[]},{"level":3,"title":"maxSuggestions","slug":"maxsuggestions","link":"#maxsuggestions","children":[]},{"level":3,"title":"isSearchable","slug":"issearchable","link":"#issearchable","children":[]},{"level":3,"title":"getExtraFields","slug":"getextrafields","link":"#getextrafields","children":[]}]},{"level":2,"title":"样式","slug":"样式","link":"#样式","children":[]},{"level":2,"title":"组件","slug":"组件","link":"#组件","children":[{"level":3,"title":"SearchBox","slug":"searchbox","link":"#searchbox","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.34,"words":701},"filePathRelative":"zh/reference/plugin/search.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/search.html-c7cf299c.js b/assets/search.html-c7cf299c.js new file mode 100644 index 00000000..232c8f12 --- /dev/null +++ b/assets/search.html-c7cf299c.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-260e1012","path":"/reference/plugin/search.html","title":"search","lang":"en-US","frontmatter":{"description":"Provide local search to your documentation site. Default theme will add search box to the navbar once you configure this plugin correctly. This plugin may not be used directly i...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/search.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/search.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"search"}],["meta",{"property":"og:description","content":"Provide local search to your documentation site. Default theme will add search box to the navbar once you configure this plugin correctly. This plugin may not be used directly i..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"search\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Local Search Index","slug":"local-search-index","link":"#local-search-index","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"locales","slug":"locales","link":"#locales","children":[]},{"level":3,"title":"hotKeys","slug":"hotkeys","link":"#hotkeys","children":[]},{"level":3,"title":"maxSuggestions","slug":"maxsuggestions","link":"#maxsuggestions","children":[]},{"level":3,"title":"isSearchable","slug":"issearchable","link":"#issearchable","children":[]},{"level":3,"title":"getExtraFields","slug":"getextrafields","link":"#getextrafields","children":[]}]},{"level":2,"title":"Styles","slug":"styles","link":"#styles","children":[]},{"level":2,"title":"Components","slug":"components","link":"#components","children":[{"level":3,"title":"SearchBox","slug":"searchbox","link":"#searchbox","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.57,"words":470},"filePathRelative":"reference/plugin/search.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/shiki.html-c91adaea.js b/assets/shiki.html-c91adaea.js new file mode 100644 index 00000000..22c741fe --- /dev/null +++ b/assets/shiki.html-c91adaea.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-bb2079f4","path":"/reference/plugin/shiki.html","title":"shiki","lang":"en-US","frontmatter":{"description":"This plugin will enable syntax highlighting for markdown code fence with Shiki (https://shiki.matsu.io/). Shiki (https://shiki.matsu.io/) is the syntax highlighter being used by...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/shiki.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/shiki.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"shiki"}],["meta",{"property":"og:description","content":"This plugin will enable syntax highlighting for markdown code fence with Shiki (https://shiki.matsu.io/). Shiki (https://shiki.matsu.io/) is the syntax highlighter being used by..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"shiki\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"theme","slug":"theme","link":"#theme","children":[]},{"level":3,"title":"langs","slug":"langs","link":"#langs","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.53,"words":158},"filePathRelative":"reference/plugin/shiki.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/shiki.html-d52b252b.js b/assets/shiki.html-d52b252b.js new file mode 100644 index 00000000..b69f60a0 --- /dev/null +++ b/assets/shiki.html-d52b252b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7a12fb77","path":"/zh/reference/plugin/shiki.html","title":"shiki","lang":"zh-CN","frontmatter":{"description":"该插件使用 Shiki (https://shiki.matsu.io/) 来为 Markdown 代码块启用代码高亮。 Shiki (https://shiki.matsu.io/) 是 VSCode 正在使用的代码高亮器。它具有更高的保真度,但比 Prism.js (https://prismjs.com/) 要慢一些,特别是在有大量代码块需要处理...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/shiki.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/shiki.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"shiki"}],["meta",{"property":"og:description","content":"该插件使用 Shiki (https://shiki.matsu.io/) 来为 Markdown 代码块启用代码高亮。 Shiki (https://shiki.matsu.io/) 是 VSCode 正在使用的代码高亮器。它具有更高的保真度,但比 Prism.js (https://prismjs.com/) 要慢一些,特别是在有大量代码块需要处理..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"shiki\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"theme","slug":"theme","link":"#theme","children":[]},{"level":3,"title":"langs","slug":"langs","link":"#langs","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.79,"words":236},"filePathRelative":"zh/reference/plugin/shiki.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/shiki.html-d54efc8e.js b/assets/shiki.html-d54efc8e.js new file mode 100644 index 00000000..f4f62ecb --- /dev/null +++ b/assets/shiki.html-d54efc8e.js @@ -0,0 +1,11 @@ +import{_ as l,W as r,X as c,Y as s,$ as n,a0 as e,a1 as i,D as t}from"./framework-46b0e263.js";const p={},d=n("h1",{id:"shiki",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#shiki","aria-hidden":"true"},"#"),e(" shiki")],-1),h={href:"https://shiki.matsu.io/",target:"_blank",rel:"noopener noreferrer"},u={class:"hint-container tip"},k=n("p",{class:"hint-container-title"},"提示",-1),_={href:"https://shiki.matsu.io/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://prismjs.com/",target:"_blank",rel:"noopener noreferrer"},g=n("p",null,[e("你可以考虑在 "),n("code",null,"dev"),e(" 模式下禁用该插件来获取更好的开发体验。")],-1),v=i(`提示
该组件主要用于主题开发。在大多数情况下你不需要直接使用该组件。
# 使用方法
npm i -D @vuepress/plugin-shiki@next +
import { shikiPlugin } from "@vuepress/plugin-shiki"; + +export default { + plugins: [ + shikiPlugin({ + // 配置项 + }), + ], +}; +
# 配置项
# theme
`,5),b=i("类型:
IThemeRegistration
默认值:
'nord'
",3),f=n("p",null,"参考:",-1),x={href:"https://github.com/shikijs/shiki/blob/master/docs/themes.md",target:"_blank",rel:"noopener noreferrer"},S=n("h3",{id:"langs",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#langs","aria-hidden":"true"},"#"),e(" langs")],-1),y=i(" 详情:
Shiki 的主题。
该配置项会被传递到 Shiki 的
getHighlighter()
方法中。类型:
(Lang | ILanguageRegistration)[]
默认值:
[]
",3),N=n("p",null,"参考:",-1),w={href:"https://github.com/shikijs/shiki/blob/master/docs/languages.md",target:"_blank",rel:"noopener noreferrer"};function B(V,j){const o=t("NpmBadge"),a=t("ExternalLinkIcon");return r(),c("div",null,[d,s(o,{package:"@vuepress/plugin-shiki"}),n("p",null,[e("该插件使用 "),n("a",h,[e("Shiki"),s(a)]),e(" 来为 Markdown 代码块启用代码高亮。")]),n("div",u,[k,n("p",null,[n("a",_,[e("Shiki"),s(a)]),e(" 是 VSCode 正在使用的代码高亮器。它具有更高的保真度,但比 "),n("a",m,[e("Prism.js"),s(a)]),e(" 要慢一些,特别是在有大量代码块需要处理的时候。")]),g]),v,n("ul",null,[b,n("li",null,[f,n("ul",null,[n("li",null,[n("a",x,[e("shiki > themes"),s(a)])])])])]),S,n("ul",null,[y,n("li",null,[N,n("ul",null,[n("li",null,[n("a",w,[e("shiki > languages"),s(a)])])])])])])}const L=l(p,[["render",B],["__file","shiki.html.vue"]]);export{L as default}; diff --git a/assets/shiki.html-e11165ea.js b/assets/shiki.html-e11165ea.js new file mode 100644 index 00000000..02d29d65 --- /dev/null +++ b/assets/shiki.html-e11165ea.js @@ -0,0 +1,11 @@ +import{_ as l,W as r,X as p,Y as s,$ as e,a0 as n,a1 as i,D as t}from"./framework-46b0e263.js";const c={},d=e("h1",{id:"shiki",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#shiki","aria-hidden":"true"},"#"),n(" shiki")],-1),h={href:"https://shiki.matsu.io/",target:"_blank",rel:"noopener noreferrer"},u={class:"hint-container tip"},k=e("p",{class:"hint-container-title"},"Tips",-1),g={href:"https://shiki.matsu.io/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://prismjs.com/",target:"_blank",rel:"noopener noreferrer"},_=e("p",null,[n("You could consider disabling this plugin in "),e("code",null,"dev"),n(" mode to get better development experience.")],-1),b=i(` 详情:
Shiki 的语言。
该配置项会被传递到 Shiki 的
getHighlighter()
方法中。如果没有传入语言, Shiki 会自动加载所有可用的语言。
# Usage
npm i -D @vuepress/plugin-shiki@next +
import { shikiPlugin } from "@vuepress/plugin-shiki"; + +export default { + plugins: [ + shikiPlugin({ + // options + }), + ], +}; +
# Options
# theme
`,5),v=i("Type:
IThemeRegistration
Default:
'nord'
",3),f=e("p",null,"Also see:",-1),x={href:"https://github.com/shikijs/shiki/blob/master/docs/themes.md",target:"_blank",rel:"noopener noreferrer"},w=e("h3",{id:"langs",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#langs","aria-hidden":"true"},"#"),n(" langs")],-1),y=i(" Details:
Theme of shiki.
This option will be forwarded to
getHighlighter()
method of shiki.Type:
(Lang | ILanguageRegistration)[]
Default:
[]
",3),T=e("p",null,"Also see:",-1),D={href:"https://github.com/shikijs/shiki/blob/master/docs/languages.md",target:"_blank",rel:"noopener noreferrer"};function I(N,B){const o=t("NpmBadge"),a=t("ExternalLinkIcon");return r(),p("div",null,[d,s(o,{package:"@vuepress/plugin-shiki"}),e("p",null,[n("This plugin will enable syntax highlighting for markdown code fence with "),e("a",h,[n("Shiki"),s(a)]),n(".")]),e("div",u,[k,e("p",null,[e("a",g,[n("Shiki"),s(a)]),n(" is the syntax highlighter being used by VSCode. It has higher fidelity, but it is slower than "),e("a",m,[n("Prism.js"),s(a)]),n(".")]),_]),b,e("ul",null,[v,e("li",null,[f,e("ul",null,[e("li",null,[e("a",x,[n("shiki > themes"),s(a)])])])])]),w,e("ul",null,[y,e("li",null,[T,e("ul",null,[e("li",null,[e("a",D,[n("shiki > languages"),s(a)])])])])])])}const V=l(c,[["render",I],["__file","shiki.html.vue"]]);export{V as default}; diff --git a/assets/style-c2b64bf5.css b/assets/style-c2b64bf5.css new file mode 100644 index 00000000..615dc608 --- /dev/null +++ b/assets/style-c2b64bf5.css @@ -0,0 +1 @@ +:root{--theme-color: #3eaf7c;--text-color: #2c3e50;--bg-color: #fff;--bg-color-secondary: #f8f8f8;--bg-color-tertiary: #efeef4;--border-color: #eaecef;--border-color-dark: #dfe2e5;--box-shadow: #f0f1f2;--card-shadow: rgba(0, 0, 0, .15);--black: #000;--dark-grey: #666;--light-grey: #999;--white: #fff;--grey3: #333;--grey12: #bbb;--grey14: #eee;--navbar-height: 3.75rem;--navbar-horizontal-padding: 1.5rem;--navbar-vertical-padding: .7rem;--navbar-mobile-height: 3.25rem;--navbar-mobile-horizontal-padding: 1rem;--navbar-mobile-vertical-padding: .5rem;--sidebar-width: 18rem;--sidebar-mobile-width: 16rem;--content-width: 780px;--home-page-width: 1160px;--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif;--font-family-fancy: Georgia Pro, Crimson, Georgia, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif;--font-family-code: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;--line-numbers-width: 2.5rem;--color-transition: .3s ease;--transform-transition: .3s ease;--vp-bg: var(--bg-color);--vp-bgl: var(--bg-color-light);--vp-bglt: var(--bg-color-tertiary);--vp-c: var(--text-color);--vp-cl: var(--text-color-light);--vp-clt: var(--text-color-lighter);--vp-brc: var(--border-color);--vp-brcd: var(--border-color-dark);--vp-tc: var(--theme-color);--vp-tcl: var(--theme-color-light);--vp-ct: var(--color-transition);--vp-tt: var(--transform-transition);--bg-color-light: #fff;--bg-color-back: #f8f8f8;--bg-color-float: #fff;--text-color-light: #3a5169;--text-color-lighter: #476582;--text-color-bright: #6a8bad;--bg-color-blur: rgba(255, 255, 255, .9);--bg-color-float-blur: rgba(255, 255, 255, .9);--theme-color-dark: #389e70;--theme-color-light: #4abf8a;--theme-color-mask: rgba(62, 175, 124, .15)}html[data-theme=dark]{--text-color: #9e9e9e;--bg-color: #1d1e1f;--bg-color-secondary: #272829;--bg-color-tertiary: #333536;--border-color: #302d28;--border-color-dark: #34404c;--box-shadow: #282a32;--card-shadow: rgba(0, 0, 0, .3);--black: #fff;--dark-grey: #999;--light-grey: #666;--white: #000;--grey3: #bbb;--grey12: #333;--grey14: #111;--bg-color-light: #272829;--bg-color-back: #1d1e1f;--bg-color-float: #272829;--text-color-light: #a8a8a8;--text-color-lighter: #b1b1b1;--text-color-bright: #c5c5c5;--bg-color-blur: rgba(29, 30, 31, .9);--bg-color-float-blur: rgba(39, 40, 41, .9)}:root{--badge-tip-color: #42b983;--badge-warning-color: #f4cd00;--badge-danger-color: #f55;--badge-info-color: #0295ff;--badge-note-color: #666}.badge{display:inline-block;vertical-align:top;height:18px;padding:0 6px;border-radius:3px;background:var(--vp-tc);color:var(--white);font-size:14px;line-height:18px;transition:background var(--vp-ct),color var(--vp-ct)}.badge+.badge{-webkit-margin-start:5px;margin-inline-start:5px}.table-of-contents .badge,#toc .badge{vertical-align:middle}.badge.tip{background:var(--badge-tip-color)}.badge.warning{background:var(--badge-warning-color)}.badge.danger{background:var(--badge-danger-color)}.badge.info{background:var(--badge-info-color)}.badge.note{background:var(--badge-note-color)}.font-icon{display:inline-block}.theme-hope-content .font-icon{vertical-align:middle}:root{--balloon-border-radius: 2px;--balloon-color: rgba(16, 16, 16, .95);--balloon-text-color: #fff;--balloon-font-size: 12px;--balloon-move: 4px}button[aria-label][data-balloon-pos]{overflow:visible}[aria-label][data-balloon-pos]{position:relative;cursor:pointer}[aria-label][data-balloon-pos]:after{opacity:0;pointer-events:none;transition:all .18s ease-out .18s;text-indent:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;font-weight:400;font-style:normal;text-shadow:none;font-size:var(--balloon-font-size);background:var(--balloon-color);border-radius:2px;color:var(--balloon-text-color);border-radius:var(--balloon-border-radius);content:attr(aria-label);padding:.5em 1em;position:absolute;white-space:nowrap;z-index:10}[aria-label][data-balloon-pos]:before{width:0;height:0;border:5px solid transparent;border-top-color:var(--balloon-color);opacity:0;pointer-events:none;transition:all .18s ease-out .18s;content:"";position:absolute;z-index:10}[aria-label][data-balloon-pos]:hover:before,[aria-label][data-balloon-pos]:hover:after,[aria-label][data-balloon-pos][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-visible]:after,[aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:before,[aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:after{opacity:1;pointer-events:none}[aria-label][data-balloon-pos].font-awesome:after{font-family:FontAwesome,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif}[aria-label][data-balloon-pos][data-balloon-break]:after{white-space:pre}[aria-label][data-balloon-pos][data-balloon-break][data-balloon-length]:after{white-space:pre-line;word-break:break-word}[aria-label][data-balloon-pos][data-balloon-blunt]:before,[aria-label][data-balloon-pos][data-balloon-blunt]:after{transition:none}[aria-label][data-balloon-pos][data-balloon-pos=up]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=up][data-balloon-visible]:after,[aria-label][data-balloon-pos][data-balloon-pos=down]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=down][data-balloon-visible]:after{transform:translate(-50%)}[aria-label][data-balloon-pos][data-balloon-pos=up]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=up][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-pos=down]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=down][data-balloon-visible]:before{transform:translate(-50%)}[aria-label][data-balloon-pos][data-balloon-pos*=-left]:after{left:0}[aria-label][data-balloon-pos][data-balloon-pos*=-left]:before{left:5px}[aria-label][data-balloon-pos][data-balloon-pos*=-right]:after{right:0}[aria-label][data-balloon-pos][data-balloon-pos*=-right]:before{right:5px}[aria-label][data-balloon-pos][data-balloon-po*=-left]:hover:after,[aria-label][data-balloon-pos][data-balloon-po*=-left][data-balloon-visible]:after,[aria-label][data-balloon-pos][data-balloon-pos*=-right]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos*=-right][data-balloon-visible]:after{transform:translate(0)}[aria-label][data-balloon-pos][data-balloon-po*=-left]:hover:before,[aria-label][data-balloon-pos][data-balloon-po*=-left][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-pos*=-right]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos*=-right][data-balloon-visible]:before{transform:translate(0)}[aria-label][data-balloon-pos][data-balloon-pos^=up]:before,[aria-label][data-balloon-pos][data-balloon-pos^=up]:after{bottom:100%;transform-origin:top;transform:translateY(var(--balloon-move))}[aria-label][data-balloon-pos][data-balloon-pos^=up]:after{margin-bottom:10px}[aria-label][data-balloon-pos][data-balloon-pos=up]:before,[aria-label][data-balloon-pos][data-balloon-pos=up]:after{left:50%;transform:translate(-50%,var(--balloon-move))}[aria-label][data-balloon-pos][data-balloon-pos^=down]:before,[aria-label][data-balloon-pos][data-balloon-pos^=down]:after{top:100%;transform:translateY(calc(var(--balloon-move) * -1))}[aria-label][data-balloon-pos][data-balloon-pos^=down]:after{margin-top:10px}[aria-label][data-balloon-pos][data-balloon-pos^=down]:before{width:0;height:0;border:5px solid transparent;border-bottom-color:var(--balloon-color)}[aria-label][data-balloon-pos][data-balloon-pos=down]:after,[aria-label][data-balloon-pos][data-balloon-pos=down]:before{left:50%;transform:translate(-50%,calc(var(--balloon-move) * -1))}[aria-label][data-balloon-pos][data-balloon-pos=left]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=left][data-balloon-visible]:after,[aria-label][data-balloon-pos][data-balloon-pos=right]:hover:after,[aria-label][data-balloon-pos][data-balloon-pos=right][data-balloon-visible]:after{transform:translateY(-50%)}[aria-label][data-balloon-pos][data-balloon-pos=left]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=left][data-balloon-visible]:before,[aria-label][data-balloon-pos][data-balloon-pos=right]:hover:before,[aria-label][data-balloon-pos][data-balloon-pos=right][data-balloon-visible]:before{transform:translateY(-50%)}[aria-label][data-balloon-pos][data-balloon-pos=left]:after,[aria-label][data-balloon-pos][data-balloon-pos=left]:before{right:100%;top:50%;transform:translate(var(--balloon-move),-50%)}[aria-label][data-balloon-pos][data-balloon-pos=left]:after{margin-right:10px}[aria-label][data-balloon-pos][data-balloon-pos=left]:before{width:0;height:0;border:5px solid transparent;border-left-color:var(--balloon-color)}[aria-label][data-balloon-pos][data-balloon-pos=right]:after,[aria-label][data-balloon-pos][data-balloon-pos=right]:before{left:100%;top:50%;transform:translate(calc(var(--balloon-move) * -1),-50%)}[aria-label][data-balloon-pos][data-balloon-pos=right]:after{margin-left:10px}[aria-label][data-balloon-pos][data-balloon-pos=right]:before{width:0;height:0;border:5px solid transparent;border-right-color:var(--balloon-color)}[aria-label][data-balloon-pos][data-balloon-length]:after{white-space:normal}[aria-label][data-balloon-pos][data-balloon-length=small]:after{width:80px}[aria-label][data-balloon-pos][data-balloon-length=medium]:after{width:150px}[aria-label][data-balloon-pos][data-balloon-length=large]:after{width:260px}[aria-label][data-balloon-pos][data-balloon-length=xlarge]:after{width:380px}@media screen and (max-width: 768px){[aria-label][data-balloon-pos][data-balloon-length=xlarge]:after{width:90vw}}[aria-label][data-balloon-pos][data-balloon-length=fit]:after{width:100%}.back-to-top{border-width:0;background:transparent;cursor:pointer;position:fixed!important;right:1rem;bottom:4rem;z-index:100;width:3rem;height:3rem;padding:.5rem;border-radius:1rem;background:var(--vp-bg);color:var(--vp-tc);box-shadow:2px 2px 10px 0 var(--card-shadow);transition:background var(--vp-ct),color var(--vp-ct),box-shadow var(--vp-ct)}@media (max-width: 719px){.back-to-top{width:2.25rem;height:2.25rem;padding:.25rem;border-radius:.5rem}}@media print{.back-to-top{display:none}}html[dir=rtl] .back-to-top{right:unset;left:1rem}.back-to-top:hover{color:var(--vp-tcl)}.back-to-top svg{overflow:hidden;width:100%;border-radius:50%;fill:currentcolor}.fade-enter-active,.fade-leave-active{transition:opacity var(--vp-ct)}.fade-enter,.fade-leave-to{opacity:0}@media screen{.sr-only{position:absolute;overflow:hidden;clip:rect 0,0,0,0;width:1px;height:1px;margin:-1px;padding:0;border:0}}@media print{.sr-only{display:none}}.auto-catalog-wrapper{margin-top:8px;margin-bottom:8px}.auto-catalog-wrapper .catalog-title{color:inherit;text-decoration:none}.auto-catalog-wrapper .catalog-title:hover{color:var(--vp-tc)}.auto-catalog-wrapper .main-title{font-size:1.75rem}.auto-catalog-wrapper .child-title{font-size:1.3rem}.auto-catalog-wrapper .child-title.has-children{border-bottom:1px solid var(--vp-brc);transition:border-color var(--vp-ct)}.auto-catalog-wrapper .sub-title{color:var(--vp-clt);font-size:1.1rem}.auto-catalog-wrapper .main-title,.auto-catalog-wrapper .child-title,.auto-catalog-wrapper .sub-title{margin-top:calc(.5rem - var(--navbar-height, 3.6rem));margin-bottom:.5rem;padding-top:var(--navbar-height, 3.6rem);font-weight:500}.auto-catalog-wrapper .main-title:first-child,.auto-catalog-wrapper .child-title:first-child,.auto-catalog-wrapper .sub-title:first-child{margin-bottom:.5rem}.auto-catalog-wrapper .font-icon{vertical-align:baseline;-webkit-margin-end:.25rem;margin-inline-end:.25rem}.auto-catalog-wrapper .child-catalog-wrapper{margin:0}.auto-catalog-wrapper .child-catalog-item::marker{color:var(--vp-clt)}.auto-catalog-wrapper .sub-catalog-wrapper{display:flex;flex-wrap:wrap}.auto-catalog-wrapper .sub-catalog-item{display:inline-block;margin:4px 8px;padding:4px 8px;border-radius:6px;background-color:var(--vp-bgl);line-height:1.5;overflow-wrap:break-word;transition:background-color var(--vp-ct),color var(--vp-ct)}.auto-catalog-wrapper .sub-catalog-item:hover{background-color:var(--vp-tcl);color:var(--vp-bg);text-decoration:none}:root{--external-link-icon-color: #aaa}.external-link-icon{position:relative;display:inline-block;color:var(--external-link-icon-color);vertical-align:middle;top:-1px}@media print{.external-link-icon{display:none}}.external-link-icon-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}:root{--nprogress-color: #29d;--nprogress-z-index: 1031}#nprogress{pointer-events:none}#nprogress .bar{background:var(--nprogress-color);position:fixed;z-index:var(--nprogress-z-index);top:0;left:0;width:100%;height:2px}:root{--copy-icon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E");--copied-icon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E")}div[class*=language-]>button.copy-code-button{border-width:0;background:transparent;position:absolute;outline:none;cursor:pointer}@media print{div[class*=language-]>button.copy-code-button{display:none}}div[class*=language-]>button.copy-code-button .copy-icon{background:currentcolor;-webkit-mask-image:var(--copy-icon);mask-image:var(--copy-icon);-webkit-mask-position:50%;mask-position:50%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:1em;mask-size:1em}div[class*=language-]>button.copy-code-button:not(.fancy){border-width:0;background:transparent;cursor:pointer;position:absolute;top:0;right:3em;z-index:5;width:2.5rem;height:2.5rem;padding:0;border-radius:.5rem;opacity:0;transition:opacity .4s}div[class*=language-]>button.copy-code-button:not(.fancy):hover{background:var(--code-hl-bg-color, rgba(0, 0, 0, .66))}div[class*=language-]>button.copy-code-button:not(.fancy).copied:after{content:attr(data-copied);position:absolute;top:0;right:100%;display:block;height:1.25rem;padding:.625rem;border-radius:.5rem;background:var(--code-hl-bg-color, rgba(0, 0, 0, .66));color:var(--code-ln-color, #9e9e9e);font-weight:500;line-height:1.25rem;white-space:nowrap}div[class*=language-]>button.copy-code-button:not(.fancy) .copy-icon{width:1.25rem;height:1.25rem;padding:.625rem;color:var(--code-ln-color, #9e9e9e);font-size:1.25rem}div[class*=language-]>button.copy-code-button.fancy{right:-14px;bottom:-14px;z-index:5;width:2rem;height:2rem;padding:7px 8px;border-radius:50%;background:#339af0;color:#fff}@media (max-width: 419px){div[class*=language-]>button.copy-code-button.fancy{right:0;bottom:0;width:28px;height:28px;border-radius:50% 10% 0}}div[class*=language-]>button.copy-code-button.fancy:hover{background:#228be6}div[class*=language-]>button.copy-code-button.fancy .copy-icon{width:100%;height:100%;color:#fff;font-size:1.25rem}@media (max-width: 419px){div[class*=language-]>button.copy-code-button.fancy .copy-icon{position:relative;top:2px;left:2px}}div[class*=language-]>button.copy-code-button.copied .copy-icon{-webkit-mask-image:var(--copied-icon);mask-image:var(--copied-icon)}div[class*=language-]:hover>button.copy-code-button:not(.fancy),div[class*=language-]>button.copy-code-button:not(.fancy):focus{opacity:1}.code-tabs-nav{overflow-x:auto;margin:.85rem 0 -.85rem;padding:0;border-radius:6px 6px 0 0;background:var(--code-tabs-nav-bg-color, #3a404c);list-style:none;white-space:nowrap;transition:background var(--vp-ct)}@media print{.code-tabs-nav{display:none}}@media (max-width: 419px){.code-tabs-nav{margin-right:-1.5rem;margin-left:-1.5rem;border-radius:0}}.code-tabs-nav-tab{border-width:0;position:relative;min-width:3rem;margin:0;padding:6px 12px;border-radius:6px 6px 0 0;background:transparent;color:var(--code-tabs-nav-text-color, #eee);font-weight:600;font-size:.85em;line-height:1.4;cursor:pointer;transition:background var(--vp-ct),color var(--vp-ct)}.code-tabs-nav-tab:hover{background:var(--code-tabs-nav-hover-color, #434a57)}.code-tabs-nav-tab:before,.code-tabs-nav-tab:after{content:" ";position:absolute;bottom:0;z-index:1;width:6px;height:6px}.code-tabs-nav-tab:before{right:100%}.code-tabs-nav-tab:after{left:100%}.code-tabs-nav-tab.active{padding:6px 16px;background:var(--code-bg-color, #282c34)}.code-tabs-nav-tab.active:before{background:radial-gradient(12px at left top,transparent 50%,var(--code-bg-color, #282c34) 50%)}.code-tabs-nav-tab.active:after{background:radial-gradient(12px at right top,transparent 50%,var(--code-bg-color, #282c34) 50%)}.code-tabs-nav-tab:first-child:before{display:none}.code-tab{display:none}.code-tab.active{display:block}.code-tab div[class*=language-]{border-top-left-radius:0;border-top-right-radius:0}@media (max-width: 419px){.code-tab div[class*=language-]{margin:.85rem -1.5rem}}@media print{.code-tab div[class*=language-] code{white-space:pre-wrap}}.code-group-nav{display:flex;margin:.85rem 0 -.85rem;padding:0;border-radius:6px 6px 0 0;background:var(--code-tabs-nav-bg-color, #3a404c);list-style:none;transition:background var(--vp-ct)}@media (max-width: 419px){.code-group-nav{margin-right:-1.5rem;margin-left:-1.5rem;border-radius:0}}.code-group-nav-tab{border-width:0;position:relative;min-width:3rem;margin:0;padding:6px 10px;border-radius:6px 6px 0 0;background:transparent;color:var(--code-tabs-nav-text-color, #eee);font-weight:600;font-size:.85em;line-height:1.4;cursor:pointer;transition:background var(--vp-ct),color var(--vp-ct)}.code-group-nav-tab:hover{background:var(--code-tabs-nav-hover-color, #434a57)}.code-group-nav-tab:before,.code-group-nav-tab:after{content:" ";position:absolute;bottom:0;z-index:1;width:6px;height:6px}.code-group-nav-tab:before{right:100%}.code-group-nav-tab:after{left:100%}.code-group-nav-tab.active{background:var(--code-bg-color, #282c34)}.code-group-nav-tab.active:before{background:radial-gradient(12px at left top,transparent 50%,var(--code-bg-color, #282c34) 50%)}.code-group-nav-tab.active:after{background:radial-gradient(12px at right top,transparent 50%,var(--code-bg-color, #282c34) 50%)}.code-group-nav-tab:first-child:before{display:none}.code-group-item{display:none}.code-group-item.active{display:block}.code-group-item div[class*=language-]{border-top-left-radius:0;border-top-right-radius:0}:root{--info-title-color: #193c47;--info-bg-color: #eef9fd;--info-border-color: #4cb3d4;--info-code-bg-color: rgb(76 179 212 / 10%);--note-title-color: #474748;--note-bg-color: #fdfdfe;--note-border-color: #ccc;--note-code-bg-color: rgb(212 213 216 / 20%);--tip-title-color: #003100;--tip-bg-color: #e6f6e6;--tip-border-color: #009400;--tip-code-bg-color: rgb(0 148 0 / 15%);--warning-title-color: #4d3800;--warning-bg-color: #fff8e6;--warning-border-color: #e6a700;--warning-code-bg-color: rgb(230 167 0 / 15%);--danger-title-color: #4b1113;--danger-bg-color: #ffebec;--danger-border-color: #e13238;--danger-code-bg-color: rgb(225 50 56 / 15%);--detail-bg-color: #eee;--detail-text-color: inherit;--detail-code-bg-color: rgb(127 127 127 / 15%)}html[data-theme=dark]{--info-title-color: #eef9fd;--info-bg-color: #193c47;--note-title-color: #fdfdfe;--note-bg-color: #474748;--tip-title-color: #e6f6e6;--tip-bg-color: #003100;--warning-title-color: #fff8e6;--warning-bg-color: #4d3800;--danger-title-color: #ffebec;--danger-bg-color: #4b1113;--detail-bg-color: #333;--detail-text-color: #a8a8a8}.hint-container{position:relative;transition:background var(--vp-ct),border-color var(--vp-ct),color var(--vp-ct)}@media print{.hint-container{page-break-inside:avoid}}.hint-container .hint-container-title{position:relative;font-weight:600;line-height:1.25}.hint-container.info,.hint-container.note,.hint-container.tip,.hint-container.warning,.hint-container.danger{margin:1rem 0;padding:.25rem 1rem;border-inline-start-width:.3rem;border-inline-start-style:solid;border-radius:.5rem;color:inherit}.hint-container.info .hint-container-title,.hint-container.note .hint-container-title,.hint-container.tip .hint-container-title,.hint-container.warning .hint-container-title,.hint-container.danger .hint-container-title{-webkit-padding-start:1.75rem;padding-inline-start:1.75rem}@media print{.hint-container.info .hint-container-title,.hint-container.note .hint-container-title,.hint-container.tip .hint-container-title,.hint-container.warning .hint-container-title,.hint-container.danger .hint-container-title{-webkit-padding-start:0;padding-inline-start:0}}.hint-container.info .hint-container-title:before,.hint-container.note .hint-container-title:before,.hint-container.tip .hint-container-title:before,.hint-container.warning .hint-container-title:before,.hint-container.danger .hint-container-title:before{content:" ";position:absolute;top:calc(50% - .6125em);left:0;width:1.25em;height:1.25em;background-position:left;background-repeat:no-repeat}@media print{.hint-container.info .hint-container-title:before,.hint-container.note .hint-container-title:before,.hint-container.tip .hint-container-title:before,.hint-container.warning .hint-container-title:before,.hint-container.danger .hint-container-title:before{display:none}}html[dir=rtl] .hint-container.info .hint-container-title:before,html[dir=rtl] .hint-container.note .hint-container-title:before,html[dir=rtl] .hint-container.tip .hint-container-title:before,html[dir=rtl] .hint-container.warning .hint-container-title:before,html[dir=rtl] .hint-container.danger .hint-container-title:before{right:0;left:unset}.hint-container.info p,.hint-container.note p,.hint-container.tip p,.hint-container.warning p,.hint-container.danger p{line-height:1.5}.hint-container.info a,.hint-container.note a,.hint-container.tip a,.hint-container.warning a,.hint-container.danger a{color:var(--vp-tc)}.hint-container.info{border-color:var(--info-border-color);background:var(--info-bg-color)}.hint-container.info>.hint-container-title{color:var(--info-title-color)}.hint-container.info>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%234cb3d4'/%3E%3C/svg%3E")}.hint-container.info code{background:var(--info-code-bg-color)}.hint-container.note{border-color:var(--note-border-color);background:var(--note-bg-color)}.hint-container.note>.hint-container-title{color:var(--note-title-color)}.hint-container.note>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%23ccc'/%3E%3C/svg%3E")}.hint-container.note code{background:var(--note-code-bg-color)}.hint-container.tip{border-color:var(--tip-border-color);background:var(--tip-bg-color)}.hint-container.tip>.hint-container-title{color:var(--tip-title-color)}.hint-container.tip>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23009400' d='M7.941 18c-.297-1.273-1.637-2.314-2.187-3a8 8 0 1 1 12.49.002c-.55.685-1.888 1.726-2.185 2.998H7.94zM16 20v1a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-1h8zm-3-9.995V6l-4.5 6.005H11v4l4.5-6H13z'/%3E%3C/svg%3E")}.hint-container.tip code{background:var(--tip-code-bg-color)}.hint-container.warning{border-color:var(--warning-border-color);background:var(--warning-bg-color)}.hint-container.warning>.hint-container-title{color:var(--warning-title-color)}.hint-container.warning>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M576.286 752.57v-95.425q0-7.031-4.771-11.802t-11.3-4.772h-96.43q-6.528 0-11.3 4.772t-4.77 11.802v95.424q0 7.031 4.77 11.803t11.3 4.77h96.43q6.528 0 11.3-4.77t4.77-11.803zm-1.005-187.836 9.04-230.524q0-6.027-5.022-9.543-6.529-5.524-12.053-5.524H456.754q-5.524 0-12.053 5.524-5.022 3.516-5.022 10.547l8.538 229.52q0 5.023 5.022 8.287t12.053 3.265h92.913q7.032 0 11.803-3.265t5.273-8.287zM568.25 95.65l385.714 707.142q17.578 31.641-1.004 63.282-8.538 14.564-23.354 23.102t-31.892 8.538H126.286q-17.076 0-31.892-8.538T71.04 866.074q-18.582-31.641-1.004-63.282L455.75 95.65q8.538-15.57 23.605-24.61T512 62t32.645 9.04 23.605 24.61z' fill='%23e6a700'/%3E%3C/svg%3E")}.hint-container.warning code{background:var(--warning-code-bg-color)}.hint-container.danger{border-color:var(--danger-border-color);background:var(--danger-bg-color)}.hint-container.danger>.hint-container-title{color:var(--danger-title-color)}.hint-container.danger>.hint-container-title:before{background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2c5.523 0 10 4.477 10 10v3.764a2 2 0 0 1-1.106 1.789L18 19v1a3 3 0 0 1-2.824 2.995L14.95 23a2.5 2.5 0 0 0 .044-.33L15 22.5V22a2 2 0 0 0-1.85-1.995L13 20h-2a2 2 0 0 0-1.995 1.85L9 22v.5c0 .171.017.339.05.5H9a3 3 0 0 1-3-3v-1l-2.894-1.447A2 2 0 0 1 2 15.763V12C2 6.477 6.477 2 12 2zm-4 9a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm8 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4z' fill='%23e13238'/%3E%3C/svg%3E")}.hint-container.danger code{background:var(--danger-code-bg-color)}.hint-container.details{position:relative;display:block;margin:1.6em 0;padding:1.5rem;border-radius:.5rem;background:var(--detail-bg-color);color:var(--detail-text-color);transition:background var(--vp-tt),color var(--vp-tt)}@media print{.hint-container.details{display:none}}.hint-container.details h4{margin-top:0}.hint-container.details figure:last-child,.hint-container.details p:last-child{margin-bottom:0;padding-bottom:0}.hint-container.details a{color:var(--vp-tc)}.hint-container.details code{background:var(--detail-code-bg-color)}.hint-container.details summary{position:relative;margin:-1.5rem;padding-top:1.5rem;padding-bottom:1.5rem;-webkit-padding-start:4rem;padding-inline-start:4rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem;list-style:none;cursor:pointer}.hint-container.details summary::-webkit-details-marker,.hint-container.details summary::marker{color:transparent;font-size:0}.hint-container.details summary:before,.hint-container.details summary:after{content:" ";position:absolute;top:calc(50% - .75rem);left:1.5rem;width:1.5rem;height:1.5rem}@media print{.hint-container.details summary:before,.hint-container.details summary:after{display:block}}html[dir=rtl] .hint-container.details summary:before,html[dir=rtl] .hint-container.details summary:after{right:1.5rem;left:unset}.hint-container.details summary:before{border-radius:50%;background:#ccc;transition:background var(--vp-ct),transform var(--vp-tt)}html[data-theme=dark] .hint-container.details summary:before{background:#555}.hint-container.details summary:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:transform var(--vp-tt);transform:rotate(90deg)}html[data-theme=dark] .hint-container.details summary:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.hint-container.details[open] summary{margin-bottom:.5em}.hint-container.details[open] summary:after{transform:rotate(180deg)}/*! PhotoSwipe main CSS by Dmytro Semenov | photoswipe.com */.pswp{--pswp-bg: #000;--pswp-placeholder-bg: #222;--pswp-root-z-index: 100000;--pswp-preloader-color: rgba(79, 79, 79, .4);--pswp-preloader-color-secondary: rgba(255, 255, 255, .9);--pswp-icon-color: #fff;--pswp-icon-color-secondary: #4f4f4f;--pswp-icon-stroke-color: #4f4f4f;--pswp-icon-stroke-width: 2px;--pswp-error-text-color: var(--pswp-icon-color)}.pswp{position:fixed;top:0;left:0;width:100%;height:100%;z-index:var(--pswp-root-z-index);display:none;touch-action:none;outline:0;opacity:.003;contain:layout style size;-webkit-tap-highlight-color:rgba(0,0,0,0)}.pswp:focus{outline:0}.pswp *{box-sizing:border-box}.pswp img{max-width:none}.pswp--open{display:block}.pswp,.pswp__bg{transform:translateZ(0);will-change:opacity}.pswp__bg{opacity:.005;background:var(--pswp-bg)}.pswp,.pswp__scroll-wrap{overflow:hidden}.pswp__scroll-wrap,.pswp__bg,.pswp__container,.pswp__item,.pswp__content,.pswp__img,.pswp__zoom-wrap{position:absolute;top:0;left:0;width:100%;height:100%}.pswp__img,.pswp__zoom-wrap{width:auto;height:auto}.pswp--click-to-zoom.pswp--zoom-allowed .pswp__img{cursor:zoom-in}.pswp--click-to-zoom.pswp--zoomed-in .pswp__img{cursor:move;cursor:grab}.pswp--click-to-zoom.pswp--zoomed-in .pswp__img:active{cursor:grabbing}.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img,.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img:active,.pswp__img{cursor:zoom-out}.pswp__container,.pswp__img,.pswp__button,.pswp__counter{-webkit-user-select:none;-moz-user-select:none;user-select:none}.pswp__item{z-index:1;overflow:hidden}.pswp__hidden{display:none!important}.pswp__content{pointer-events:none}.pswp__content>*{pointer-events:auto}.pswp__error-msg-container{display:grid}.pswp__error-msg{margin:auto;font-size:1em;line-height:1;color:var(--pswp-error-text-color)}.pswp .pswp__hide-on-close{opacity:.005;will-change:opacity;transition:opacity var(--pswp-transition-duration) cubic-bezier(.4,0,.22,1);z-index:10;pointer-events:none}.pswp--ui-visible .pswp__hide-on-close{opacity:1;pointer-events:auto}.pswp__button{position:relative;display:block;width:50px;height:60px;padding:0;margin:0;overflow:hidden;cursor:pointer;background:none;border:0;box-shadow:none;opacity:.85;-webkit-appearance:none;-webkit-touch-callout:none}.pswp__button:hover,.pswp__button:active,.pswp__button:focus{transition:none;padding:0;background:none;border:0;box-shadow:none;opacity:1}.pswp__button:disabled{opacity:.3;cursor:auto}.pswp__icn{fill:var(--pswp-icon-color);color:var(--pswp-icon-color-secondary)}.pswp__icn{position:absolute;top:14px;left:9px;width:32px;height:32px;overflow:hidden;pointer-events:none}.pswp__icn-shadow{stroke:var(--pswp-icon-stroke-color);stroke-width:var(--pswp-icon-stroke-width);fill:none}.pswp__icn:focus{outline:0}div.pswp__img--placeholder,.pswp__img--with-bg{background:var(--pswp-placeholder-bg)}.pswp__top-bar{position:absolute;left:0;top:0;width:100%;height:60px;display:flex;flex-direction:row;justify-content:flex-end;z-index:10;pointer-events:none!important}.pswp__top-bar>*{pointer-events:auto;will-change:opacity}.pswp__button--close{margin-right:6px}.pswp__button--arrow{position:absolute;top:0;width:75px;height:100px;top:50%;margin-top:-50px}.pswp__button--arrow:disabled{display:none;cursor:default}.pswp__button--arrow .pswp__icn{top:50%;margin-top:-30px;width:60px;height:60px;background:none;border-radius:0}.pswp--one-slide .pswp__button--arrow{display:none}.pswp--touch .pswp__button--arrow{visibility:hidden}.pswp--has_mouse .pswp__button--arrow{visibility:visible}.pswp__button--arrow--prev{right:auto;left:0px}.pswp__button--arrow--next{right:0px}.pswp__button--arrow--next .pswp__icn{left:auto;right:14px;transform:scaleX(-1)}.pswp__button--zoom{display:none}.pswp--zoom-allowed .pswp__button--zoom{display:block}.pswp--zoomed-in .pswp__zoom-icn-bar-v{display:none}.pswp__preloader{position:relative;overflow:hidden;width:50px;height:60px;margin-right:auto}.pswp__preloader .pswp__icn{opacity:0;transition:opacity .2s linear;animation:pswp-clockwise .6s linear infinite}.pswp__preloader--active .pswp__icn{opacity:.85}@keyframes pswp-clockwise{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.pswp__counter{height:30px;margin-top:15px;-webkit-margin-start:20px;margin-inline-start:20px;font-size:14px;line-height:30px;color:var(--pswp-icon-color);text-shadow:1px 1px 3px var(--pswp-icon-color-secondary);opacity:.85}.pswp--one-slide .pswp__counter{display:none}.footer-wrapper{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-evenly;padding-top:.75rem;padding-bottom:.75rem;-webkit-padding-start:calc(var(--sidebar-space) + 2rem);padding-inline-start:calc(var(--sidebar-space) + 2rem);-webkit-padding-end:2rem;padding-inline-end:2rem;border-top:1px solid var(--border-color);background:var(--bg-color);color:var(--dark-grey);text-align:center;transition:border-top-color var(--color-transition),background var(--color-transition),padding var(--transform-transition)}@media (max-width: 719px){.footer-wrapper{-webkit-padding-start:2rem;padding-inline-start:2rem}}@media (min-width: 1440px){.footer-wrapper{z-index:50;-webkit-padding-start:2rem;padding-inline-start:2rem}}@media print{.footer-wrapper{margin:0!important;padding:0!important}}@media (max-width: 419px){.footer-wrapper{display:block}}.no-sidebar .footer-wrapper,.sidebar-collapsed .footer-wrapper{-webkit-padding-start:2rem;padding-inline-start:2rem}.footer-wrapper .footer{margin:.5rem 1rem;font-size:14px}@media print{.footer-wrapper .footer{display:none}}.footer-wrapper .copyright{margin:6px 0;font-size:13px}.page:not(.not-found)+.footer-wrapper{margin-top:-2rem}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper:not(:hover) .arrow{transform:rotate(-180deg)}.dropdown-wrapper .dropdown-title{border-width:0;background:transparent;cursor:pointer;padding:0 .25rem;color:var(--dark-grey);font-weight:500;font-size:inherit;font-family:inherit;line-height:inherit;cursor:inherit}.dropdown-wrapper .dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .icon{-webkit-margin-end:.25em;margin-inline-end:.25em;font-size:1em}.dropdown-wrapper .dropdown-title .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s;font-size:1.2em}html[data-theme=dark] .dropdown-wrapper .dropdown-title .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.dropdown-wrapper .dropdown-title .arrow.down{transform:rotate(180deg)}html[dir=rtl] .dropdown-wrapper .dropdown-title .arrow.down{transform:rotate(-180deg)}.dropdown-wrapper .dropdown-title .arrow.end{transform:rotate(90deg)}html[dir=rtl] .dropdown-wrapper .dropdown-title .arrow.end,.dropdown-wrapper .dropdown-title .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .dropdown-wrapper .dropdown-title .arrow.start{transform:rotate(90deg)}.dropdown-wrapper ul{margin:0;padding:0;list-style-type:none}.dropdown-wrapper .nav-dropdown{position:absolute;top:100%;right:0;overflow-y:auto;box-sizing:border-box;min-width:6rem;max-height:calc(100vh - var(--navbar-height));margin:0;padding:.5rem .75rem;border:1px solid var(--grey14);border-radius:.25rem;background:var(--bg-color);box-shadow:2px 2px 10px var(--card-shadow);text-align:start;white-space:nowrap;opacity:0;visibility:hidden;transition:all .18s ease-out;transform:scale(.8)}html[dir=rtl] .dropdown-wrapper .nav-dropdown{right:unset;left:0}.dropdown-wrapper:hover .nav-dropdown,.dropdown-wrapper.open .nav-dropdown{z-index:2;opacity:1;visibility:visible;transform:scale(1)}.dropdown-wrapper .nav-link{position:relative;display:block;margin-bottom:0;border-bottom:none;color:var(--dark-grey);font-weight:400;font-size:.875rem;line-height:1.7rem;transition:color var(--color-transition)}.dropdown-wrapper .nav-link:hover,.dropdown-wrapper .nav-link.active{color:var(--theme-color)}.dropdown-wrapper .dropdown-subtitle{margin:0;padding:0 .25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;text-transform:uppercase;transition:color var(--color-transition)}.dropdown-wrapper .dropdown-subitem-wrapper{padding:0 0 .5rem;border-bottom:1px solid var(--grey14)}.dropdown-wrapper .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .dropdown-item:last-child .dropdown-subitem-wrapper{padding-bottom:0;border-bottom-width:0}.nav-screen-dropdown-title{border-width:0;background:transparent;position:relative;display:flex;align-items:center;width:100%;padding:0;color:var(--dark-grey);font-size:inherit;font-family:inherit;text-align:start;cursor:pointer}.nav-screen-dropdown-title:hover,.nav-screen-dropdown-title.active{color:var(--text-color)}.nav-screen-dropdown-title .title{flex:1}.nav-screen-dropdown-title .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s}html[data-theme=dark] .nav-screen-dropdown-title .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.nav-screen-dropdown-title .arrow.down{transform:rotate(180deg)}html[dir=rtl] .nav-screen-dropdown-title .arrow.down{transform:rotate(-180deg)}.nav-screen-dropdown-title .arrow.end{transform:rotate(90deg)}html[dir=rtl] .nav-screen-dropdown-title .arrow.end,.nav-screen-dropdown-title .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .nav-screen-dropdown-title .arrow.start{transform:rotate(90deg)}.nav-screen-dropdown{overflow:hidden;margin:.5rem 0 0;padding:0;list-style:none;transition:transform .1s ease-out;transform:scaleY(1);transform-origin:top}.nav-screen-dropdown.hide{height:0;margin:0;transform:scaleY(0)}.nav-screen-dropdown .nav-link{position:relative;display:block;-webkit-padding-start:.5rem;padding-inline-start:.5rem;font-weight:400;line-height:2}.nav-screen-dropdown .nav-link:hover,.nav-screen-dropdown .nav-link.active{color:var(--theme-color)}.nav-screen-dropdown .nav-link .icon{font-size:1em}.nav-screen-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.nav-screen-dropdown .dropdown-subtitle{margin:0;-webkit-padding-start:.25rem;padding-inline-start:.25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;text-transform:uppercase;transition:color var(--color-transition)}.nav-screen-dropdown .dropdown-subtitle .nav-link{padding:0}.nav-screen-dropdown .dropdown-subitem-wrapper{margin:0;padding:0;list-style:none}.nav-screen-dropdown .dropdown-subitem{-webkit-padding-start:.5rem;padding-inline-start:.5rem;font-size:.9em}.nav-screen-links{display:none;padding-bottom:.75rem}@media (max-width: 719px){.nav-screen-links{display:block}}.nav-screen-links .navbar-links-item{position:relative;display:block;padding:12px 4px 11px 0;border-bottom:1px solid var(--border-color);font-size:16px;line-height:1.5rem;transition:border-bottom-color var(--color-transition)}.nav-screen-links .nav-link{display:inline-block;width:100%;color:var(--dark-grey);font-weight:400}.nav-screen-links .nav-link:hover{color:var(--text-color)}.nav-screen-links .nav-link.active{color:var(--theme-color)}.appearance-title{display:block;margin:0;padding:0 .25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;transition:color var(--color-transition)}#appearance-switch{border-width:0;background:transparent;vertical-align:middle;padding:6px;color:var(--dark-grey);cursor:pointer;transition:color var(--color-transition)}#appearance-switch:hover{color:var(--theme-color)}#appearance-switch .icon{width:1.25rem;height:1.25rem}.theme-color-title{display:block;margin:0;padding:0 .25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;transition:color var(--color-transition)}#theme-color-picker{display:flex;margin:0;padding:0;list-style-type:none;font-size:14px}#theme-color-picker li span{display:inline-block;vertical-align:middle;width:15px;height:15px;margin:0 2px;border-radius:2px}#theme-color-picker li span.theme-color,#theme-color-picker li span.theme-color html[data-theme=dark]{background:#3eaf7c}@media print{.full-screen-wrapper{display:none}}.full-screen-title{display:block;margin:0;padding:0 .25rem;color:var(--light-grey);font-weight:600;font-size:.75rem;line-height:2;transition:color var(--color-transition)}.full-screen,.cancel-full-screen{border-width:0;background:transparent;vertical-align:middle;padding:.375rem;color:var(--dark-grey);cursor:pointer}.full-screen:hover,.cancel-full-screen:hover{color:var(--theme-color)}.full-screen .icon,.cancel-full-screen .icon{width:1.25rem;height:1.25rem}.enter-fullscreen-icon:hover,.cancel-fullscreen-icon{color:var(--theme-color)}.cancel-fullscreen-icon:hover{color:var(--dark-grey)}#nav-screen{position:fixed;top:var(--navbar-height);right:0;bottom:0;left:0;z-index:150;display:none;overflow-y:auto;padding:0 2rem;background:var(--bg-color);transition:background .5s}@media (max-width: 719px){#nav-screen{display:block}}#nav-screen .container{max-width:320px;margin:0 auto;padding:2rem 0 4rem}#nav-screen.fade-enter-active,#nav-screen.fade-leave-active{transition:opacity .25s}#nav-screen.fade-enter-active .container,#nav-screen.fade-leave-active .container{transition:transform .25s ease}#nav-screen.fade-enter-from,#nav-screen.fade-leave-to{opacity:0}#nav-screen.fade-enter-from .container,#nav-screen.fade-leave-to .container{transform:translateY(-8px)}#nav-screen .outlook-wrapper{display:flex;justify-content:space-around}#nav-screen .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.navbar .logo{vertical-align:top;height:var(--navbar-line-height);-webkit-margin-end:.8rem;margin-inline-end:.8rem}.navbar .logo.light{display:inline-block}.navbar .logo.dark,html[data-theme=dark] .navbar .logo.light{display:none}html[data-theme=dark] .navbar .logo.dark{display:inline-block}.navbar .site-name{position:relative;color:var(--text-color);font-size:1.25rem}@media (max-width: 719px){.navbar .site-name{overflow:hidden;width:calc(100vw - 9.4rem);text-overflow:ellipsis;white-space:nowrap}}.brand:hover .navbar .site-name{color:var(--theme-color)}.navbar .nav-links{display:flex;align-items:center;font-size:.875rem}.navbar .nav-item{position:relative;margin:0 .25rem;line-height:2rem}.navbar .nav-item:first-child{-webkit-margin-start:0;margin-inline-start:0}.navbar .nav-item:last-child{-webkit-margin-end:0;margin-inline-end:0}.navbar .nav-item>.nav-link{color:var(--dark-grey)}.navbar .nav-item>.nav-link:after{content:" ";position:absolute;right:50%;bottom:0;left:50%;height:2px;border-radius:1px;background:var(--theme-color-light);visibility:hidden;transition:left .2s ease-in-out,right .2s ease-in-out}.navbar .nav-item>.nav-link.active{color:var(--theme-color)}.navbar .nav-item>.nav-link:hover:after,.navbar .nav-item>.nav-link.active:after{right:0;left:0;visibility:visible}.navbar .repo-link{display:inline-block;margin:auto;padding:6px;color:var(--dark-grey);line-height:1}.navbar .repo-link:hover,.navbar .repo-link:active{color:var(--theme-color)}.toggle-navbar-button{border-width:0;background:transparent;cursor:pointer;position:relative;display:none;align-items:center;justify-content:center;padding:6px}@media screen and (max-width: 719px){.toggle-navbar-button{display:flex}}.toggle-navbar-button .button-container{position:relative;overflow:hidden;width:16px;height:14px}.toggle-navbar-button .button-top,.toggle-navbar-button .button-middle,.toggle-navbar-button .button-bottom{position:absolute;width:16px;height:2px;background:var(--dark-grey);transition:top .25s,background .5s,transform .25s}.toggle-navbar-button .button-top{top:0;left:0;transform:translate(0)}.toggle-navbar-button .button-middle{top:6px;left:0;transform:translate(8px)}.toggle-navbar-button .button-bottom{top:12px;left:0;transform:translate(4px)}.toggle-navbar-button:hover .button-top{top:0;left:0;transform:translate(4px)}.toggle-navbar-button:hover .button-middle{top:6;left:0;transform:translate(0)}.toggle-navbar-button:hover .button-bottom{top:12px;left:0;transform:translate(8px)}.toggle-navbar-button.is-active .button-top{top:6px;transform:translate(0) rotate(225deg)}.toggle-navbar-button.is-active .button-middle{top:6px;transform:translate(16px)}.toggle-navbar-button.is-active .button-bottom{top:6px;transform:translate(0) rotate(135deg)}.toggle-navbar-button.is-active:hover .button-top,.toggle-navbar-button.is-active:hover .button-middle,.toggle-navbar-button.is-active:hover .button-bottom{background:var(--theme-color);transition:top .25s,background .25s,transform .25s}.toggle-sidebar-button{border-width:0;background:transparent;cursor:pointer;display:none;vertical-align:middle;box-sizing:content-box;width:1rem;height:1rem;padding:.5rem;font:unset;transition:transform .2s ease-in-out}@media screen and (max-width: 719px){.toggle-sidebar-button{display:block;-webkit-padding-end:var(--navbar-mobile-horizontal-padding);padding-inline-end:var(--navbar-mobile-horizontal-padding)}}.toggle-sidebar-button:before,.toggle-sidebar-button:after,.toggle-sidebar-button .icon{display:block;width:100%;height:2px;border-radius:.05em;background:var(--dark-grey);transition:transform .2s ease-in-out}.toggle-sidebar-button:before{content:" ";margin-top:.125em}.sidebar-open .toggle-sidebar-button:before{transform:translateY(.34rem) rotate(135deg)}.toggle-sidebar-button:after{content:" ";margin-bottom:.125em}.sidebar-open .toggle-sidebar-button:after{transform:translateY(-.34rem) rotate(-135deg)}.toggle-sidebar-button .icon{margin:.2em 0}.sidebar-open .toggle-sidebar-button .icon{transform:scale(0)}.outlook-button{border-width:0;background:transparent;cursor:pointer;position:relative;padding:.375rem;color:var(--dark-grey)}.outlook-button .icon{vertical-align:middle;width:1.25rem;height:1.25rem}.outlook-dropdown{position:absolute;top:100%;right:0;overflow-y:auto;box-sizing:border-box;min-width:100px;margin:0;padding:.5rem .75rem;border:1px solid var(--grey14);border-radius:.25rem;background:var(--bg-color);box-shadow:2px 2px 10px var(--card-shadow);text-align:start;white-space:nowrap;opacity:0;visibility:hidden;transition:all .18s ease-out;transform:scale(.8)}html[dir=rtl] .outlook-dropdown{right:unset;left:0}.outlook-dropdown>*:not(:last-child){padding-bottom:.5rem;border-bottom:1px solid var(--grey14)}.outlook-button:hover .outlook-dropdown,.outlook-button.open .outlook-dropdown{z-index:2;opacity:1;visibility:visible;transform:scale(1)}.navbar{--navbar-line-height: calc( var(--navbar-height) - var(--navbar-vertical-padding) * 2 );position:fixed;top:0;right:0;left:0;z-index:175;display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;height:var(--navbar-height);padding:var(--navbar-vertical-padding) var(--navbar-horizontal-padding);background:var(--navbar-bg-color);box-shadow:0 2px 8px var(--card-shadow);line-height:var(--navbar-line-height);white-space:nowrap;transition:transform ease-in-out .3s,background var(--color-transition),box-shadow var(--color-transition);-webkit-backdrop-filter:saturate(150%) blur(12px);backdrop-filter:saturate(150%) blur(12px)}@media print{.navbar{display:none}}.hide-navbar .navbar.auto-hide{transform:translateY(-100%)}.navbar .nav-link{padding:0 .25rem;color:var(--dark-grey)}.navbar .nav-link.active{color:var(--theme-color)}.navbar .nav-link .icon{-webkit-margin-end:.25em;margin-inline-end:.25em;font-size:1em}.navbar.hide-icon .nav-links .icon{display:none!important}.navbar-start,.navbar-end,.navbar-center{display:flex;flex:1;align-items:center}.navbar-start>*,.navbar-end>*,.navbar-center>*{position:relative;margin:0 .25rem!important}.navbar-start>*:first-child,.navbar-end>*:first-child,.navbar-center>*:first-child{-webkit-margin-start:0!important;margin-inline-start:0!important}.navbar-start>*:last-child,.navbar-end>*:last-child,.navbar-center>*:last-child{-webkit-margin-end:0!important;margin-inline-end:0!important}.navbar-start{justify-content:start}.navbar-center{justify-content:center}.navbar-end{justify-content:end}.sidebar-heading{display:flex;align-items:center;overflow:hidden;box-sizing:border-box;width:calc(100% - 1rem);margin:0;margin-inline:.5rem;padding:.25rem .5rem;border-width:0;border-radius:.375rem;background:transparent;color:var(--text-color);font-size:1.1em;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:color .15s ease;transform:rotate(0)}.sidebar-heading.open{color:inherit}.sidebar-heading.clickable:hover{background:var(--bg-color-secondary)}.sidebar-heading.clickable.exact{border-inline-start-color:var(--theme-color);color:var(--theme-color)}.sidebar-heading.clickable.exact a{color:inherit}.sidebar-heading .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.sidebar-heading .title{flex:1}.sidebar-heading .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s;font-size:1.5em}html[data-theme=dark] .sidebar-heading .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.sidebar-heading .arrow.down{transform:rotate(180deg)}html[dir=rtl] .sidebar-heading .arrow.down{transform:rotate(-180deg)}.sidebar-heading .arrow.end{transform:rotate(90deg)}html[dir=rtl] .sidebar-heading .arrow.end,.sidebar-heading .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .sidebar-heading .arrow.start{transform:rotate(90deg)}button.sidebar-heading{outline:none;font-weight:inherit;line-height:inherit;text-align:start;cursor:pointer}.sidebar-link{display:inline-block;box-sizing:border-box;width:calc(100% - 1rem);margin-inline:.5rem;padding:.25rem .5rem;border-radius:.375rem;color:var(--text-color);font-weight:400;font-size:1em;line-height:1.5}.sidebar-link .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.sidebar-link:hover{background:var(--bg-color-secondary)}.sidebar-link.active{background:var(--theme-color-mask);color:var(--theme-color);font-weight:500}.sidebar-link.active .icon{color:var(--theme-color)}.sidebar-sub-headers .sidebar-link{padding-top:.25rem;padding-bottom:.25rem;-webkit-border-start:none;border-inline-start:none}.sidebar-sub-headers .sidebar-link.active{background:transparent;font-weight:500}.sidebar-group .sidebar-group{-webkit-padding-start:.5em;padding-inline-start:.5em}.sidebar-group:not(.collapsible) .sidebar-heading:not(.clickable){color:inherit;cursor:auto}.sidebar-group .sidebar-link{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem}.sidebar-links,.sidebar-links ul{margin:0;padding:0}.sidebar-links ul.sidebar-sub-headers{-webkit-padding-start:.75rem;padding-inline-start:.75rem;font-size:.95em}@media (min-width: 1440px){.has-toc .sidebar-links ul.sidebar-sub-headers{display:none}}.sidebar-links li{list-style-type:none}.sidebar>.sidebar-links{padding:1.5rem 0}@media (max-width: 719px){.sidebar>.sidebar-links{padding:1rem 0}}.sidebar>.sidebar-links>li>.sidebar-link{font-size:1.1em}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.5rem}.sidebar{position:fixed;top:0;bottom:0;left:0;overflow-y:auto;width:var(--sidebar-width);margin:0;-webkit-padding-start:calc(var(--sidebar-space) - var(--sidebar-width));padding-inline-start:calc(var(--sidebar-space) - var(--sidebar-width));background:var(--sidebar-bg-color);box-shadow:2px 0 8px var(--card-shadow);font-size:15px;transition:background var(--color-transition),box-shadow var(--color-transition),padding var(--transform-transition),transform var(--transform-transition);-webkit-backdrop-filter:saturate(150%) blur(12px);backdrop-filter:saturate(150%) blur(12px);scrollbar-color:var(--theme-color) var(--border-color);scrollbar-width:thin}@media (max-width: 959px){.sidebar{font-size:14px}}@media (max-width: 719px){.sidebar{z-index:125;box-shadow:none;transform:translate(-100%)}html[dir=rtl] .sidebar{transform:translate(100%)}}@media (min-width: 1440px){.sidebar{padding-bottom:3rem;box-shadow:none}}@media print{.sidebar{display:none}}html[dir=rtl] .sidebar{right:0;left:unset}.sidebar a{display:inline-block;color:var(--text-color);font-weight:400}.sidebar .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.sidebar.hide-icon .icon{display:none!important}.sidebar .blogger-info.mobile{display:none}@media (max-width: 719px){.sidebar .blogger-info.mobile{display:block}}.sidebar .blogger-info.mobile+hr{display:none}@media (max-width: 719px){.sidebar .blogger-info.mobile+hr{display:block;margin-top:1rem}}.sidebar-mask{position:fixed;top:0;left:0;z-index:9;width:100vw;height:100vh;background:rgba(0,0,0,.15)}.sidebar-mask.fade-enter-active,.sidebar-mask.fade-leave-active{transition:opacity .25s}.sidebar-mask.fade-enter-from,.sidebar-mask.fade-leave-to{opacity:0}.toggle-sidebar-wrapper{position:fixed;top:var(--navbar-height);bottom:0;left:var(--sidebar-space);z-index:100;display:flex;align-items:center;justify-content:center;font-size:2rem;transition:left var(--transform-transition)}@media (max-width: 719px){.toggle-sidebar-wrapper{display:none}}@media (min-width: 1440px){.toggle-sidebar-wrapper{display:none}}html[dir=rtl] .toggle-sidebar-wrapper{right:var(--sidebar-space);left:unset}.toggle-sidebar-wrapper:hover{background:rgba(127,127,127,.05);cursor:pointer}.toggle-sidebar-wrapper .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s}html[data-theme=dark] .toggle-sidebar-wrapper .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.toggle-sidebar-wrapper .arrow.down{transform:rotate(180deg)}html[dir=rtl] .toggle-sidebar-wrapper .arrow.down{transform:rotate(-180deg)}.toggle-sidebar-wrapper .arrow.end{transform:rotate(90deg)}html[dir=rtl] .toggle-sidebar-wrapper .arrow.end,.toggle-sidebar-wrapper .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .toggle-sidebar-wrapper .arrow.start{transform:rotate(90deg)}.theme-container{display:flex;flex-direction:column;justify-content:space-between;min-height:100vh}.theme-container .page{padding-top:var(--navbar-height);-webkit-padding-start:calc(var(--sidebar-space) + 2rem);padding-inline-start:calc(var(--sidebar-space) + 2rem)}@media (max-width: 719px){.theme-container .page{-webkit-padding-start:0;padding-inline-start:0;-webkit-padding-end:0;padding-inline-end:0}}@media (min-width: 1440px){.theme-container .page{-webkit-padding-end:calc(100vw - var(--content-width) - var(--sidebar-space) - 6rem);padding-inline-end:calc(100vw - var(--content-width) - var(--sidebar-space) - 6rem)}}.theme-container .sidebar{top:var(--navbar-height)}.theme-container.no-navbar .page{padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (max-width: 719px){.theme-container.no-navbar .sidebar{top:0}}@media (max-width: 719px){.theme-container.hide-navbar .sidebar{top:0}}.theme-container.sidebar-collapsed .page{-webkit-padding-start:0;padding-inline-start:0}.theme-container.sidebar-collapsed .sidebar{box-shadow:none;transform:translate(-100%)}html[dir=rtl] .theme-container.sidebar-collapsed .sidebar{transform:translate(100%)}.theme-container.sidebar-collapsed .toggle-sidebar-wrapper{left:0}html[dir=rtl] .theme-container.sidebar-collapsed .toggle-sidebar-wrapper{right:0;left:unset}.theme-container.no-sidebar .page{-webkit-padding-start:0;padding-inline-start:0;-webkit-padding-end:0;padding-inline-end:0}@media (min-width: 1440px){.theme-container.no-sidebar.has-toc .page{-webkit-padding-end:16rem;padding-inline-end:16rem}}.theme-container.no-sidebar .toggle-sidebar-button,.theme-container.no-sidebar .toggle-sidebar-wrapper,.theme-container.no-sidebar .sidebar{display:none}.theme-container.sidebar-open .sidebar{box-shadow:2px 0 8px var(--card-shadow);transform:translate(0)}@keyframes bounce{0%{transform:scale(1) translateY(0)}10%{transform:scale(var(--bounce-start-scale-x, 1.1),var(--bounce-start-scale-y, .9)) translateY(0)}30%{transform:scale(var(--bounce-jump-scale-x, .9),var(--bounce-jump-scale-y, 1.1)) translateY(var(--bounce-height, -.5em))}50%{transform:scale(var(--bounce-land-scale-x, 1.05),var(--bounce-land-scale-y, .95)) translateY(0)}57%{transform:scale(1) translateY(var(--bounce-rebound, -.125em))}64%{transform:scale(1) translateY(0)}to{transform:scale(1) translateY(0)}}.feature-header{margin:0 1.75rem}.feature-wrapper{display:flex;flex-wrap:wrap;align-content:stretch;align-items:stretch;justify-content:center}@media print{.feature-wrapper{display:block}}.feature-wrapper:first-child{border-top:1px solid var(--border-color);transition:border-color var(--color-transition)}.feature-item{position:relative;flex-basis:calc(33% - 3rem);margin:.5rem;padding:1rem;border-radius:.5rem;transition:background var(--color-transition),box-shadow var(--color-transition),transform var(--transform-transition)}@media (min-width: 1440px){.feature-item{flex-basis:calc(25% - 3rem)}}@media (max-width: 959px){.feature-item{flex-basis:calc(50% - 3rem)}}@media (max-width: 719px){.feature-item{flex-basis:100%;font-size:.95rem}}@media (max-width: 419px){.feature-item{margin:.5rem 0;font-size:.9rem}}.feature-item.link{cursor:pointer}@media print{.feature-item.link{text-decoration:none}}.feature-item .icon{display:inline-block;width:1.1em;-webkit-margin-end:.5rem;margin-inline-end:.5rem;color:var(--theme-color);font-weight:400;font-size:1.1em}.feature-item:hover{background-color:var(--bg-color-secondary);box-shadow:0 2px 12px 0 var(--card-shadow);transform:scale(1.05)}.home.project:not(.pure) .feature-item{position:relative;overflow:hidden}.home.project:not(.pure) .feature-item:before{content:" ";position:absolute;top:0;bottom:0;width:300%;height:300%;background:rgba(255,255,255,.5);transition:transform .6s;transform:scale3d(1.9,1.4,1) rotate3d(0,0,1,45deg) translate3d(0,-125%,0)}html[data-theme=dark] .home.project:not(.pure) .feature-item:before{background:rgba(255,255,255,.15)}html[dir=rtl] .home.project:not(.pure) .feature-item:before{transform:scale3d(-1.9,1.4,1) rotate3d(0,0,1,45deg) translate3d(0,-125%,0)}.home.project:not(.pure) .feature-item:hover:before{transform:scale3d(1.9,1.4,1) rotate3d(0,0,1,45deg) translate3d(0,125%,0)}html[dir=rtl] .home.project:not(.pure) .feature-item:hover:before{transform:scale3d(-1.9,1.4,1) rotate3d(0,0,1,45deg) translate3d(0,125%,0)}.home.project:not(.pure) .feature-item:hover .icon{animation-name:bounce;animation-duration:var(--fa-animation-duration, 1s);animation-timing-function:var(--fa-animation-timing, cubic-bezier(.28, .84, .42, 1));animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal)}.feature-item h3{margin:.25rem 0 .5rem;color:var(--text-color-light);font-weight:700;font-size:1.3rem}@media (max-width: 419px){.feature-item h3{font-size:1.2rem}}.feature-item p{margin:0;color:var(--text-color-lighter);line-height:1.4}@media (min-width: 959px){.hero-info-wrapper{display:flex;align-items:center;justify-content:space-evenly}}.hero-info-wrapper img{display:block;max-width:100%;max-height:18rem;margin:0}@media (max-width: 959px){.hero-info-wrapper img{margin:2rem auto}}@media (max-width: 719px){.hero-info-wrapper img{max-height:16rem;margin:1.5rem auto}}@media (max-width: 419px){.hero-info-wrapper img{max-height:14rem}}.hero-info-wrapper img.light{display:block}html[data-theme=dark] .hero-info-wrapper img.light,.hero-info-wrapper img.dark{display:none}html[data-theme=dark] .hero-info-wrapper img.dark{display:block}.hero-info-wrapper h1,.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.8rem 0}@media (max-width: 719px){.hero-info-wrapper h1,.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.5rem 0}}@media (max-width: 959px){.hero-info-wrapper h1,.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.5rem auto;text-align:center}}@media (max-width: 419px){.hero-info-wrapper h1,.hero-info-wrapper .description,.hero-info-wrapper .actions{margin:1.2rem 0}}.hero-info-wrapper h1{font-size:3.6rem;font-family:var(--font-family-fancy)}@media (max-width: 719px){.hero-info-wrapper h1{font-size:2.5rem}}@media (max-width: 419px){.hero-info-wrapper h1{font-size:2rem}}.hero-info-wrapper .description{max-width:35rem;color:var(--text-color-bright);font-weight:500;font-size:1.6rem;line-height:1.3}@media (max-width: 719px){.hero-info-wrapper .description{font-size:1.4rem}}@media (max-width: 419px){.hero-info-wrapper .description{font-size:1.2rem}}.hero-info-wrapper .action-button{display:inline-block;overflow:hidden;margin:.5rem;padding:.5em 1.5rem;border-radius:2rem;background:var(--bg-color-secondary);color:var(--text-color);font-size:1.2rem;transition:color var(--color-transition),color var(--color-transition),transform var(--transform-transition)}@media (max-width: 719px){.hero-info-wrapper .action-button{padding:.8rem 1.2rem;font-size:1.1rem}}@media (max-width: 419px){.hero-info-wrapper .action-button{font-size:1rem}}@media print{.hero-info-wrapper .action-button{text-decoration:none}}.hero-info-wrapper .action-button:hover{background:var(--bg-color-tertiary)}.hero-info-wrapper .action-button.primary{border-color:var(--theme-color);background:var(--theme-color);color:var(--white)}.hero-info-wrapper .action-button.primary:hover{border-color:var(--theme-color-light);background:var(--theme-color-light)}.home.project:not(.pure) .hero-info-wrapper .action-button:active{transform:scale(.96)}.home.project{--content-width: var(--home-page-width);display:block;flex:1;padding-top:var(--navbar-height)}.home.project .hero-info-wrapper{max-width:var(--home-page-width);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem}@media (max-width: 959px){.home.project .hero-info-wrapper{-webkit-padding-start:1.5em;padding-inline-start:1.5em;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.home.project .hero-info-wrapper{max-width:unset}}.home.project .feature-panel{max-width:var(--home-page-width);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:1rem;padding-inline-start:1rem;-webkit-padding-end:1rem;padding-inline-end:1rem}@media print{.home.project .feature-panel{max-width:unset}}.home.project .theme-hope-content{padding-bottom:1.5rem}.theme-hope-content:not(.custom)>*:first-child{margin-top:0}.breadcrumb{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;position:relative;z-index:2;padding-top:1rem;font-size:15px}@media (max-width: 959px){.breadcrumb{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.breadcrumb{max-width:unset}}@media (max-width: 959px){.breadcrumb{font-size:14px}}@media (max-width: 419px){.breadcrumb{padding-top:.5rem;font-size:12.8px}}@media print{.breadcrumb{display:none}}.breadcrumb .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.breadcrumb a{display:inline-block;padding:0 .5em}.breadcrumb a:before{position:relative;bottom:.125rem;-webkit-margin-end:.25em;margin-inline-end:.25em}.breadcrumb a:hover{color:var(--theme-color)}.breadcrumb ol{margin:0;-webkit-padding-start:0;padding-inline-start:0;list-style:none}.breadcrumb li{display:inline-block;line-height:1.5}.breadcrumb li:first-child a{-webkit-padding-start:0;padding-inline-start:0}.breadcrumb li:last-child a{-webkit-padding-end:0;padding-inline-end:0}.breadcrumb li.is-active a{color:var(--light-grey);cursor:default;pointer-events:none}.breadcrumb li+li:before{content:"/";color:var(--light-grey)}.page-nav{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;display:flex;flex-wrap:wrap;min-height:2rem;margin-top:0;padding-top:.5rem;padding-bottom:.5rem;border-top:1px solid var(--border-color);transition:border-top var(--color-transition)}@media (max-width: 959px){.page-nav{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.page-nav{max-width:unset}}@media print{.page-nav{display:none}}.page-nav .nav-link{display:inline-block;flex-grow:1;margin:.25rem;padding:.25rem .5rem;border:1px solid var(--border-color);border-radius:.25rem}.page-nav .nav-link:hover{background:var(--bg-color-secondary)}.page-nav .nav-link .hint{color:var(--light-grey);font-size:.875rem;line-height:2}.page-nav .nav-link .arrow{display:inline-block;vertical-align:middle;width:1em;height:1em;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(0,0,0,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E");line-height:normal;transition:all .3s;font-size:.75rem}html[data-theme=dark] .page-nav .nav-link .arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='rgba(255,255,255,0.5)' d='M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z'/%3E%3C/svg%3E")}.page-nav .nav-link .arrow.down{transform:rotate(180deg)}html[dir=rtl] .page-nav .nav-link .arrow.down{transform:rotate(-180deg)}.page-nav .nav-link .arrow.end{transform:rotate(90deg)}html[dir=rtl] .page-nav .nav-link .arrow.end,.page-nav .nav-link .arrow.start{transform:rotate(-90deg)}html[dir=rtl] .page-nav .nav-link .arrow.start{transform:rotate(90deg)}.page-nav .prev{text-align:start}.page-nav .prev .icon{-webkit-margin-end:.25em;margin-inline-end:.25em}.page-nav .next{text-align:end}.page-nav .next .icon{-webkit-margin-start:.25em;margin-inline-start:.25em}.page-author-item{display:inline-block;margin:0 4px;font-weight:400;overflow-wrap:break-word}.page-category-info{flex-wrap:wrap}.page-category-item{display:inline-block;margin:.125em .25em;padding:0 .25em;border-radius:.25em;background:var(--bg-color-secondary);color:var(--text-color-light);font-weight:700;font-size:.75rem;line-height:2;transition:background var(--color-transition),color var(--color-transition)}@media print{.page-category-item{padding:0;font-weight:400}.page-category-item:after{content:", "}.page-category-item:last-of-type:after{content:""}}.page-category-item.clickable>span:hover{color:var(--theme-color);cursor:pointer}.page-category-item.category0{background:#fde5e7;color:#ec2f3e}html[data-theme=dark] .page-category-item.category0{background:#340509;color:#ba111f}.page-category-item.category0:hover{background:#f9bec3}html[data-theme=dark] .page-category-item.category0:hover{background:#53080e}.page-category-item.category1{background:#ffeee8;color:#fb7649}html[data-theme=dark] .page-category-item.category1{background:#441201;color:#f54205}.page-category-item.category1:hover{background:#fed4c6}html[data-theme=dark] .page-category-item.category1:hover{background:#6d1d02}.page-category-item.category2{background:#fef5e7;color:#f5b041}html[data-theme=dark] .page-category-item.category2{background:#3e2703;color:#e08e0b}.page-category-item.category2:hover{background:#fce6c4}html[data-theme=dark] .page-category-item.category2:hover{background:#633f05}.page-category-item.category3{background:#eafaf1;color:#55d98d}html[data-theme=dark] .page-category-item.category3{background:#0c331c;color:#29b866}.page-category-item.category3:hover{background:#caf3db}html[data-theme=dark] .page-category-item.category3:hover{background:#12522d}.page-category-item.category4{background:#e6f9ee;color:#36d278}html[data-theme=dark] .page-category-item.category4{background:#092917;color:#219552}.page-category-item.category4:hover{background:#c0f1d5}html[data-theme=dark] .page-category-item.category4:hover{background:#0f4224}.page-category-item.category5{background:#e1fcfc;color:#16e1e1}html[data-theme=dark] .page-category-item.category5{background:#042929;color:#0e9595}.page-category-item.category5:hover{background:#b4f8f8}html[data-theme=dark] .page-category-item.category5:hover{background:#064242}.page-category-item.category6{background:#e4f0fe;color:#2589f6}html[data-theme=dark] .page-category-item.category6{background:#021b36;color:#0862c3}.page-category-item.category6:hover{background:#bbdafc}html[data-theme=dark] .page-category-item.category6:hover{background:#042c57}.page-category-item.category7{background:#f7f1fd;color:#bb8ced}html[data-theme=dark] .page-category-item.category7{background:#2a0b4b;color:#9851e4}.page-category-item.category7:hover{background:#eadbfa}html[data-theme=dark] .page-category-item.category7:hover{background:#431277}.page-category-item.category8{background:#fdeaf5;color:#ef59ab}html[data-theme=dark] .page-category-item.category8{background:#400626;color:#e81689}.page-category-item.category8:hover{background:#facbe5}html[data-theme=dark] .page-category-item.category8:hover{background:#670a3d}.page-original-info{position:relative;display:inline-block;vertical-align:middle;overflow:hidden;padding:0 .5em;border:.5px solid var(--dark-grey);border-radius:.75em;background:var(--bg-color);font-size:.75em;line-height:1.5}.page-tag-info{flex-wrap:wrap}.page-tag-item{position:relative;display:inline-block;vertical-align:middle;overflow:hidden;min-width:1.5rem;margin:.125rem;padding:.125rem .25rem .125rem .625rem;background:var(--bg-color-secondary);background:linear-gradient(135deg,transparent .75em,var(--bg-color-secondary) 0) top,linear-gradient(45deg,transparent .75em,var(--bg-color-secondary) 0) bottom;background-size:100% 52%!important;background-repeat:no-repeat!important;color:var(--text-color-light);font-weight:700;font-size:.625rem;line-height:1.5;text-align:center;transition:background var(--color-transition),color var(--color-transition)}@media print{.page-tag-item{padding:0;font-weight:400}.page-tag-item:after{content:", "}.page-tag-item:last-of-type:after{content:""}}.page-tag-item.clickable:hover{cursor:pointer}.page-tag-item.tag0{background:#fde5e7;background:linear-gradient(135deg,transparent .75em,#fde5e7 0) top,linear-gradient(45deg,transparent .75em,#fde5e7 0) bottom;color:#ec2f3e}html[data-theme=dark] .page-tag-item.tag0{background:#340509;background:linear-gradient(135deg,transparent .75em,#340509 0) top,linear-gradient(45deg,transparent .75em,#340509 0) bottom;color:#ba111f}.page-tag-item.tag0.clickable:hover{background:#f9bec3;background:linear-gradient(135deg,transparent .75em,#f9bec3 0) top,linear-gradient(45deg,transparent .75em,#f9bec3 0) bottom}html[data-theme=dark] .page-tag-item.tag0.clickable:hover{background:#53080e;background:linear-gradient(135deg,transparent .75em,#53080e 0) top,linear-gradient(45deg,transparent .75em,#53080e 0) bottom}.page-tag-item.tag1{background:#ffeee8;background:linear-gradient(135deg,transparent .75em,#ffeee8 0) top,linear-gradient(45deg,transparent .75em,#ffeee8 0) bottom;color:#fb7649}html[data-theme=dark] .page-tag-item.tag1{background:#441201;background:linear-gradient(135deg,transparent .75em,#441201 0) top,linear-gradient(45deg,transparent .75em,#441201 0) bottom;color:#f54205}.page-tag-item.tag1.clickable:hover{background:#fed4c6;background:linear-gradient(135deg,transparent .75em,#fed4c6 0) top,linear-gradient(45deg,transparent .75em,#fed4c6 0) bottom}html[data-theme=dark] .page-tag-item.tag1.clickable:hover{background:#6d1d02;background:linear-gradient(135deg,transparent .75em,#6d1d02 0) top,linear-gradient(45deg,transparent .75em,#6d1d02 0) bottom}.page-tag-item.tag2{background:#fef5e7;background:linear-gradient(135deg,transparent .75em,#fef5e7 0) top,linear-gradient(45deg,transparent .75em,#fef5e7 0) bottom;color:#f5b041}html[data-theme=dark] .page-tag-item.tag2{background:#3e2703;background:linear-gradient(135deg,transparent .75em,#3e2703 0) top,linear-gradient(45deg,transparent .75em,#3e2703 0) bottom;color:#e08e0b}.page-tag-item.tag2.clickable:hover{background:#fce6c4;background:linear-gradient(135deg,transparent .75em,#fce6c4 0) top,linear-gradient(45deg,transparent .75em,#fce6c4 0) bottom}html[data-theme=dark] .page-tag-item.tag2.clickable:hover{background:#633f05;background:linear-gradient(135deg,transparent .75em,#633f05 0) top,linear-gradient(45deg,transparent .75em,#633f05 0) bottom}.page-tag-item.tag3{background:#eafaf1;background:linear-gradient(135deg,transparent .75em,#eafaf1 0) top,linear-gradient(45deg,transparent .75em,#eafaf1 0) bottom;color:#55d98d}html[data-theme=dark] .page-tag-item.tag3{background:#0c331c;background:linear-gradient(135deg,transparent .75em,#0c331c 0) top,linear-gradient(45deg,transparent .75em,#0c331c 0) bottom;color:#29b866}.page-tag-item.tag3.clickable:hover{background:#caf3db;background:linear-gradient(135deg,transparent .75em,#caf3db 0) top,linear-gradient(45deg,transparent .75em,#caf3db 0) bottom}html[data-theme=dark] .page-tag-item.tag3.clickable:hover{background:#12522d;background:linear-gradient(135deg,transparent .75em,#12522d 0) top,linear-gradient(45deg,transparent .75em,#12522d 0) bottom}.page-tag-item.tag4{background:#e6f9ee;background:linear-gradient(135deg,transparent .75em,#e6f9ee 0) top,linear-gradient(45deg,transparent .75em,#e6f9ee 0) bottom;color:#36d278}html[data-theme=dark] .page-tag-item.tag4{background:#092917;background:linear-gradient(135deg,transparent .75em,#092917 0) top,linear-gradient(45deg,transparent .75em,#092917 0) bottom;color:#219552}.page-tag-item.tag4.clickable:hover{background:#c0f1d5;background:linear-gradient(135deg,transparent .75em,#c0f1d5 0) top,linear-gradient(45deg,transparent .75em,#c0f1d5 0) bottom}html[data-theme=dark] .page-tag-item.tag4.clickable:hover{background:#0f4224;background:linear-gradient(135deg,transparent .75em,#0f4224 0) top,linear-gradient(45deg,transparent .75em,#0f4224 0) bottom}.page-tag-item.tag5{background:#e1fcfc;background:linear-gradient(135deg,transparent .75em,#e1fcfc 0) top,linear-gradient(45deg,transparent .75em,#e1fcfc 0) bottom;color:#16e1e1}html[data-theme=dark] .page-tag-item.tag5{background:#042929;background:linear-gradient(135deg,transparent .75em,#042929 0) top,linear-gradient(45deg,transparent .75em,#042929 0) bottom;color:#0e9595}.page-tag-item.tag5.clickable:hover{background:#b4f8f8;background:linear-gradient(135deg,transparent .75em,#b4f8f8 0) top,linear-gradient(45deg,transparent .75em,#b4f8f8 0) bottom}html[data-theme=dark] .page-tag-item.tag5.clickable:hover{background:#064242;background:linear-gradient(135deg,transparent .75em,#064242 0) top,linear-gradient(45deg,transparent .75em,#064242 0) bottom}.page-tag-item.tag6{background:#e4f0fe;background:linear-gradient(135deg,transparent .75em,#e4f0fe 0) top,linear-gradient(45deg,transparent .75em,#e4f0fe 0) bottom;color:#2589f6}html[data-theme=dark] .page-tag-item.tag6{background:#021b36;background:linear-gradient(135deg,transparent .75em,#021b36 0) top,linear-gradient(45deg,transparent .75em,#021b36 0) bottom;color:#0862c3}.page-tag-item.tag6.clickable:hover{background:#bbdafc;background:linear-gradient(135deg,transparent .75em,#bbdafc 0) top,linear-gradient(45deg,transparent .75em,#bbdafc 0) bottom}html[data-theme=dark] .page-tag-item.tag6.clickable:hover{background:#042c57;background:linear-gradient(135deg,transparent .75em,#042c57 0) top,linear-gradient(45deg,transparent .75em,#042c57 0) bottom}.page-tag-item.tag7{background:#f7f1fd;background:linear-gradient(135deg,transparent .75em,#f7f1fd 0) top,linear-gradient(45deg,transparent .75em,#f7f1fd 0) bottom;color:#bb8ced}html[data-theme=dark] .page-tag-item.tag7{background:#2a0b4b;background:linear-gradient(135deg,transparent .75em,#2a0b4b 0) top,linear-gradient(45deg,transparent .75em,#2a0b4b 0) bottom;color:#9851e4}.page-tag-item.tag7.clickable:hover{background:#eadbfa;background:linear-gradient(135deg,transparent .75em,#eadbfa 0) top,linear-gradient(45deg,transparent .75em,#eadbfa 0) bottom}html[data-theme=dark] .page-tag-item.tag7.clickable:hover{background:#431277;background:linear-gradient(135deg,transparent .75em,#431277 0) top,linear-gradient(45deg,transparent .75em,#431277 0) bottom}.page-tag-item.tag8{background:#fdeaf5;background:linear-gradient(135deg,transparent .75em,#fdeaf5 0) top,linear-gradient(45deg,transparent .75em,#fdeaf5 0) bottom;color:#ef59ab}html[data-theme=dark] .page-tag-item.tag8{background:#400626;background:linear-gradient(135deg,transparent .75em,#400626 0) top,linear-gradient(45deg,transparent .75em,#400626 0) bottom;color:#e81689}.page-tag-item.tag8.clickable:hover{background:#facbe5;background:linear-gradient(135deg,transparent .75em,#facbe5 0) top,linear-gradient(45deg,transparent .75em,#facbe5 0) bottom}html[data-theme=dark] .page-tag-item.tag8.clickable:hover{background:#670a3d;background:linear-gradient(135deg,transparent .75em,#670a3d 0) top,linear-gradient(45deg,transparent .75em,#670a3d 0) bottom}.page-info{display:flex;flex-wrap:wrap;align-content:stretch;align-items:center;justify-content:flex-start;color:var(--dark-grey);font-size:14px}@media print{.page-info{display:flex!important}}.page-info>span{display:flex;align-items:center;max-width:100%;-webkit-margin-end:.5em;margin-inline-end:.5em;line-height:2}@media (min-width: 1440px){.page-info>span{font-size:1.1em}}@media (max-width: 419px){.page-info>span{-webkit-margin-end:.3em;margin-inline-end:.3em;font-size:.875em}}@media print{.page-info>span{display:flex!important}}.page-info .icon{position:relative;display:inline-block;vertical-align:middle;width:1em;height:1em;-webkit-margin-end:.25em;margin-inline-end:.25em}.page-info a{color:inherit}.page-info a:hover,.page-info a:active{color:var(--theme-color)}.page-title{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;position:relative;z-index:1;padding-top:1rem;padding-bottom:0}@media (max-width: 959px){.page-title{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.page-title{max-width:unset}}@media print{.page-title{-webkit-padding-start:0!important;padding-inline-start:0!important;-webkit-padding-end:0!important;padding-inline-end:0!important}}@media (max-width: 959px){.page-title{padding-top:.5rem}}.page-title h1{margin-top:calc(0px - var(--navbar-height))!important;margin-bottom:1rem;padding-top:var(--navbar-height)!important;font-size:2.2rem}@media (max-width: 959px){.page-title h1{margin-bottom:.5rem}}.page-title h1 .icon{-webkit-margin-end:.25em;margin-inline-end:.25em;color:var(--theme-color);font-size:.9em}.theme-hope-content:not(.custom){padding-top:0!important}.theme-hope-content:not(.custom) h1:first-child,.theme-hope-content:not(.custom) h2:first-child,.theme-hope-content:not(.custom) h3:first-child,.theme-hope-content:not(.custom) h4:first-child,.theme-hope-content:not(.custom) h5:first-child,.theme-hope-content:not(.custom) h6:first-child{margin-top:calc(.5rem - var(--navbar-height))!important;padding-top:var(--navbar-height)!important}.theme-hope-content:not(.custom)>h1:first-child{display:none}.page-meta{max-width:var(--content-width, 740px);-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;display:flex;flex-wrap:wrap;justify-content:space-between;overflow:auto;padding-top:.75rem;padding-bottom:.75rem}@media (max-width: 959px){.page-meta{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.page-meta{max-width:unset}}@media print{.page-meta{margin:0!important;-webkit-padding-start:0!important;padding-inline-start:0!important;-webkit-padding-end:0!important;padding-inline-end:0!important}}@media (max-width: 719px){.page-meta{display:block}}.page-meta .meta-item{flex-grow:1}.page-meta .meta-item .label{font-weight:500}.page-meta .meta-item .label:not(a){color:var(--text-color-lighter)}.page-meta .meta-item .info{color:var(--dark-grey);font-weight:400}.page-meta .git-info{text-align:end}.page-meta .edit-link{margin-top:.25rem;margin-bottom:.25rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem;font-size:14px}@media print{.page-meta .edit-link{display:none}}.page-meta .edit-link .icon{position:relative;bottom:-.125em;width:1em;height:1em;-webkit-margin-end:.25em;margin-inline-end:.25em}.page-meta .update-time,.page-meta .contributors{margin-top:.25rem;margin-bottom:.25rem;font-size:14px}@media (max-width: 719px){.page-meta .update-time,.page-meta .contributors{font-size:13px;text-align:start}}.print-button{border-width:0;background:transparent;cursor:pointer;box-sizing:content-box;width:1rem;height:1rem;padding:.5rem;border-radius:.25em;color:inherit;font-size:1rem;transform:translateY(.25rem)}@media print{.print-button{display:none}}.toc-place-holder{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem;-webkit-padding-end:2.5rem;padding-inline-end:2.5rem;position:sticky;top:calc(var(--navbar-height) + 2rem);z-index:99;max-width:var(--content-width, 740px)}@media (max-width: 959px){.toc-place-holder{-webkit-padding-start:1.5rem;padding-inline-start:1.5rem;-webkit-padding-end:1.5rem;padding-inline-end:1.5rem}}@media print{.toc-place-holder{max-width:unset}}.toc-place-holder+.theme-hope-content:not(.custom){padding-top:0}#toc{position:absolute;left:calc(100% + 1rem);display:none;min-width:10rem;max-width:15rem}@media (min-width: 1440px){.has-toc #toc{display:block}}@media print{#toc{display:none!important}}html[dir=rtl] #toc{right:calc(100% + 1rem);left:unset}#toc .toc-header{margin-bottom:.75rem;-webkit-margin-start:.5rem;margin-inline-start:.5rem;font-weight:600;font-size:.875rem}#toc .toc-wrapper{position:relative;overflow-x:hidden;overflow-y:auto;max-height:75vh;margin:0 .5rem;-webkit-padding-start:8px;padding-inline-start:8px;text-overflow:ellipsis;white-space:nowrap;scroll-behavior:smooth}#toc .toc-wrapper::-webkit-scrollbar-track-piece{background:transparent}#toc .toc-wrapper::-webkit-scrollbar{width:3px}#toc .toc-wrapper::-webkit-scrollbar-thumb:vertical{background:#ddd}html[data-theme=dark] #toc .toc-wrapper::-webkit-scrollbar-thumb:vertical{background:#333}#toc .toc-list{position:relative;margin:0;padding:0}#toc .toc-list:before{content:" ";position:absolute;top:0;bottom:0;left:-8px;z-index:-1;width:2px;background:var(--border-color)}html[dir=rtl] #toc .toc-list:before{right:-8px;left:unset}#toc .toc-link{position:relative;display:block;overflow:hidden;max-width:100%;color:var(--light-grey);line-height:inherit;text-overflow:ellipsis;white-space:nowrap}#toc .toc-link.level2{-webkit-padding-start:0px;padding-inline-start:0px;font-size:14px}#toc .toc-link.level3{-webkit-padding-start:8px;padding-inline-start:8px;font-size:13px}#toc .toc-link.level4{-webkit-padding-start:16px;padding-inline-start:16px;font-size:12px}#toc .toc-link.level5{-webkit-padding-start:24px;padding-inline-start:24px;font-size:11px}#toc .toc-link.level6{-webkit-padding-start:32px;padding-inline-start:32px;font-size:10px}#toc .toc-item{position:relative;box-sizing:border-box;height:1.7rem;padding:0 .5rem;list-style:none;line-height:1.7rem}#toc .toc-item:before{content:" ";position:absolute;top:0;bottom:0;left:-8px;z-index:2;width:2px;background:transparent}html[dir=rtl] #toc .toc-item:before{right:-8px;left:unset}#toc .toc-item:hover>.toc-link{color:var(--theme-color)}#toc .toc-item.active>.toc-link{color:var(--theme-color);font-weight:700}#toc .toc-item.active:before{background:var(--theme-color)}.page{display:block;flex-grow:1;padding-bottom:2rem;transition:padding var(--transform-transition)}@media print{.page{min-height:auto!important;margin:0!important;padding:0!important}}.skip-link{top:.25rem;left:.25rem;z-index:999;padding:.65rem 1.5rem;border-radius:.5rem;background:var(--bg-color);color:var(--theme-color);box-shadow:var(--card-shadow);font-weight:700;font-size:.9em;text-decoration:none}@media print{.skip-link{display:none}}.skip-link:focus{clip:auto;width:auto;height:auto;-webkit-clip-path:none;clip-path:none}.fade-slide-y-enter-active{transition:all .3s ease}.fade-slide-y-leave-active{transition:all .3s cubic-bezier(1,.5,.8,1)}.fade-slide-y-enter-from,.fade-slide-y-leave-to{opacity:0;transform:translateY(10px)}.not-found-hint{padding:2rem}.not-found-hint .error-code{margin:0;font-weight:700;font-size:4rem;line-height:4rem}.not-found-hint .error-title{font-weight:700}.not-found-hint .error-hint{margin:0;padding:12px 0;font-weight:600;font-size:20px;line-height:20px;letter-spacing:2px}.page.not-found{display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;width:100vw;max-width:var(--home-page-width);margin:0 auto;padding:calc(var(--navbar-height) + 1rem) 1rem 1rem!important;text-align:center}.page.not-found .action-button{display:inline-block;box-sizing:border-box;margin:.25rem;padding:.75rem 1rem;border-width:0;border-bottom:1px solid var(--theme-color-dark);border-radius:3rem;background:var(--theme-color);color:var(--white);outline:none;font-size:1rem;transition:background .1s ease}.page.not-found .action-button:hover{background:var(--theme-color-light);cursor:pointer}:root{--navbar-bg-color: var(--bg-color-float-blur);--sidebar-bg-color: var(--bg-color-blur)}html[data-theme=dark]{--navbar-bg-color: var(--bg-color-blur);--sidebar-bg-color: var(--bg-color-blur)}#app{--code-hl-bg-color: var(--code-highlight-line-color);--code-ln-color: var(--code-line-color);--code-ln-wrapper-width: var(--line-numbers-width);--code-tabs-nav-text-color: var(--code-color);--code-tabs-nav-bg-color: var(--code-border-color);--code-tabs-nav-hover-color: var(--code-highlight-line-color);--sidebar-space: var(--sidebar-width)}@media (max-width: 959px){#app{--navbar-height: var(--navbar-mobile-height);--navbar-vertical-padding: var(--navbar-mobile-vertical-padding);--navbar-horizontal-padding: var(--navbar-mobile-horizontal-padding);--sidebar-width: var(--sidebar-mobile-width)}}@media (min-width: 1440px){#app{--sidebar-space: clamp( var(--sidebar-width), max(0px, calc((100vw - var(--content-width)) / 2 - 2rem)), 100vw )}}.DocSearch-Button,.DocSearch{--docsearch-primary-color: var(--vp-tc);--docsearch-text-color: var(--vp-c);--docsearch-highlight-color: var(--vp-tc);--docsearch-muted-color: var(--light-grey);--docsearch-container-background: rgb(9 10 17 / 80%);--docsearch-modal-background: var(--bg-color-float);--docsearch-searchbox-background: var(--bg-color-secondary);--docsearch-searchbox-focus-background: var(--vp-bg);--docsearch-searchbox-shadow: inset 0 0 0 2px var(--vp-tc);--docsearch-hit-color: var(--vp-cl);--docsearch-hit-active-color: var(--vp-bg);--docsearch-hit-background: var(--vp-bg);--docsearch-hit-shadow: 0 1px 3px 0 var(--border-color);--docsearch-footer-background: var(--vp-bg)}html[data-theme=dark] .DocSearch-Button,html[data-theme=dark] .DocSearch{--docsearch-logo-color: var(--vp-c);--docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309;--docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d, 0 2px 2px 0 rgb(3 4 9 / 30%);--docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21);--docsearch-footer-shadow: inset 0 1px 0 0 rgb(73 76 106 / 50%), 0 -4px 8px 0 rgb(0 0 0 / 20%)}#nprogress{--nprogress-color: var(--vp-tc)}.search-box{--search-bg-color: var(--vp-bg);--search-accent-color: var(--vp-tc);--search-text-color: var(--vp-c);--search-border-color: var(--border-color);--search-item-text-color: var(--vp-clt);--search-item-focus-bg-color: var(--bg-color-secondary)}.external-link-icon{--external-link-icon-color: var(--light-grey)}html,body{margin:0;padding:0;background:#fff}body{min-height:100vh;color:#2c3e50;font-size:16px;font-display:optional;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-tap-highlight-color:transparent}@media print{body{font-size:12pt}}a{color:#3eaf7c;font-weight:500;text-decoration:none;overflow-wrap:break-word}kbd{padding:0 .15em;border:solid .15rem #ddd;border-bottom:solid .25rem #ddd;border-radius:.15rem;background:#eee}code{margin:0;padding:.25rem .5rem;border-radius:3px;background:rgba(127,127,127,.12);font-size:.85em;overflow-wrap:break-word}table code{padding:.1rem .4rem}p a code{color:#3eaf7c;font-weight:400}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:500;line-height:1.25;overflow-wrap:break-word}h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2rem}h2{padding-bottom:.3rem;border-bottom:1px solid #eaecef;font-size:1.65rem}h3{font-size:1.35rem}h4{font-size:1.15rem}h5{font-size:1.05rem}h6{font-size:1rem}a.header-anchor{float:left;margin-top:.125em;-webkit-margin-start:-.87em;margin-inline-start:-.87em;-webkit-padding-end:.23em;padding-inline-end:.23em;font-size:.85em;opacity:0;transition:opacity .2s}@media print{a.header-anchor{display:none!important}}a.header-anchor:hover{text-decoration:none}a.header-anchor:focus-visible{opacity:1}p,ul,ol{line-height:1.7;overflow-wrap:break-word}@media print{p,ul,ol{line-height:1.5}}ul,ol{-webkit-padding-start:1.2em;padding-inline-start:1.2em}blockquote{margin:1rem 0;padding:.25rem 0 .25rem 1rem;-webkit-border-start:.2rem solid #ddd;border-inline-start:.2rem solid #ddd;color:#666;font-size:1rem;overflow-wrap:break-word}blockquote>p{margin:0}hr{border:0;border-top:1px solid #eaecef}table{display:block;overflow-x:auto;margin:1rem 0;border-collapse:collapse}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background:#f6f8fa}th,td{padding:.6em 1em;border:1px solid #dfe2e5}pre{direction:ltr}@page{margin:2cm;font-size:12pt;size:a4}@media print{*,:after,:before{box-shadow:none!important;text-shadow:none!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}a{color:inherit;font-weight:inherit!important;font-size:inherit!important;text-decoration:underline}a[href^="http://"]:after,a[href^="https://"]:after{content:" (" attr(href) ") "}abbr[title]:after{content:" (" attr(title) ")"}pre{border:1px solid #eee;white-space:pre-wrap!important}pre>code{white-space:pre-wrap!important}blockquote{-webkit-border-start:.2rem solid #ddd;border-inline-start:.2rem solid #ddd;color:inherit}blockquote,pre{orphans:5;widows:5}img,tr,canvas{page-break-inside:avoid}}@font-face{font-weight:400;font-style:normal;font-family:Crimson;src:url(data:font/truetype;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTYr5mwEAAAyMAAAAHEdERUYAKQATAAAMbAAAAB5PUy8yVsJ0MgAAAVgAAABgY21hcBiKDzgAAAHcAAABWGdhc3D//wADAAAMZAAAAAhnbHlmr+DBdQAAA1AAAAdsaGVhZBZwt+8AAADcAAAANmhoZWEFawEuAAABFAAAACRobXR4BksA9gAAAbgAAAAibG9jYQlsC24AAAM0AAAAHG1heHAAEQBZAAABOAAAACBuYW1lLaFDVAAACrwAAAFrcG9zdAC1AHoAAAwoAAAAPAABAAAAAQAAqBd2H18PPPUACwQAAAAAANqqufwAAAAA2qq5/AAb/9wB4QMeAAAACAACAAAAAAAAAAEAAAMs/ywAXAH9AAAAAAHhAAEAAAAAAAAAAAAAAAAAAAAEAAEAAAANAFkAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAH1AZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAIABgMAAAAAAAAAAAABEAAAAAAAAAAAAAAAUGZFZADAADAAOQMs/ywAXAMsANQAAAABAAAAAAMYAAAAAAAgAAEBpwAfAAAAAAFVAAAB/QAfAH0ALQA+ABsAPgAyACgAPgAxAAAAAAADAAAAAwAAABwAAQAAAAAAUgADAAEAAAAcAAQANgAAAAQABAABAAAAOf//AAAAL///AAAAAQAEAAAAAAADAAQABQAGAAcACAAJAAoACwAMAAABBgAAAQAAAAAAAAABAgAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwQFBgcICQoLDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYAJgAmAGIAwAEeAZIBzgJAApYC2gNiA7YAAQAf/9wBhwMeABIAAAEGBwYHATAXFjM2NzY3ASYnJjcBgxwLCgH+zgMECxIKCgIBLgEDAwMDHhQFBgP85wMEAQgJBgMOAwMDEwAAAAIAH//9Ad0CkAAQACEAABMWFxYXNjc2NzQnJicGBwYHNyY3NjcWFxYXFAcGByYnJjcfATo6amo7OQE5OmxrOjkBXQIlJEE5IyIBIyJEOSQjAgFOkV5eBAReXoqJXl4EBF5eggJ0UlEDA09Qe3xVVgMDU1OEAAAAAAEAff/9AYACkQA+AAA3FAcGBwYHBiMGFQYXNjc2MzIXFhc2JzQnIicmJyY1JjURNjc2MSYnJicjBgcGBwYVFBUUFxYXNjc2NzIXFhXkAQEEBRgYDAMBBB4ZGhweGxofBAEDDBgZBQQBAQMEAQIDBAIFNTZCAgMDBA0XFw0LBQV3GBMVDAgEBAUKCgUCAQICAQIFCgoFBAQIDBUTGAGnLxkbBAYFAQIZGh4BAgECBQUEAwUHBwEICRYAAAAAAQAtAAAB0QKRADoAADcGFxYXITY3NjcmJyYjIgcGBwYHBisBNjc2NzY3NjUmJyYnBgcGBxQXFhc2NzY3FhcWFxYHBgcGBwYHLgEEAwMBYwURERADBwYFBAMDAg8VEx/LJkBAOhsQDwIxMkxSMjIHCAYGCSYmPTIfHwEBCgoeLkJBQg8EBQQCETAwKQICAgEBBCgUEylJSUYhJicsRDIzAgY1NRoEBQYBEyEhAwEjIjYlJCQtQlBQSAAAAAABAD7/+wG+ApEASgAANwYXFhcWFxYzNjc2NyYnJic2NzY3JicmIwYHBgcUFxYXNjc2NxYXFhcGBwYHBgcUFRQXNjc2NxYXFhcGBwYnIicmJyYnJiciBwYXPwEIBwUaHB0VZU5NBAMvLi8eIB4DAywsKzwrKxgEAwUIHR4wLRscAQMvLz8BAQYKEhEQNSYmAgImJSsWExQPCw0NFREMDQE7DgsLBQwFBgE8PWpMKSoGECQkMkAiIQIdHyUHBwcBCRscAwEbGSpCIyUOAgMCAwwIAwUEAQEoKD9XJSQBBQYODg8PAQ0NFQAAAgAb//oB4QKTACIAJQAANxQXFhchFRQXFjMyNzYjNTM2NzY1NCcmJyMRNCcmIwYHBgcBExEbAgMFASEJCRIdCAkBRgIBAQUEBTwFAwgHCQkG/vjmxgUGBgOwBQIBAwKzAgQDCBAMDQEBlAYGBgEICQf+cwEs/tQAAQA+//sBvgKTAEoAADcGFxYXFhcWMzY3NjcmJyYnIgcGBzY3NjczMjc2NzY3NjU0JyYnBgcGByMGBwYHFBcWMzY3NjMWFxYHBgcGJyInJicmJyYnIgcGFz8BCAcFGhwdFWVOTQQBMjJbFx8gFwoJCQlWKB0dFQ4JCAQDBQMdHSKXCREQEgMCBA4bGhNYJyUBAiYlKxYTFA8LDQ0VEQwNATsOCwsFDAUGATw9akU2NwMFBggrMC8uAgICExcZBgQCAgMBAwQBMVNUWAUFBAYFBAMxMTNZIyQBBQYODg8PAQ0NFQAAAgAy//oBzQKXACAAMwAANxQXFhc2NzY3NicmJyIHBgc2NzY3NCcmJwYHBgcGBwYXNyY3Njc2FxYXFgcGBwYHJicmNzM1NV5aOTsCAioqahoiIRsnWFhFAwIHQ0tMOTAZGQFbBAQaGxkXRB8fAQEfIDE9Hh4E511FRwQDPT1ZPEJBBQwLF4Y9PRMGCwwBEiwsPDZFRkkTHyAbCAcBAjAwREYsLQEFREVQAAAAAAEAKP/7AdUCiwApAAATFhcWMzI3Njc2NzYzIQYHBgcWFxYzMjcBNjc2NzQnJiMiBwYjIQYHBgcoAwYHAwYDAwELEBEdAQUJYWJXAQ8PDgcDAQ4LCQgBAQEEBhUVFv7JBgsNDAH6DQMCAQEFKRITFMjHjQcFBgMCPxYSEwoEAgMBAhkrKiAAAAADAD7/9wG/ApIAKABBAFgAADcGFxYXNjc2NyYnJicmJzQ3Njc2NyYnJiMGBwYHFhcWFxYVFAcGBwYHNyY3Njc2MzIzMhcyFxYXFhcGBwYHIicmNxMmNzY3FhcWFRQHBgcGByIjIicmJyY3PwE1M1ZQODgDAykpMQIBAyYlJQMCMC9HRjExAgIiIiMCAiMvLwNTBBQTKgEBAQECAQIBEjU1CAEdHjMrISICGAMYGSYvGxoTEx8CAQIBBAMfJCQBoU8tLQECMjFPOC4uGwIBAgEWJiU7SCYoAjEwQzopKhMBAgECEykpQAQsIiEbAQEBBywsQjUeHQEiI0QBZSMhIAECJiYvKh8gFAEBAhAfIEYAAAIAMf/6AcsClwAgADMAABMGFxYXMjc2NwYHBgcUFxYXNjc2NzY3NjUmJyYnBgcGBzcmNzY3FhcWFRQHBgcGJyYnJjc0AyopahoiIRsoV1hFAwIHQ0tMODEZGQE2NF5ZOjoBWgMfHzE9Hh4EGhoaF0QeHwUBy0dBQgUMCxeFPj0SBwsLAREsLD01RkVPV0dFBQQ8PU8UPCwtAQVFRUklIRsHCAECMDBPAAAADACWAAEAAAAAAAEABwAQAAEAAAAAAAIABwAoAAEAAAAAAAMABwBAAAEAAAAAAAQABwBYAAEAAAAAAAUAHgCeAAEAAAAAAAYABwDNAAMAAQQJAAEADgAAAAMAAQQJAAIADgAYAAMAAQQJAAMADgAwAAMAAQQJAAQADgBIAAMAAQQJAAUAPABgAAMAAQQJAAYADgC9AEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAFYAZQByAHMAaQBvAG4AIAAxAC4AMAA7ACAARgBvAG4AdABFAGQAaQB0AG8AcgAgACgAdgAxAC4AMAApAABWZXJzaW9uIDEuMDsgRm9udEVkaXRvciAodjEuMCkAAEMAcgBpAG0AcwBvAG4AAENyaW1zb24AAAACAAAAAAAAADIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAABAAIAEwAUABUAFgAXABgAGQAaABsAHAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAwAAQAEAAAAAgAAAAAAAAABAAAAANWkJwgAAAAA2qq5/AAAAADaqrn8) format("truetype")}html,body{background:var(--bg-color);transition:background var(--color-transition)}:root{color-scheme:light}html[data-theme=dark]{color-scheme:dark}body{color:var(--text-color);font-family:var(--font-family)}a{color:var(--theme-color)}kbd{border-color:var(--grey14);background:var(--bg-color-light);font-family:var(--font-family-code)}code{font-family:var(--font-family-code);transition:background var(--color-transition),color var(--color-transition)}html[data-theme=dark] code{background:#333}p a code{color:var(--theme-color)}blockquote{border-color:#eee;color:#666;transition:border-color var(--color-transition),color var(--color-transition)}html[data-theme=dark] blockquote{border-color:#333}@media (max-width: 419px){h1{font-size:1.9rem}}h2{border-color:var(--border-color);transition:border-bottom-color var(--color-transition)}hr{border-color:var(--border-color);transition:border-top-color var(--color-transition)}tr{border-color:var(--grey14)}tr:nth-child(2n){background:var(--bg-color-light)}html[data-theme=dark] tr:nth-child(2n){background:#252322}th,td{border-color:var(--grey14)}@media print{@page{--text-color: #000 !important;--bg-color: #fff !important}div[class*=language-]{position:relative!important}}.theme-hope-content pre{overflow:auto;margin:.85rem 0;padding:1rem;border-radius:6px;line-height:1.375}.theme-hope-content pre code{padding:0;border-radius:0;background:transparent!important;color:var(--code-color);font-family:var(--font-family-code);text-align:left;white-space:pre;word-spacing:normal;word-wrap:normal;word-break:normal;overflow-wrap:unset;-webkit-hyphens:none;hyphens:none;transition:color var(--color-transition);-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}@media print{.theme-hope-content pre code{white-space:pre-wrap}}.theme-hope-content .line-number{font-family:var(--font-family-code)}div[class*=language-]{position:relative;border-radius:6px;background:var(--code-bg-color);transition:background var(--color-transition)}@media (max-width: 419px){.theme-hope-content>div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}div[class*=language-]:before{content:attr(data-ext);position:absolute;top:.8em;right:1em;z-index:3;color:var(--code-line-color);font-size:.75rem;transition:color var(--color-transition)}div[class*=language-] pre{position:relative;z-index:1}div[class*=language-] .highlight-lines{position:absolute;top:0;left:0;width:100%;padding-top:1rem;line-height:1.375;-webkit-user-select:none;-moz-user-select:none;user-select:none}div[class*=language-] .highlight-line{background:var(--code-highlight-line-color);transition:background var(--color-transition)}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;top:0;left:0;z-index:2;width:var(--line-numbers-width);height:100%;border-right:1px solid var(--code-highlight-line-color);border-radius:6px 0 0 6px;transition:border-color var(--color-transition)}@media (max-width: 419px){div[class*=language-].line-numbers-mode:after{border-radius:0}}div[class*=language-].line-numbers-mode .highlight-line{position:relative}div[class*=language-].line-numbers-mode .highlight-line:before{content:" ";position:absolute;top:0;left:0;z-index:3;display:block;width:var(--line-numbers-width);height:100%}div[class*=language-].line-numbers-mode pre{vertical-align:middle;margin-left:var(--line-numbers-width);padding-left:.5rem}@media print{div[class*=language-].line-numbers-mode pre{margin-left:0;padding-left:1rem}}div[class*=language-].line-numbers-mode .line-numbers{position:absolute;top:0;left:0;width:var(--line-numbers-width);padding:1rem 0;color:var(--code-line-color);line-height:1.375;counter-reset:line-number;text-align:center;transition:color var(--color-transition);transform:translateY(1px)}@media print{div[class*=language-].line-numbers-mode .line-numbers{display:none}}div[class*=language-].line-numbers-mode .line-number{position:relative;z-index:4;height:1.375em;-webkit-user-select:none;-moz-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-number:before{content:counter(line-number);font-size:.85em;counter-increment:line-number}div[class*=language-]:not(.line-numbers-mode) .line-numbers{display:none}html[data-theme=light] #app{--code-color: #383a42;--code-line-color: rgba(56, 58, 66, .67);--code-bg-color: #ecf4fa;--code-border-color: #c3def3;--code-highlight-line-color: #d8e9f6}html[data-theme=light] code[class*=language-],html[data-theme=light] pre[class*=language-]{-moz-tab-size:2;-o-tab-size:2;tab-size:2}html[data-theme=light] code[class*=language-]::-moz-selection,html[data-theme=light] code[class*=language-] ::-moz-selection,html[data-theme=light] pre[class*=language-]::-moz-selection,html[data-theme=light] pre[class*=language-] ::-moz-selection{background:#e5e5e6;color:inherit}html[data-theme=light] code[class*=language-]::selection,html[data-theme=light] code[class*=language-] ::selection,html[data-theme=light] pre[class*=language-]::selection,html[data-theme=light] pre[class*=language-] ::selection{background:#e5e5e6;color:inherit}html[data-theme=light] .token.comment,html[data-theme=light] .token.prolog,html[data-theme=light] .token.cdata{color:#a0a1a7}html[data-theme=light] .token.doctype,html[data-theme=light] .token.punctuation,html[data-theme=light] .token.entity{color:#383a42}html[data-theme=light] .token.attr-name,html[data-theme=light] .token.class-name,html[data-theme=light] .token.boolean,html[data-theme=light] .token.constant,html[data-theme=light] .token.number,html[data-theme=light] .token.atrule{color:#b76b01}html[data-theme=light] .token.keyword{color:#a626a4}html[data-theme=light] .token.property,html[data-theme=light] .token.tag,html[data-theme=light] .token.symbol,html[data-theme=light] .token.deleted,html[data-theme=light] .token.important{color:#e45649}html[data-theme=light] .token.selector,html[data-theme=light] .token.string,html[data-theme=light] .token.char,html[data-theme=light] .token.builtin,html[data-theme=light] .token.inserted,html[data-theme=light] .token.regex,html[data-theme=light] .token.attr-value,html[data-theme=light] .token.attr-value>.token.punctuation{color:#50a14f}html[data-theme=light] .token.variable,html[data-theme=light] .token.operator,html[data-theme=light] .token.function{color:#4078f2}html[data-theme=light] .token.url{color:#0184bc}html[data-theme=light] .token.attr-value>.token.punctuation.attr-equals,html[data-theme=light] .token.special-attr>.token.attr-value>.token.value.css{color:#383a42}html[data-theme=light] .language-css .token.selector{color:#e45649}html[data-theme=light] .language-css .token.property{color:#383a42}html[data-theme=light] .language-css .token.function,html[data-theme=light] .language-css .token.url>.token.function{color:#0184bc}html[data-theme=light] .language-css .token.url>.token.string.url{color:#50a14f}html[data-theme=light] .language-css .token.important,html[data-theme=light] .language-css .token.atrule .token.rule,html[data-theme=light] .language-javascript .token.operator{color:#a626a4}html[data-theme=light] .language-javascript .token.template-string>.token.interpolation>.token.interpolation-punctuation.punctuation{color:#ca1243}html[data-theme=light] .language-json .token.operator{color:#383a42}html[data-theme=light] .language-json .token.null.keyword{color:#b76b01}html[data-theme=light] .language-markdown .token.url,html[data-theme=light] .language-markdown .token.url>.token.operator,html[data-theme=light] .language-markdown .token.url-reference.url>.token.string{color:#383a42}html[data-theme=light] .language-markdown .token.url>.token.content{color:#4078f2}html[data-theme=light] .language-markdown .token.url>.token.url,html[data-theme=light] .language-markdown .token.url-reference.url{color:#0184bc}html[data-theme=light] .language-markdown .token.blockquote.punctuation,html[data-theme=light] .language-markdown .token.hr.punctuation{color:#a0a1a7;font-style:italic}html[data-theme=light] .language-markdown .token.code-snippet{color:#50a14f}html[data-theme=light] .language-markdown .token.bold .token.content{color:#b76b01}html[data-theme=light] .language-markdown .token.italic .token.content{color:#a626a4}html[data-theme=light] .language-markdown .token.strike .token.content,html[data-theme=light] .language-markdown .token.strike .token.punctuation,html[data-theme=light] .language-markdown .token.list.punctuation,html[data-theme=light] .language-markdown .token.title.important>.token.punctuation{color:#e45649}html[data-theme=light] .token.bold{font-weight:700}html[data-theme=light] .token.comment,html[data-theme=light] .token.italic{font-style:italic}html[data-theme=light] .token.entity{cursor:help}html[data-theme=light] .token.namespace{opacity:.8}html[data-theme=dark] #app{--code-color: #abb2bf;--code-line-color: rgba(171, 178, 191, .67);--code-bg-color: #282c34;--code-border-color: #343e51;--code-highlight-line-color: #2f3542}html[data-theme=dark] code[class*=language-],html[data-theme=dark] pre[class*=language-]{text-shadow:0 1px rgba(0,0,0,.3);-moz-tab-size:2;-o-tab-size:2;tab-size:2}@media print{html[data-theme=dark] code[class*=language-],html[data-theme=dark] pre[class*=language-]{text-shadow:none}}html[data-theme=dark] code[class*=language-]::-moz-selection,html[data-theme=dark] code[class*=language-] ::-moz-selection,html[data-theme=dark] pre[class*=language-]::-moz-selection,html[data-theme=dark] pre[class*=language-] ::-moz-selection{background:#3e4451;color:inherit;text-shadow:none}html[data-theme=dark] code[class*=language-]::selection,html[data-theme=dark] code[class*=language-] ::selection,html[data-theme=dark] pre[class*=language-]::selection,html[data-theme=dark] pre[class*=language-] ::selection{background:#3e4451;color:inherit;text-shadow:none}html[data-theme=dark] .token.comment,html[data-theme=dark] .token.prolog,html[data-theme=dark] .token.cdata{color:#5c6370}html[data-theme=dark] .token.doctype,html[data-theme=dark] .token.punctuation,html[data-theme=dark] .token.entity{color:#abb2bf}html[data-theme=dark] .token.attr-name,html[data-theme=dark] .token.class-name,html[data-theme=dark] .token.boolean,html[data-theme=dark] .token.constant,html[data-theme=dark] .token.number,html[data-theme=dark] .token.atrule{color:#d19a66}html[data-theme=dark] .token.keyword{color:#c678dd}html[data-theme=dark] .token.property,html[data-theme=dark] .token.tag,html[data-theme=dark] .token.symbol,html[data-theme=dark] .token.deleted,html[data-theme=dark] .token.important{color:#e06c75}html[data-theme=dark] .token.selector,html[data-theme=dark] .token.string,html[data-theme=dark] .token.char,html[data-theme=dark] .token.builtin,html[data-theme=dark] .token.inserted,html[data-theme=dark] .token.regex,html[data-theme=dark] .token.attr-value,html[data-theme=dark] .token.attr-value>.token.punctuation{color:#98c379}html[data-theme=dark] .token.variable,html[data-theme=dark] .token.operator,html[data-theme=dark] .token.function{color:#61afef}html[data-theme=dark] .token.url{color:#56b6c2}html[data-theme=dark] .token.attr-value>.token.punctuation.attr-equals,html[data-theme=dark] .token.special-attr>.token.attr-value>.token.value.css{color:#abb2bf}html[data-theme=dark] .language-css .token.selector{color:#e06c75}html[data-theme=dark] .language-css .token.property{color:#abb2bf}html[data-theme=dark] .language-css .token.function,html[data-theme=dark] .language-css .token.url>.token.function{color:#56b6c2}html[data-theme=dark] .language-css .token.url>.token.string.url{color:#98c379}html[data-theme=dark] .language-css .token.important,html[data-theme=dark] .language-css .token.atrule .token.rule,html[data-theme=dark] .language-javascript .token.operator{color:#c678dd}html[data-theme=dark] .language-javascript .token.template-string>.token.interpolation>.token.interpolation-punctuation.punctuation{color:#be5046}html[data-theme=dark] .language-json .token.operator{color:#abb2bf}html[data-theme=dark] .language-json .token.null.keyword{color:#d19a66}html[data-theme=dark] .language-markdown .token.url,html[data-theme=dark] .language-markdown .token.url>.token.operator,html[data-theme=dark] .language-markdown .token.url-reference.url>.token.string{color:#abb2bf}html[data-theme=dark] .language-markdown .token.url>.token.content{color:#61afef}html[data-theme=dark] .language-markdown .token.url>.token.url,html[data-theme=dark] .language-markdown .token.url-reference.url{color:#56b6c2}html[data-theme=dark] .language-markdown .token.blockquote.punctuation,html[data-theme=dark] .language-markdown .token.hr.punctuation{color:#5c6370;font-style:italic}html[data-theme=dark] .language-markdown .token.code-snippet{color:#98c379}html[data-theme=dark] .language-markdown .token.bold .token.content{color:#d19a66}html[data-theme=dark] .language-markdown .token.italic .token.content{color:#c678dd}html[data-theme=dark] .language-markdown .token.strike .token.content,html[data-theme=dark] .language-markdown .token.strike .token.punctuation,html[data-theme=dark] .language-markdown .token.list.punctuation,html[data-theme=dark] .language-markdown .token.title.important>.token.punctuation{color:#e06c75}html[data-theme=dark] .token.bold{font-weight:700}html[data-theme=dark] .token.comment,html[data-theme=dark] .token.italic{font-style:italic}html[data-theme=dark] .token.entity{cursor:help}html[data-theme=dark] .token.namespace{opacity:.8}.sr-only{position:absolute;overflow:hidden;clip:rect(0,0,0,0);width:1px;height:1px;margin:-1px;padding:0;border-width:0;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;user-select:none}@media print{.theme-hope-content{margin:0!important;-webkit-padding-start:0!important;padding-inline-start:0!important;-webkit-padding-end:0!important;padding-inline-end:0!important}}.theme-hope-content.custom{margin:0;padding:0}.theme-hope-content:not(.custom){max-width:var(--content-width, 740px);margin:0 auto;padding:2rem 2.5rem;padding-top:0}@media (max-width: 959px){.theme-hope-content:not(.custom){padding:1.5rem}}@media (max-width: 419px){.theme-hope-content:not(.custom){padding:1rem 1.5rem}}@media print{.theme-hope-content:not(.custom){max-width:unset}}.theme-hope-content:not(.custom)>h1,.theme-hope-content:not(.custom)>h2,.theme-hope-content:not(.custom)>h3,.theme-hope-content:not(.custom)>h4,.theme-hope-content:not(.custom)>h5,.theme-hope-content:not(.custom)>h6{margin-top:calc(.5rem - var(--navbar-height));margin-bottom:.5rem;padding-top:calc(1rem + var(--navbar-height));outline:none}.theme-container.no-navbar .theme-hope-content:not(.custom)>h1,.theme-container.no-navbar .theme-hope-content:not(.custom)>h2,.theme-container.no-navbar .theme-hope-content:not(.custom)>h3,.theme-container.no-navbar .theme-hope-content:not(.custom)>h4,.theme-container.no-navbar .theme-hope-content:not(.custom)>h5,.theme-container.no-navbar .theme-hope-content:not(.custom)>h6{margin-top:1.5rem;padding-top:0}.theme-hope-content:not(.custom)>p,.theme-hope-content:not(.custom)>ul p,.theme-hope-content:not(.custom)>ol p{text-align:justify;overflow-wrap:break-word;-webkit-hyphens:auto;hyphens:auto}@media (max-width: 419px){.theme-hope-content:not(.custom)>p,.theme-hope-content:not(.custom)>ul p,.theme-hope-content:not(.custom)>ol p{text-align:start}}@media print{.theme-hope-content:not(.custom)>p,.theme-hope-content:not(.custom)>ul p,.theme-hope-content:not(.custom)>ol p{text-align:start}}.theme-hope-content a:hover{text-decoration:underline}.theme-hope-content img{max-width:100%}@media (min-width: 1280px){.chart-wrapper::-webkit-scrollbar,.flowchart-wrapper::-webkit-scrollbar,.mermaid-wrapper::-webkit-scrollbar{width:8px;height:8px}.chart-wrapper::-webkit-scrollbar-track-piece,.flowchart-wrapper::-webkit-scrollbar-track-piece,.mermaid-wrapper::-webkit-scrollbar-track-piece{border-radius:8px;background:rgba(0,0,0,.1)}}html[dir=rtl] a.header-anchor{float:right}#docsearch-container{min-width:145.7px!important}@media (max-width: 959px){#docsearch-container{min-width:36px!important}#docsearch-container .DocSearch-Button-Keys{display:none}}.DocSearch.DocSearch-Button{margin-left:0}.DocSearch .DocSearch-Button-Placeholder{display:inline-block;padding:4px 12px 4px 6px;font-size:14px}@media (max-width: 719px){.DocSearch .DocSearch-Button-Placeholder{display:none}}.DocSearch .DocSearch-Search-Icon{width:1.25em;height:1.25em}.DocSearch .DocSearch-Button-Key{background:var(--bg-color);box-shadow:none}@media (prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track-piece{border-radius:6px;background:rgba(0,0,0,.1)}::-webkit-scrollbar-thumb{border-radius:6px;background:var(--theme-color)}::-webkit-scrollbar-thumb:active{background:var(--theme-color-light)}@media (max-width: 719px){.hide-in-mobile{display:none!important}}@media (max-width: 959px){.hide-in-pad{display:none!important}}@keyframes shake{0%,to{transform:translate(0)}10%{transform:translate(-9px)}20%{transform:translate(8px)}30%{transform:translate(-7px)}40%{transform:translate(6px)}50%{transform:translate(-5px)}60%{transform:translate(4px)}70%{transform:translate(-3px)}80%{transform:translate(2px)}90%{transform:translate(-1px)}}.password-layer{display:flex;flex-direction:column;align-items:center;justify-content:center;height:calc(80vh - var(--navbar-height));margin-top:var(--navbar-height);text-align:center}.password-layer.expand{margin-top:0}.password-modal{width:calc(100% - 8rem);max-width:420px;margin:2rem;padding:2rem;border-radius:1.5rem;box-shadow:2px 2px 10px 6px var(--card-shadow);transition:box-shadow var(--color-transition)}@media (max-width: 719px){.password-modal{width:calc(100% - 5rem);padding:1.5rem}}@media (max-width: 419px){.password-modal{width:calc(100% - 3rem);box-shadow:none}}.password-modal .hint{margin-bottom:20px;font-weight:600;font-size:1.5rem;line-height:2}.password-modal .hint.tried{color:red;animation-name:shake;animation-duration:.5s;animation-timing-function:ease-out;animation-fill-mode:both}.password-modal .hint svg{width:1.25em;height:1.25em}.password-modal .password input{width:calc(100% - 3rem);padding:0 1.5rem;border:2px solid var(--theme-color);border-radius:.5rem;background:var(--bg-color)!important;color:var(--black)!important;outline:none;font-size:1.25rem;line-height:2;transition:background var(--color-transition),color var(--color-transition)}.password-modal .remember-password{margin-top:.5rem;color:var(--dark-grey);font-size:14px;text-align:start}.password-modal .remember-password input[type=checkbox]{position:relative;vertical-align:text-bottom;width:0;-webkit-margin-end:18px;margin-inline-end:18px;cursor:pointer}.password-modal .remember-password input[type=checkbox]:after{content:" ";position:absolute;top:0;display:inline-block;box-sizing:border-box;width:14px;height:14px;-webkit-padding-start:0;padding-inline-start:0;border:1px solid #ddd;border-radius:50%;background:#fff;text-align:center;visibility:visible;transition:background var(--color-transition),border-color var(--color-transition)}html[data-theme=dark] .password-modal .remember-password input[type=checkbox]:after{border-color:#666;background:#333}.password-modal .remember-password input[type=checkbox]:checked:after{content:"";border-color:var(--theme-color);background:var(--theme-color)}html[data-theme=dark] .password-modal .remember-password input[type=checkbox]:checked:after{border-color:var(--theme-color);background:var(--theme-color)}.password-modal .remember-password input[type=checkbox]:checked:before{content:"";position:absolute;top:2px;left:5px;z-index:1;width:2px;height:6px;border:solid var(--white);border-width:0 2px 2px 0;transform:rotate(45deg)}html[dir=rtl] .password-modal .remember-password input[type=checkbox]:checked:before{right:unset;left:5px}.password-modal button.submit{background:transparent;cursor:pointer;width:70px;margin-top:1.5rem;border-width:0;border-radius:.5rem;background:var(--theme-color);color:var(--bg-color);outline:none;font-size:1.2rem;line-height:2;transition:color var(--color-transition)}.password-modal button.submit:hover{background:var(--theme-color-light)}.red-div{color:red}/*! @docsearch/css 3.3.3 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:none}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;position:relative;padding:0 0 2px;border:0;top:-1px;width:20px}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:none;padding:0 0 0 8px;width:80%}.DocSearch-Input::-moz-placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:transparent}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:rgba(0,0,0,.2);transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:rgba(0,0,0,.2);transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"\bb "}.DocSearch-Prefill{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:none;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:2px;box-shadow:var(--docsearch-key-shadow);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;color:var(--docsearch-muted-color);border:0;width:20px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh, 1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:none;overflow:hidden;padding:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@media (min-width: 751px){#docsearch-container{min-width:171.36px}}@media (max-width: 750px){.DocSearch-Container{position:fixed}#docsearch-container{min-width:52px}}@media print{#docsearch-container{display:none}} diff --git a/assets/style-e9220a04.js b/assets/style-e9220a04.js new file mode 100644 index 00000000..c9305480 --- /dev/null +++ b/assets/style-e9220a04.js @@ -0,0 +1 @@ +const t="";export{t as default}; diff --git a/assets/styles.html-18ac6f01.js b/assets/styles.html-18ac6f01.js new file mode 100644 index 00000000..d966adef --- /dev/null +++ b/assets/styles.html-18ac6f01.js @@ -0,0 +1,4 @@ +import{_ as c,W as r,X as d,Y as a,$ as s,a0 as e,a1 as o,D as n}from"./framework-46b0e263.js";const i={},p=s("h1",{id:"样式",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#样式","aria-hidden":"true"},"#"),e(" 样式")],-1),u={href:"https://sass-lang.com/",target:"_blank",rel:"noopener noreferrer"},m=o(` Details:
Languages of shiki.
This option will be forwarded to
getHighlighter()
method of shiki.If no languages are provided, shiki will load all available languages automatically.
用户可以通过 palette 文件 来自定义样式变量,还可以通过 style 文件 来添加额外的样式。
# Palette 文件
Palette 文件的路径是
.vuepress/styles/palette.scss
。你可以利用它来覆盖默认主题的预定义 SASS 变量。
点击查看 SASS 变量
File not found
# Style 文件
Style 文件的路径是
.vuepress/styles/index.scss
。你可以在这里添加额外的样式,或者覆盖默认样式:
:root { + scroll-behavior: smooth; +} +
你也可以利用它来覆盖默认主题的预定义 CSS 变量。
点击查看 CSS 变量
File not found
`,12);function h(v,_){const t=n("NpmBadge"),l=n("ExternalLinkIcon");return r(),d("div",null,[p,a(t,{package:"@vuepress/theme-default"}),s("p",null,[e("默认主题使用 "),s("a",u,[e("SASS"),a(l)]),e(" 作为 CSS 预处理器。")]),m])}const S=c(i,[["render",h],["__file","styles.html.vue"]]);export{S as default}; diff --git a/assets/styles.html-2c440e5c.js b/assets/styles.html-2c440e5c.js new file mode 100644 index 00000000..4a88b646 --- /dev/null +++ b/assets/styles.html-2c440e5c.js @@ -0,0 +1,4 @@ +import{_ as i,W as r,X as d,Y as a,$ as s,a0 as e,a1 as o,D as t}from"./framework-46b0e263.js";const c={},p=s("h1",{id:"styles",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#styles","aria-hidden":"true"},"#"),e(" Styles")],-1),u={href:"https://sass-lang.com/",target:"_blank",rel:"noopener noreferrer"},h=o(`点击查看暗黑模式 CSS 变量
File not found
Users can customize style variables via a palette file, and add extra styles via a style file.
# Palette File
The path of the palette file is
.vuepress/styles/palette.scss
.You can make use of it to override predefined SASS variables of the default theme.
Click to expand SASS variables
File not found
# Style File
The path of the style file is
.vuepress/styles/index.scss
.You can add extra styles here, or override the default styles:
:root { + scroll-behavior: smooth; +} +
You can also make use of it to override predefined CSS variables of the default theme.
Click to expand CSS variables
File not found
`,12);function m(f,v){const n=t("NpmBadge"),l=t("ExternalLinkIcon");return r(),d("div",null,[p,a(n,{package:"@vuepress/theme-default"}),s("p",null,[e("The default theme uses "),s("a",u,[e("SASS"),a(l)]),e(" as the CSS pre-processor.")]),h])}const _=i(c,[["render",m],["__file","styles.html.vue"]]);export{_ as default}; diff --git a/assets/styles.html-cf9c349d.js b/assets/styles.html-cf9c349d.js new file mode 100644 index 00000000..ec6b439f --- /dev/null +++ b/assets/styles.html-cf9c349d.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-31e08608","path":"/reference/default-theme/styles.html","title":"Styles","lang":"en-US","frontmatter":{"icon":"fa6-solid:wand-magic-sparkles","description":"The default theme uses SASS (https://sass-lang.com/) as the CSS pre-processor. Users can customize style variables via a palette file (#palette-file), and add extra styles via a...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/default-theme/styles.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/default-theme/styles.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Styles"}],["meta",{"property":"og:description","content":"The default theme uses SASS (https://sass-lang.com/) as the CSS pre-processor. Users can customize style variables via a palette file (#palette-file), and add extra styles via a..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Styles\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Palette File","slug":"palette-file","link":"#palette-file","children":[]},{"level":2,"title":"Style File","slug":"style-file","link":"#style-file","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.57,"words":170},"filePathRelative":"reference/default-theme/styles.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/styles.html-f0854e57.js b/assets/styles.html-f0854e57.js new file mode 100644 index 00000000..5aa64d6b --- /dev/null +++ b/assets/styles.html-f0854e57.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2100bd79","path":"/zh/reference/default-theme/styles.html","title":"样式","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:wand-magic-sparkles","description":"默认主题使用 SASS (https://sass-lang.com/) 作为 CSS 预处理器。 用户可以通过 palette 文件 (#palette-文件) 来自定义样式变量,还可以通过 style 文件 (#style-文件) 来添加额外的样式。 Palette 文件 Palette 文件的路径是 .vuepress/styles/palett...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/default-theme/styles.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/default-theme/styles.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"样式"}],["meta",{"property":"og:description","content":"默认主题使用 SASS (https://sass-lang.com/) 作为 CSS 预处理器。 用户可以通过 palette 文件 (#palette-文件) 来自定义样式变量,还可以通过 style 文件 (#style-文件) 来添加额外的样式。 Palette 文件 Palette 文件的路径是 .vuepress/styles/palett..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"样式\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Palette 文件","slug":"palette-文件","link":"#palette-文件","children":[]},{"level":2,"title":"Style 文件","slug":"style-文件","link":"#style-文件","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.73,"words":219},"filePathRelative":"zh/reference/default-theme/styles.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/theme-api.html-089c0c83.js b/assets/theme-api.html-089c0c83.js new file mode 100644 index 00000000..956dc441 --- /dev/null +++ b/assets/theme-api.html-089c0c83.js @@ -0,0 +1,10 @@ +import{_ as o,W as p,X as u,Y as t,$ as e,a0 as n,Z as l,a1 as d,D as s}from"./framework-46b0e263.js";const c={},r=e("h1",{id:"theme-api",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#theme-api","aria-hidden":"true"},"#"),n(" Theme API")],-1),h=d(`Click to expand dark mode CSS variables
File not found
# Basic Options
# name
Type:
string
Details:
Name of the theme.
It should follow the naming convention, and ensure consistency with the package name when publishing to NPM:
- Non-scoped:
vuepress-theme-foo
- Scoped:
@org/vuepress-theme-foo
# multiple
Details:
A theme should never be used multiple times, so this option is not supported in theme API.
# Theme Specific Options
# extends
Type:
Theme
Details:
The theme to inherit.
All of the Theme API of the parent theme will be inherited, but the child theme will not override the parent theme directly. Theme specific options will override according to following rules:
- plugins: When a same plugin is used in both child and parent theme, if the plugin does not support to be used multiple times, only the one used in the child theme will take effect.
- templateBuild / templateDev: Child theme templates will override parent theme templates.
Multi-level inheritance is supported, i.e. theme B could be extended from theme A, and then theme C could be extended from theme B. In other words, a theme could have a parent theme, a grandparent theme and so on.
Example:
import { defaultTheme } from "@vuepress/theme-default"; +import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + // inherit the default theme + extends: defaultTheme(), +}; +
# plugins
`,10),m=e("li",null,[e("p",null,[n("Type: "),e("code",null,"(Plugin | Plugin[])[]")])],-1),f=e("li",null,[e("p",null,"Details:"),e("p",null,"Plugins to use in the theme.")],-1),_=e("p",null,"Also see:",-1),v=e("h3",{id:"templatebuild",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#templatebuild","aria-hidden":"true"},"#"),n(" templateBuild")],-1),k=e("li",null,[e("p",null,[n("Type: "),e("code",null,"string")])],-1),g=e("p",null,"Details:",-1),b=e("p",null,"Specify the HTML template for build.",-1),w=e("p",null,"Also see:",-1),x=e("h3",{id:"templatedev",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#templatedev","aria-hidden":"true"},"#"),n(" templateDev")],-1),y=e("li",null,[e("p",null,[n("Type: "),e("code",null,"string")])],-1),T=e("p",null,"Details:",-1),D=e("p",null,"Specify the HTML template for dev.",-1),A=e("p",null,"Also see:",-1);function B(P,I){const i=s("NpmBadge"),a=s("RouterLink");return p(),u("div",null,[r,t(i,{package:"@vuepress/core"}),e("p",null,[n("VuePress theme also works as a plugin, so Theme API can accept all the options of "),t(a,{to:"/reference/plugin-api.html"},{default:l(()=>[n("Plugin API")]),_:1}),n(" with following differences.")]),h,e("ul",null,[m,f,e("li",null,[_,e("ul",null,[e("li",null,[t(a,{to:"/reference/config.html#plugins"},{default:l(()=>[n("Config > plugins")]),_:1})])])])]),v,e("ul",null,[k,e("li",null,[g,b,e("p",null,[n("It would override the default value of "),t(a,{to:"/reference/config.html#templatebuild"},{default:l(()=>[n("templateBuild")]),_:1}),n(", but could be overridden by user config.")])]),e("li",null,[w,e("ul",null,[e("li",null,[t(a,{to:"/reference/config.html#templatebuild"},{default:l(()=>[n("Config > templateBuild")]),_:1})])])])]),x,e("ul",null,[y,e("li",null,[T,D,e("p",null,[n("It would override the default value of "),t(a,{to:"/reference/config.html#templatedev"},{default:l(()=>[n("templateDev")]),_:1}),n(", but could be overridden by user config.")])]),e("li",null,[A,e("ul",null,[e("li",null,[t(a,{to:"/reference/config.html#templatedev"},{default:l(()=>[n("Config > templateDev")]),_:1})])])])])])}const C=o(c,[["render",B],["__file","theme-api.html.vue"]]);export{C as default}; diff --git a/assets/theme-api.html-a169223d.js b/assets/theme-api.html-a169223d.js new file mode 100644 index 00000000..8ed84f22 --- /dev/null +++ b/assets/theme-api.html-a169223d.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6b76c1c0","path":"/reference/theme-api.html","title":"Theme API","lang":"en-US","frontmatter":{"icon":"fa6-solid:palette","description":"VuePress theme also works as a plugin, so Theme API can accept all the options of Plugin API (./plugin-api.md) with following differences. Basic Options name Type: string; Detai...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/theme-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/theme-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Theme API"}],["meta",{"property":"og:description","content":"VuePress theme also works as a plugin, so Theme API can accept all the options of Plugin API (./plugin-api.md) with following differences. Basic Options name Type: string; Detai..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Theme API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Basic Options","slug":"basic-options","link":"#basic-options","children":[{"level":3,"title":"name","slug":"name","link":"#name","children":[]},{"level":3,"title":"multiple","slug":"multiple","link":"#multiple","children":[]}]},{"level":2,"title":"Theme Specific Options","slug":"theme-specific-options","link":"#theme-specific-options","children":[{"level":3,"title":"extends","slug":"extends","link":"#extends","children":[]},{"level":3,"title":"plugins","slug":"plugins","link":"#plugins","children":[]},{"level":3,"title":"templateBuild","slug":"templatebuild","link":"#templatebuild","children":[]},{"level":3,"title":"templateDev","slug":"templatedev","link":"#templatedev","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.13,"words":338},"filePathRelative":"reference/theme-api.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/theme-api.html-b6aae4d8.js b/assets/theme-api.html-b6aae4d8.js new file mode 100644 index 00000000..727b201c --- /dev/null +++ b/assets/theme-api.html-b6aae4d8.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-49a27222","path":"/zh/reference/theme-api.html","title":"主题 API","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:palette","description":"VuePress 主题同样是一个插件,因此主题 API 可以接收 插件 API (./plugin-api.md) 的所有选项,但存在以下差别: 基础配置项 name 类型: string; 详情:; 主题的名称。 它应遵从如下命名约定,并且在发布到 NPM 时应确保和包名保持一致: 非 Scoped: vuepress-theme-foo; Scop...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/theme-api.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/theme-api.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"主题 API"}],["meta",{"property":"og:description","content":"VuePress 主题同样是一个插件,因此主题 API 可以接收 插件 API (./plugin-api.md) 的所有选项,但存在以下差别: 基础配置项 name 类型: string; 详情:; 主题的名称。 它应遵从如下命名约定,并且在发布到 NPM 时应确保和包名保持一致: 非 Scoped: vuepress-theme-foo; Scop..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"主题 API\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"基础配置项","slug":"基础配置项","link":"#基础配置项","children":[{"level":3,"title":"name","slug":"name","link":"#name","children":[]},{"level":3,"title":"multiple","slug":"multiple","link":"#multiple","children":[]}]},{"level":2,"title":"主题特定配置项","slug":"主题特定配置项","link":"#主题特定配置项","children":[{"level":3,"title":"extends","slug":"extends","link":"#extends","children":[]},{"level":3,"title":"plugins","slug":"plugins","link":"#plugins","children":[]},{"level":3,"title":"templateBuild","slug":"templatebuild","link":"#templatebuild","children":[]},{"level":3,"title":"templateDev","slug":"templatedev","link":"#templatedev","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.56,"words":468},"filePathRelative":"zh/reference/theme-api.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/theme-api.html-c8d9fb01.js b/assets/theme-api.html-c8d9fb01.js new file mode 100644 index 00000000..6212a747 --- /dev/null +++ b/assets/theme-api.html-c8d9fb01.js @@ -0,0 +1,10 @@ +import{_ as p,W as o,X as u,Y as a,$ as e,a0 as n,Z as l,a1 as c,D as t}from"./framework-46b0e263.js";const d={},r=e("h1",{id:"主题-api",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#主题-api","aria-hidden":"true"},"#"),n(" 主题 API")],-1),h=c(`# 基础配置项
# name
类型:
string
详情:
主题的名称。
它应遵从如下命名约定,并且在发布到 NPM 时应确保和包名保持一致:
- 非 Scoped:
vuepress-theme-foo
- Scoped:
@org/vuepress-theme-foo
# multiple
详情:
主题永远不能被多次使用,因此主题 API 不支持该配置项。
# 主题特定配置项
# extends
类型:
Theme
详情:
要继承的主题。
父主题的所有主题 API 都会被继承,但是子主题不会直接覆盖父主题。主题特定的配置项会根据以下规则进行覆盖:
- plugins: 当同一个插件在子主题和父主题中都被使用时,如果该插件不支持被多次使用,那么只有在子主题中使用的插件会生效。
- templateBuild / templateDev: 子主题的模板会覆盖父主题的模板。
支持多级继承,即主题 B 可以继承主题 A ,然后主题 C 可以继承主题 B 。换句话说,一个主题可以有一个父主题、一个祖父主题等等。
示例:
import { defaultTheme } from "@vuepress/theme-default"; +import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +export default { + // 继承默认主题 + extends: defaultTheme(), +}; +
# plugins
`,10),m=e("li",null,[e("p",null,[n("类型: "),e("code",null,"(Plugin | Plugin[])[]")])],-1),_=e("li",null,[e("p",null,"详情:"),e("p",null,"主题中要使用的插件。")],-1),k=e("p",null,"参考:",-1),f=e("h3",{id:"templatebuild",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#templatebuild","aria-hidden":"true"},"#"),n(" templateBuild")],-1),v=e("li",null,[e("p",null,[n("类型: "),e("code",null,"string")])],-1),g=e("p",null,"详情:",-1),b=e("p",null,"指定构建时使用的 HTML 模板。",-1),x=e("p",null,"参考:",-1),y=e("h3",{id:"templatedev",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#templatedev","aria-hidden":"true"},"#"),n(" templateDev")],-1),B=e("li",null,[e("p",null,[n("类型: "),e("code",null,"string")])],-1),w=e("p",null,"详情:",-1),P=e("p",null,"指定开发时使用的 HTML 模板。",-1),A=e("p",null,"参考:",-1);function D(N,z){const i=t("NpmBadge"),s=t("RouterLink");return o(),u("div",null,[r,a(i,{package:"@vuepress/core"}),e("p",null,[n("VuePress 主题同样是一个插件,因此主题 API 可以接收 "),a(s,{to:"/zh/reference/plugin-api.html"},{default:l(()=>[n("插件 API")]),_:1}),n(" 的所有选项,但存在以下差别:")]),h,e("ul",null,[m,_,e("li",null,[k,e("ul",null,[e("li",null,[a(s,{to:"/zh/reference/config.html#plugins"},{default:l(()=>[n("配置 > plugins")]),_:1})])])])]),f,e("ul",null,[v,e("li",null,[g,b,e("p",null,[n("它会覆盖 "),a(s,{to:"/zh/reference/config.html#templatebuild"},{default:l(()=>[n("templateBuild")]),_:1}),n(" 的默认值,但是也会被用户配置覆盖。")])]),e("li",null,[x,e("ul",null,[e("li",null,[a(s,{to:"/zh/reference/config.html#templatebuild"},{default:l(()=>[n("配置 > templateBuild")]),_:1})])])])]),y,e("ul",null,[B,e("li",null,[w,P,e("p",null,[n("它会覆盖 "),a(s,{to:"/zh/reference/config.html#templatedev"},{default:l(()=>[n("templateDev")]),_:1}),n(" 的默认值,但是也会被用户配置覆盖。")])]),e("li",null,[A,e("ul",null,[e("li",null,[a(s,{to:"/zh/reference/config.html#templatedev"},{default:l(()=>[n("配置 > templateDev")]),_:1})])])])])])}const I=p(d,[["render",D],["__file","theme-api.html.vue"]]);export{I as default}; diff --git a/assets/theme-data.html-03afc4d1.js b/assets/theme-data.html-03afc4d1.js new file mode 100644 index 00000000..32f0246d --- /dev/null +++ b/assets/theme-data.html-03afc4d1.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-411f140a","path":"/zh/reference/plugin/theme-data.html","title":"theme-data","lang":"zh-CN","frontmatter":{"description":"为你的主题提供客户端数据,包含 VuePress 的 多语言支持 (../../guide/i18n.md) 。 该插件主要用于开发主题,并且已经集成到默认主题中。大部分情况下你不需要直接使用它。 对于主题作者,该插件可以提供与 VuePress 及默认主题相同的多语言支持机制。但是如果你的主题不需要提供多语言支持,或者你想用你自己的方式来实现多语言支...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/theme-data.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/theme-data.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"theme-data"}],["meta",{"property":"og:description","content":"为你的主题提供客户端数据,包含 VuePress 的 多语言支持 (../../guide/i18n.md) 。 该插件主要用于开发主题,并且已经集成到默认主题中。大部分情况下你不需要直接使用它。 对于主题作者,该插件可以提供与 VuePress 及默认主题相同的多语言支持机制。但是如果你的主题不需要提供多语言支持,或者你想用你自己的方式来实现多语言支..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"theme-data\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"themeData","slug":"themedata","link":"#themedata","children":[]}]},{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"useThemeData","slug":"usethemedata","link":"#usethemedata","children":[]},{"level":3,"title":"useThemeLocaleData","slug":"usethemelocaledata","link":"#usethemelocaledata","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.49,"words":447},"filePathRelative":"zh/reference/plugin/theme-data.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/theme-data.html-2029f336.js b/assets/theme-data.html-2029f336.js new file mode 100644 index 00000000..667c3453 --- /dev/null +++ b/assets/theme-data.html-2029f336.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-18fd0fcc","path":"/reference/plugin/theme-data.html","title":"theme-data","lang":"en-US","frontmatter":{"description":"Provide client data for your theme, with VuePress i18n (../../guide/i18n.md) support. This plugin is mainly used to develop themes, and has been integrated into the default them...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/theme-data.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/theme-data.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"theme-data"}],["meta",{"property":"og:description","content":"Provide client data for your theme, with VuePress i18n (../../guide/i18n.md) support. This plugin is mainly used to develop themes, and has been integrated into the default them..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"theme-data\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"themeData","slug":"themedata","link":"#themedata","children":[]}]},{"level":2,"title":"Composition API","slug":"composition-api","link":"#composition-api","children":[{"level":3,"title":"useThemeData","slug":"usethemedata","link":"#usethemedata","children":[]},{"level":3,"title":"useThemeLocaleData","slug":"usethemelocaledata","link":"#usethemelocaledata","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.06,"words":319},"filePathRelative":"reference/plugin/theme-data.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/theme-data.html-71846647.js b/assets/theme-data.html-71846647.js new file mode 100644 index 00000000..3d0d5cf9 --- /dev/null +++ b/assets/theme-data.html-71846647.js @@ -0,0 +1,51 @@ +import{_ as o,W as i,X as c,Y as s,$ as a,a0 as n,Z as l,a1 as u,D as e}from"./framework-46b0e263.js";const r={},d=a("h1",{id:"theme-data",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#theme-data","aria-hidden":"true"},"#"),n(" theme-data")],-1),k=u(`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.
For theme authors, this plugin will help you to use the same i18n mechanism as VuePress and the default theme. But if you don't want to provide i18n support, or you want to implement in your own way, you don't need this plugin.
# Usage
npm i -D @vuepress/plugin-theme-data@next +
import { themeDataPlugin } from "@vuepress/plugin-theme-data"; + +export default { + plugins: [ + themeDataPlugin({ + // options + }), + ], +}; +
# Options
# themeData
Type:
ThemeData
Default:
{}
Details:
The theme data object that you want to use in client side.
You can provide theme data in Node side via this option, and use it in client side via useThemeData and useThemeLocaleData.
Example:
export default { + plugins: [ + themeDataPlugin({ + themeData: { + foo: "foo", + locales: { + "/zh/": { + foo: "zh-foo", + }, + }, + }, + }), + ], +}; +
Note
The theme data object will be processed by
JSON.stringify()
before forwarding to client side, so you should ensure that you are providing a JSON-friendly object.# Composition API
# useThemeData
Details:
Returns the theme data ref object.
The value is provided by themeData option.
Example:
import { useThemeData } from "@vuepress/plugin-theme-data/client"; +import type { ThemeData } from "@vuepress/plugin-theme-data/client"; + +type MyThemeData = ThemeData<{ + foo: string; +}>; + +export default { + setup() { + const themeData = useThemeData<MyThemeData>(); + console.log(themeData.value); + }, +}; +
# useThemeLocaleData
Details:
Returns the theme data ref object in current locale.
The properties of current locale has been merged into the root-level properties.
Example:
`,17);function m(v,h){const t=e("NpmBadge"),p=e("RouterLink");return i(),c("div",null,[d,s(t,{package:"@vuepress/plugin-theme-data"}),a("p",null,[n("Provide client data for your theme, with VuePress "),s(p,{to:"/guide/i18n.html"},{default:l(()=>[n("i18n")]),_:1}),n(" support.")]),k])}const g=o(r,[["render",m],["__file","theme-data.html.vue"]]);export{g as default}; diff --git a/assets/theme-data.html-a62c4182.js b/assets/theme-data.html-a62c4182.js new file mode 100644 index 00000000..b240641c --- /dev/null +++ b/assets/theme-data.html-a62c4182.js @@ -0,0 +1,51 @@ +import{_ as o,W as c,X as i,Y as s,$ as a,a0 as n,Z as l,a1 as u,D as e}from"./framework-46b0e263.js";const r={},d=a("h1",{id:"theme-data",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#theme-data","aria-hidden":"true"},"#"),n(" theme-data")],-1),k=u(`import { useThemeLocaleData } from "@vuepress/plugin-theme-data/client"; +import type { ThemeData } from "@vuepress/plugin-theme-data/client"; + +type MyThemeData = ThemeData<{ + foo: string; +}>; + +export default { + setup() { + const themeLocaleData = useThemeLocaleData<MyThemeData>(); + console.log(themeLocaleData.value); + }, +}; +
该插件主要用于开发主题,并且已经集成到默认主题中。大部分情况下你不需要直接使用它。
对于主题作者,该插件可以提供与 VuePress 及默认主题相同的多语言支持机制。但是如果你的主题不需要提供多语言支持,或者你想用你自己的方式来实现多语言支持,那么你不需要使用该插件。
# 使用方法
npm i -D @vuepress/plugin-theme-data@next +
import { themeDataPlugin } from "@vuepress/plugin-theme-data"; + +export default { + plugins: [ + themeDataPlugin({ + // 配置项 + }), + ], +}; +
# 配置项
# themeData
类型:
ThemeData
默认值:
{}
详情:
你希望在 Client 端中使用的主题数据对象。
你可以通过该配置项,在 Node 端提供主题数据,然后在客户端通过 useThemeData 和 useThemeLocaleData 来使用主题数据。
示例:
export default { + plugins: [ + themeDataPlugin({ + themeData: { + foo: "foo", + locales: { + "/zh/": { + foo: "zh-foo", + }, + }, + }, + }), + ], +}; +
注意
主题数据对象在传递到客户端之前,会使用
JSON.stringify()
进行处理,因此你需要保证你提供的是一个可以被 JSON 序列化的对象。# Composition API
# useThemeData
详情:
返回主题数据的 Ref 对象。
数据是通过 themeData 配置项提供的。
示例:
import { useThemeData } from "@vuepress/plugin-theme-data/client"; +import type { ThemeData } from "@vuepress/plugin-theme-data/client"; + +type MyThemeData = ThemeData<{ + foo: string; +}>; + +export default { + setup() { + const themeData = useThemeData<MyThemeData>(); + console.log(themeData.value); + }, +}; +
# useThemeLocaleData
详情:
返回当前 locale 下主题数据的 Ref 对象。
当前 locale 中的字段已被合并到顶层字段中。
示例:
`,17);function m(v,h){const t=e("NpmBadge"),p=e("RouterLink");return c(),i("div",null,[d,s(t,{package:"@vuepress/plugin-theme-data"}),a("p",null,[n("为你的主题提供客户端数据,包含 VuePress 的 "),s(p,{to:"/zh/guide/i18n.html"},{default:l(()=>[n("多语言支持")]),_:1}),n(" 。")]),k])}const g=o(r,[["render",m],["__file","theme-data.html.vue"]]);export{g as default}; diff --git a/assets/theme.html-18dd2f4e.js b/assets/theme.html-18dd2f4e.js new file mode 100644 index 00000000..a716c314 --- /dev/null +++ b/assets/theme.html-18dd2f4e.js @@ -0,0 +1,58 @@ +import{_ as i,W as l,X as u,$ as s,a0 as n,Y as a,Z as t,a1 as o,D as p}from"./framework-46b0e263.js";const d={},r=s("h1",{id:"writing-a-theme",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#writing-a-theme","aria-hidden":"true"},"#"),n(" Writing a Theme")],-1),k={class:"hint-container tip"},m=s("p",{class:"hint-container-title"},"Tips",-1),v=s("h2",{id:"create-a-theme",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#create-a-theme","aria-hidden":"true"},"#"),n(" Create a Theme")],-1),h=s("em",null,"Theme Object",-1),g=s("em",null,"Theme Function",-1),b=o(`import { useThemeLocaleData } from "@vuepress/plugin-theme-data/client"; +import type { ThemeData } from "@vuepress/plugin-theme-data/client"; + +type MyThemeData = ThemeData<{ + foo: string; +}>; + +export default { + setup() { + const themeLocaleData = useThemeLocaleData<MyThemeData>(); + console.log(themeLocaleData.value); + }, +}; +
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +const fooTheme = (options) => { + // returns a theme object + return { + name: "vuepress-theme-foo", + + // path to the client config of your theme + clientConfigFile: path.resolve(__dirname, "client.js"), + + // set custom dev / build template + // if the template is not specified, the default template from \`@vuepress/client\` will be used + templateBuild: path.resolve(__dirname, "templates/build.html"), + templateDev: path.resolve(__dirname, "templates/dev.html"), + + // use plugins + plugins: [ + // ... + ], + + // other plugin APIs are also available + }; +}; + +const barTheme = (options) => { + // returns a theme function + return (app) => { + return { + name: "vuepress-theme-bar", + // ... + }; + }; +}; +
Then, create theme's client config file
client.js
:import { defineClientConfig } from "@vuepress/client"; +import Layout from "./layouts/Layout.vue"; +import NotFound from "./layouts/NotFound.vue"; + +export default defineClientConfig({ + layouts: { + Layout, + NotFound, + }, +}); +
The
`,4),f=s("code",null,"Layout",-1),_=o(`layouts
field declares the layouts provided by your theme. A theme must provide at least two layouts:Layout
andNotFound
. The former is to provide default layout for common pages, while the latter is to provide layout for 404-not-found page.<template> + <div> + <Content /> + </div> +</template> +
The
NotFound
layout will be used for the404.html
page:`,3),y=s("h2",{id:"publish-to-npm",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#publish-to-npm","aria-hidden":"true"},"#"),n(" Publish to NPM")],-1),w={href:"https://docs.npmjs.com/cli/v8/configuring-npm/package-json",target:"_blank",rel:"noopener noreferrer"},q=o(`<template> + <div>404 Not Found</div> +</template> +
`,1),x=s("code",null,"name",-1),T=s("code",null,"vuepress-theme-xxx",-1),N=s("code",null,"@org/vuepress-theme-xxx",-1),j=s("em",null,"Theme Object",-1),C=s("li",null,[n("Set "),s("code",null,"keywords"),n(" to include "),s("code",null,"vuepress-theme"),n(", so that users can search your theme on NPM.")],-1);function L(F,P){const e=p("RouterLink"),c=p("ExternalLinkIcon");return l(),u("div",null,[r,s("div",k,[m,s("p",null,[n("Before reading this guide, you'd better learn the guide of "),a(e,{to:"/advanced/plugin.html"},{default:t(()=>[n("Writing a Plugin")]),_:1}),n(" first.")])]),v,s("p",null,[n("A VuePress theme is a special plugin, which should satisfy the "),a(e,{to:"/reference/theme-api.html"},{default:t(()=>[n("Theme API")]),_:1}),n(". Like plugins, a theme should also be a "),h,n(" or a "),g,n(", and could be wrapped with a function to receive options:")]),b,s("p",null,[n("The "),f,n(" layout should contain the "),a(e,{to:"/reference/components.html#content"},{default:t(()=>[n("Content")]),_:1}),n(" component to display the markdown content:")]),_,s("p",null,[n("You can provide more layouts, and users can change layout via "),a(e,{to:"/reference/frontmatter.html#layout"},{default:t(()=>[n("layout")]),_:1}),n(" frontmatter.")]),y,s("p",null,[n("Also, there are some conventions for theme in "),s("a",w,[n("package.json"),a(c)]),n(":")]),q,s("ul",null,[s("li",null,[n("Set "),x,n(" to follow the naming convention: "),T,n(" or "),N,n(", which should be consistent with the "),a(e,{to:"/reference/theme-api.html#name"},{default:t(()=>[n("name")]),_:1}),n(" field of the "),j,n(".")]),C])])}const B=i(d,[["render",L],["__file","theme.html.vue"]]);export{B as default}; diff --git a/assets/theme.html-2c740ba6.js b/assets/theme.html-2c740ba6.js new file mode 100644 index 00000000..b0be76ef --- /dev/null +++ b/assets/theme.html-2c740ba6.js @@ -0,0 +1,14 @@ +import{_ as p,W as i,X as l,$ as n,a0 as s,Y as e,Z as t,a1 as r,D as o}from"./framework-46b0e263.js";const u={},d=n("h1",{id:"主题",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#主题","aria-hidden":"true"},"#"),s(" 主题")],-1),h=n("p",null,"VuePress 主题为你提供了布局、样式和其他功能,帮助你专注于 Markdown 内容的写作。",-1),k=n("h2",{id:"默认主题",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#默认主题","aria-hidden":"true"},"#"),s(" 默认主题")],-1),m=n("p",null,"VuePress 有一个开箱即用的默认主题,正使用在你当前正在浏览的文档网站上。",-1),_=n("p",null,"如果你不指定要使用的主题,那么就会自动使用默认主题。",-1),v=r(`{ + "name": "vuepress-theme-foo", + "keywords": ["vuepress-theme"] +} +
`,1),f=n("p",null,"然而,你可能觉得默认主题不够出色,又或者你不想搭建一个文档网站,而是一个其他类型的网站,比如博客。此时,你可以尝试使用社区主题或者创建本地主题。",-1),b=n("h2",{id:"社区主题",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#社区主题","aria-hidden":"true"},"#"),s(" 社区主题")],-1),x={href:"https://www.npmjs.com/search?q=keywords:vuepress-theme",target:"_blank",rel:"noopener noreferrer"},g=n("h2",{id:"本地主题",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#本地主题","aria-hidden":"true"},"#"),s(" 本地主题")],-1);function w(q,y){const a=o("RouterLink"),c=o("ExternalLinkIcon");return i(),l("div",null,[d,h,k,m,_,n("p",null,[s("为了配置默认主题,你需要在你的配置文件中通过 "),e(a,{to:"/zh/reference/config.html#theme"},{default:t(()=>[s("theme")]),_:1}),s(" 配置项来使用它:")]),v,n("p",null,[s("默认主题为文档网站提供了基础且实用的功能,你可以前往 "),e(a,{to:"/zh/reference/default-theme/config.html"},{default:t(()=>[s("默认主题配置参考")]),_:1}),s(" 获取全部的配置列表。")]),f,b,n("p",null,[s("社区用户创建了很多主题,并将它们发布到了 "),n("a",x,[s("NPM"),e(c)]),s(" 上。查看主题本身的文档可以获取更详细的指引。")]),g,n("p",null,[s("如果你想要使用自己的自定义主题,但是又不想发布它,你可以创建一个本地主题。前往 "),e(a,{to:"/zh/advanced/theme.html"},{default:t(()=>[s("深入 > 开发主题")]),_:1}),s(" 学习如何开发你自己的主题。")])])}const N=p(u,[["render",w],["__file","theme.html.vue"]]);export{N as default}; diff --git a/assets/theme.html-3d462c1b.js b/assets/theme.html-3d462c1b.js new file mode 100644 index 00000000..3cd76efa --- /dev/null +++ b/assets/theme.html-3d462c1b.js @@ -0,0 +1,14 @@ +import{_ as c,W as u,X as l,$ as e,a0 as n,Y as t,Z as s,a1 as r,D as o}from"./framework-46b0e263.js";const p={},d=e("h1",{id:"theme",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#theme","aria-hidden":"true"},"#"),n(" Theme")],-1),h=e("p",null,"VuePress theme can provide layouts, styles and many other features for you, helping you to focus on writing Markdown content.",-1),m=e("h2",{id:"default-theme",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#default-theme","aria-hidden":"true"},"#"),n(" Default Theme")],-1),f=e("p",null,"VuePress has a default theme out of the box, which is applied to our documentation site you are currently browsing.",-1),k=e("p",null,"If you don't specify the theme to use, the default theme will be used automatically.",-1),v=r(`import { defaultTheme } from "vuepress"; + +export default { + theme: defaultTheme({ + // 默认主题配置 + navbar: [ + { + text: "首页", + link: "/", + }, + ], + }), +}; +
`,1),_=e("p",null,"However, you might think it is not good enough. Or, you want to build a different type of site, for example, a blog, instead of a documentation. Then, you can try to use a community theme or create a local theme.",-1),y=e("h2",{id:"community-theme",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#community-theme","aria-hidden":"true"},"#"),n(" Community Theme")],-1),b={href:"https://www.npmjs.com/search?q=keywords:vuepress-theme",target:"_blank",rel:"noopener noreferrer"},g=e("h2",{id:"local-theme",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#local-theme","aria-hidden":"true"},"#"),n(" Local Theme")],-1);function w(x,T){const a=o("RouterLink"),i=o("ExternalLinkIcon");return u(),l("div",null,[d,h,m,f,k,e("p",null,[n("To configure the default theme, you need to import and use it in your config file via the "),t(a,{to:"/reference/config.html#theme"},{default:s(()=>[n("theme")]),_:1}),n(" option:")]),v,e("p",null,[n("The default theme provides basic but useful features for documentation site, you can check out "),t(a,{to:"/reference/default-theme/config.html"},{default:s(()=>[n("Default Theme Config Reference")]),_:1}),n(" for a full list of config.")]),_,y,e("p",null,[n("Community users have created lots of theme and published them to "),e("a",b,[n("NPM"),t(i)]),n(". You should check the theme's own documentation for detailed guide.")]),g,e("p",null,[n("If you want to use your own custom theme but don't want to publish it, you can create a local theme. Refer to "),t(a,{to:"/advanced/theme.html"},{default:s(()=>[n("Advanced > Writing a Theme")]),_:1}),n(" for how to write your own theme.")])])}const V=c(p,[["render",w],["__file","theme.html.vue"]]);export{V as default}; diff --git a/assets/theme.html-6daccb0c.js b/assets/theme.html-6daccb0c.js new file mode 100644 index 00000000..02c145a3 --- /dev/null +++ b/assets/theme.html-6daccb0c.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2efcb26a","path":"/zh/guide/theme.html","title":"主题","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:palette","description":"VuePress 主题为你提供了布局、样式和其他功能,帮助你专注于 Markdown 内容的写作。 默认主题 VuePress 有一个开箱即用的默认主题,正使用在你当前正在浏览的文档网站上。 如果你不指定要使用的主题,那么就会自动使用默认主题。 为了配置默认主题,你需要在你的配置文件中通过 theme (../reference/config.md#t...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/guide/theme.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/guide/theme.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"主题"}],["meta",{"property":"og:description","content":"VuePress 主题为你提供了布局、样式和其他功能,帮助你专注于 Markdown 内容的写作。 默认主题 VuePress 有一个开箱即用的默认主题,正使用在你当前正在浏览的文档网站上。 如果你不指定要使用的主题,那么就会自动使用默认主题。 为了配置默认主题,你需要在你的配置文件中通过 theme (../reference/config.md#t..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"主题\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"默认主题","slug":"默认主题","link":"#默认主题","children":[]},{"level":2,"title":"社区主题","slug":"社区主题","link":"#社区主题","children":[]},{"level":2,"title":"本地主题","slug":"本地主题","link":"#本地主题","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.25,"words":375},"filePathRelative":"zh/guide/theme.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/theme.html-c65f5d90.js b/assets/theme.html-c65f5d90.js new file mode 100644 index 00000000..0e7ce943 --- /dev/null +++ b/assets/theme.html-c65f5d90.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4d76029c","path":"/guide/theme.html","title":"Theme","lang":"en-US","frontmatter":{"icon":"fa6-solid:palette","description":"VuePress theme can provide layouts, styles and many other features for you, helping you to focus on writing Markdown content. Default Theme VuePress has a default theme out of t...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/guide/theme.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/guide/theme.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Theme"}],["meta",{"property":"og:description","content":"VuePress theme can provide layouts, styles and many other features for you, helping you to focus on writing Markdown content. Default Theme VuePress has a default theme out of t..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Theme\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Default Theme","slug":"default-theme","link":"#default-theme","children":[]},{"level":2,"title":"Community Theme","slug":"community-theme","link":"#community-theme","children":[]},{"level":2,"title":"Local Theme","slug":"local-theme","link":"#local-theme","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.84,"words":252},"filePathRelative":"guide/theme.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/theme.html-cacc09fb.js b/assets/theme.html-cacc09fb.js new file mode 100644 index 00000000..9ef08429 --- /dev/null +++ b/assets/theme.html-cacc09fb.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-06329db8","path":"/advanced/theme.html","title":"Writing a Theme","lang":"en-US","frontmatter":{"icon":"fa6-solid:palette","description":"Before reading this guide, you'd better learn the guide of Writing a Plugin (./plugin.md) first. Create a Theme A VuePress theme is a special plugin, which should satisfy the Th...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/theme.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/theme.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Writing a Theme"}],["meta",{"property":"og:description","content":"Before reading this guide, you'd better learn the guide of Writing a Plugin (./plugin.md) first. Create a Theme A VuePress theme is a special plugin, which should satisfy the Th..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Writing a Theme\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Create a Theme","slug":"create-a-theme","link":"#create-a-theme","children":[]},{"level":2,"title":"Publish to NPM","slug":"publish-to-npm","link":"#publish-to-npm","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.26,"words":379},"filePathRelative":"advanced/theme.md","localizedDate":"February 22, 2023","autoDesc":true}`);export{e as data}; diff --git a/assets/theme.html-cb66f31b.js b/assets/theme.html-cb66f31b.js new file mode 100644 index 00000000..75e2b271 --- /dev/null +++ b/assets/theme.html-cb66f31b.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-66c42ad6","path":"/zh/advanced/theme.html","title":"开发主题","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:palette","description":"在阅读该指南之前,你最好先了解一下 开发插件 (./plugin.md) 指南。 创建一个主题 VuePress 主题是一个特殊的插件,它应该符合 主题 API (../reference/theme-api.md) 。和插件一样,主题可以是一个 主题对象 或一个 主题函数 ,并且通常通过一个函数来接收配置项: 然后,创建主题的客户端配置文件 clie...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/advanced/theme.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/theme.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"开发主题"}],["meta",{"property":"og:description","content":"在阅读该指南之前,你最好先了解一下 开发插件 (./plugin.md) 指南。 创建一个主题 VuePress 主题是一个特殊的插件,它应该符合 主题 API (../reference/theme-api.md) 。和插件一样,主题可以是一个 主题对象 或一个 主题函数 ,并且通常通过一个函数来接收配置项: 然后,创建主题的客户端配置文件 clie..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"开发主题\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"创建一个主题","slug":"创建一个主题","link":"#创建一个主题","children":[]},{"level":2,"title":"发布到 NPM","slug":"发布到-npm","link":"#发布到-npm","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.66,"words":497},"filePathRelative":"zh/advanced/theme.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/theme.html-ee0c13ce.js b/assets/theme.html-ee0c13ce.js new file mode 100644 index 00000000..d993906e --- /dev/null +++ b/assets/theme.html-ee0c13ce.js @@ -0,0 +1,58 @@ +import{_ as l,W as i,X as u,$ as s,a0 as n,Y as a,Z as e,a1 as o,D as p}from"./framework-46b0e263.js";const d={},r=s("h1",{id:"开发主题",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#开发主题","aria-hidden":"true"},"#"),n(" 开发主题")],-1),k={class:"hint-container tip"},v=s("p",{class:"hint-container-title"},"提示",-1),m=s("h2",{id:"创建一个主题",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#创建一个主题","aria-hidden":"true"},"#"),n(" 创建一个主题")],-1),b=s("em",null,"主题对象",-1),h=s("em",null,"主题函数",-1),g=o(`import { defaultTheme } from "vuepress"; + +export default { + theme: defaultTheme({ + // default theme config + navbar: [ + { + text: "Home", + link: "/", + }, + ], + }), +}; +
import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +const fooTheme = (options) => { + // 返回一个主题对象 + return { + name: "vuepress-theme-foo", + + // 主题的客户端配置文件的路径 + clientConfigFile: path.resolve(__dirname, "client.js"), + + // 设置自定义 dev / build 模板 + // 如果没有指定模板,将会使用 \`@vuepress/client\` 提供的默认模板 + templateBuild: path.resolve(__dirname, "templates/build.html"), + templateDev: path.resolve(__dirname, "templates/dev.html"), + + // 使用插件 + plugins: [ + // ... + ], + + // 其他的插件 API 也都可用 + }; +}; + +const barTheme = (options) => { + // 返回一个主题函数 + return (app) => { + return { + name: "vuepress-theme-bar", + // ... + }; + }; +}; +
然后,创建主题的客户端配置文件
client.js
:import { defineClientConfig } from "@vuepress/client"; +import Layout from "./layouts/Layout.vue"; +import NotFound from "./layouts/NotFound.vue"; + +export default defineClientConfig({ + layouts: { + Layout, + NotFound, + }, +}); +
`,4),_=s("code",null,"Layout",-1),f=o(`
layouts
字段声明了你的主题提供的布局。一个主题必须提供至少两个布局:Layout
和NotFound
。前者用于提供一般页面的默认布局,后者用于提供 404 页面的布局。<template> + <div> + <Content /> + </div> +</template> +
NotFound
布局会被用于404.html
页面:`,3),y=s("h2",{id:"发布到-npm",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#发布到-npm","aria-hidden":"true"},"#"),n(" 发布到 NPM")],-1),q={href:"https://docs.npmjs.com/cli/v8/configuring-npm/package-json",target:"_blank",rel:"noopener noreferrer"},x=o(`<template> + <div>404 Not Found</div> +</template> +
`,1),w=s("code",null,"name",-1),N=s("code",null,"vuepress-theme-xxx",-1),C=s("code",null,"@org/vuepress-theme-xxx",-1),L=s("em",null,"主题对象",-1),j=s("li",null,[n("在 "),s("code",null,"keywords"),n(" 中包含 "),s("code",null,"vuepress-theme"),n(" ,这样用户可以在 NPM 上搜索到你的主题。")],-1);function F(z,P){const t=p("RouterLink"),c=p("ExternalLinkIcon");return i(),u("div",null,[r,s("div",k,[v,s("p",null,[n("在阅读该指南之前,你最好先了解一下 "),a(t,{to:"/zh/advanced/plugin.html"},{default:e(()=>[n("开发插件")]),_:1}),n(" 指南。")])]),m,s("p",null,[n("VuePress 主题是一个特殊的插件,它应该符合 "),a(t,{to:"/zh/reference/theme-api.html"},{default:e(()=>[n("主题 API")]),_:1}),n(" 。和插件一样,主题可以是一个 "),b,n(" 或一个 "),h,n(" ,并且通常通过一个函数来接收配置项:")]),g,s("p",null,[_,n(" 布局应该包含 "),a(t,{to:"/zh/reference/components.html#content"},{default:e(()=>[n("Content")]),_:1}),n(" 组件来展示 Markdown 内容:")]),f,s("p",null,[n("你可以提供多个布局,用户可以通过 "),a(t,{to:"/zh/reference/frontmatter.html#layout"},{default:e(()=>[n("layout")]),_:1}),n(" Frontmatter 来修改布局。")]),y,s("p",null,[n("同样的,对于主题也有 "),s("a",q,[n("package.json"),a(c)]),n(" 相关的约定:")]),x,s("ul",null,[s("li",null,[n("将 "),w,n(" 按照约定命名: "),N,n(" 或 "),C,n(" ,它应该和 "),L,n(" 的 "),a(t,{to:"/zh/reference/theme-api.html#name"},{default:e(()=>[n("name")]),_:1}),n(" 字段保持一致。")]),j])])}const B=l(d,[["render",F],["__file","theme.html.vue"]]);export{B as default}; diff --git a/assets/toc.html-35e9d7bb.js b/assets/toc.html-35e9d7bb.js new file mode 100644 index 00000000..900516d8 --- /dev/null +++ b/assets/toc.html-35e9d7bb.js @@ -0,0 +1,74 @@ +import{_ as c,W as i,X as u,Y as a,$ as s,a0 as n,Z as e,a1 as p,D as o}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"toc",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#toc","aria-hidden":"true"},"#"),n(" toc")],-1),k=p(`{ + "name": "vuepress-theme-foo", + "keywords": ["vuepress-theme"] +} +
This plugin will provide a table-of-contents (TOC) component.
# Usage
npm i -D @vuepress/plugin-toc@next +
import { tocPlugin } from "@vuepress/plugin-toc"; + +export default { + plugins: [ + tocPlugin({ + // options + }), + ], +}; +
# Differences with Markdown TOC Syntax
`,5),v=p(`<!-- markdown toc syntax --> + +[[toc]] + +<!-- vue toc component --> +<Toc /> +
Both of them can be pre-rendered correctly in build mode. However, there are some differences between them.
The markdown syntax
[[toc]]
could only be used in markdown files. It is parsed by markdown-it, and the generated TOC is static content.The component
`,4),m=s("code",null,"linkClass",-1),g=s("code",null,"linkActiveClass",-1),h=p(`<Toc/>
could be used in both markdown files and vue files. It is loaded by vue, and the generated TOC is a vue component.Therefore, this plugin is more useful for theme developers.
# Options
# componentName
Type:
string
Default:
'Toc'
Details:
Specify the name of the TOC component.
# defaultPropsOptions
Type:
Partial<TocPropsOptions>
Default:
{}
Details:
Override the default values of the component options prop.
# Component Props
The TOC component also accepts props for customization.
<template> + <Toc :headers="headers" :options="options" /> +</template> +
# headers
- Type:
PageHeader[]
interface PageHeader { + level: number; + title: string; + slug: string; + children: PageHeader[]; +} +
Details:
Specify the headers array to render.
If this prop is not specified, the headers of current page will be used.
# options
- Type:
Partial<TocPropsOptions>
interface TocPropsOptions { + containerTag: string; + containerClass: string; + listClass: string; + itemClass: string; + linkTag: "a" | "RouterLink"; + linkClass: string; + linkActiveClass: string; + linkChildrenActiveClass: string; +} +
Default:
Following default values can be overridden by defaultPropsOptions.
const defaultOptions = { + containerTag: "nav", + containerClass: "vuepress-toc", + listClass: "vuepress-toc-list", + itemClass: "vuepress-toc-item", + linkTag: "RouterLink", + linkClass: "vuepress-toc-link", + linkActiveClass: "active", + linkChildrenActiveClass: "active", +}; +
Details:
Customize the TOC component.
If the
containerTag
is set to an empty string''
, the<nav>
container will be removed totally.Example:
The rendered TOC component with default options looks like:
`,20);function b(f,q){const l=o("NpmBadge"),t=o("RouterLink");return i(),u("div",null,[d,a(l,{package:"@vuepress/plugin-toc"}),k,s("p",null,[n("Similar to the "),a(t,{to:"/guide/markdown.html#table-of-contents"},{default:e(()=>[n("Table of Contents Markdown Syntax")]),_:1}),n(", the TOC component that provided by this plugin could be used in your markdown content directly:")]),v,s("p",null,[n("This plugin could work together with "),a(t,{to:"/reference/plugin/active-header-links.html"},{default:e(()=>[n("@vuepress/plugin-active-header-links")]),_:1}),n(" by setting the "),a(t,{to:"/reference/plugin/active-header-links.html#headerlinkselector"},{default:e(()=>[n("headerLinkSelector")]),_:1}),n(" to match the "),m,n(" option. When the page scroll to a certain header anchor, this corresponding link will be added "),g,n(" class name.")]),h])}const w=c(r,[["render",b],["__file","toc.html.vue"]]);export{w as default}; diff --git a/assets/toc.html-6a6abe62.js b/assets/toc.html-6a6abe62.js new file mode 100644 index 00000000..ded4d99d --- /dev/null +++ b/assets/toc.html-6a6abe62.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-76709450","path":"/reference/plugin/toc.html","title":"toc","lang":"en-US","frontmatter":{"description":"This plugin will provide a table-of-contents (TOC) component. Usage Differences with Markdown TOC Syntax Similar to the Table of Contents Markdown Syntax (../../guide/markdown.m...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/plugin/toc.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/plugin/toc.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"toc"}],["meta",{"property":"og:description","content":"This plugin will provide a table-of-contents (TOC) component. Usage Differences with Markdown TOC Syntax Similar to the Table of Contents Markdown Syntax (../../guide/markdown.m..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"toc\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Differences with Markdown TOC Syntax","slug":"differences-with-markdown-toc-syntax","link":"#differences-with-markdown-toc-syntax","children":[]},{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"componentName","slug":"componentname","link":"#componentname","children":[]},{"level":3,"title":"defaultPropsOptions","slug":"defaultpropsoptions","link":"#defaultpropsoptions","children":[]}]},{"level":2,"title":"Component Props","slug":"component-props","link":"#component-props","children":[{"level":3,"title":"headers","slug":"headers","link":"#headers","children":[]},{"level":3,"title":"options","slug":"options-1","link":"#options-1","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.59,"words":478},"filePathRelative":"reference/plugin/toc.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/toc.html-aac1b6d6.js b/assets/toc.html-aac1b6d6.js new file mode 100644 index 00000000..4e1a8024 --- /dev/null +++ b/assets/toc.html-aac1b6d6.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-048d95fe","path":"/zh/reference/plugin/toc.html","title":"toc","lang":"zh-CN","frontmatter":{"description":"该插件会提供一个目录 (table-of-contents, TOC) 组件。 使用方法 在 Build 模式中,它们都可以被正确地预渲染。然而,它们之间存在一些区别。 Markdown 语法 [[toc]] 仅能在 Markdown 文件中使用。它是由 markdown-it 解析的,生成的目录是静态内容。 组件 既可以用在 Markdown 文件中...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/plugin/toc.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/plugin/toc.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"toc"}],["meta",{"property":"og:description","content":"该插件会提供一个目录 (table-of-contents, TOC) 组件。 使用方法 在 Build 模式中,它们都可以被正确地预渲染。然而,它们之间存在一些区别。 Markdown 语法 [[toc]] 仅能在 Markdown 文件中使用。它是由 markdown-it 解析的,生成的目录是静态内容。 组件 既可以用在 Markdown 文件中..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"toc\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[]},{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"componentName","slug":"componentname","link":"#componentname","children":[]},{"level":3,"title":"defaultPropsOptions","slug":"defaultpropsoptions","link":"#defaultpropsoptions","children":[]}]},{"level":2,"title":"组件 Props","slug":"组件-props","link":"#组件-props","children":[{"level":3,"title":"headers","slug":"headers","link":"#headers","children":[]},{"level":3,"title":"options","slug":"options","link":"#options","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.08,"words":625},"filePathRelative":"zh/reference/plugin/toc.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/toc.html-d4b62f4b.js b/assets/toc.html-d4b62f4b.js new file mode 100644 index 00000000..d6204749 --- /dev/null +++ b/assets/toc.html-d4b62f4b.js @@ -0,0 +1,79 @@ +import{_ as c,W as i,X as u,Y as a,$ as s,a0 as n,Z as e,a1 as o,D as p}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"toc",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#toc","aria-hidden":"true"},"#"),n(" toc")],-1),k=o(`<template> + <!-- container --> + <nav class="vuepress-toc"> + <!-- list --> + <ul class="vuepress-toc-list"> + <!-- item --> + <li class="vuepress-toc-item"> + <!-- link --> + <RouterLink class="vuepress-toc-link" to="#foo">Foo</RouterLink> + </li> + <!-- item with children --> + <li class="vuepress-toc-item"> + <!-- link (children active) --> + <RouterLink class="vuepress-toc-link active" to="#bar">Bar</RouterLink> + <!-- list (children) --> + <ul class="vuepress-toc-list"> + <!-- item --> + <li class="vuepress-toc-item"> + <!-- link (active) --> + <RouterLink class="vuepress-toc-link active" to="#bar-child" + >Bar Child</RouterLink + > + </li> + </ul> + </li> + </ul> + </nav> +</template> +
该插件会提供一个目录 (table-of-contents, TOC) 组件。
# 使用方法
npm i -D @vuepress/plugin-toc@next +
import { tocPlugin } from '@vuepress/plugin-toc' + +export default { + plugins: [ + tocPlugin({ + // 配置项 + }), + ], +} + +## 与 Markdown 目录语法的区别 + +与 [Markdown 目录语法](../../guide/markdown.md#目录) 类似,该插件提供的目录组件可以直接在你的 Markdown 内容中使用: + +\`\`\`md +<!-- Markdown 目录语法 --> +[[toc]] + +<!-- Vue 目录组件 --> +<Toc /> +
在 Build 模式中,它们都可以被正确地预渲染。然而,它们之间存在一些区别。
Markdown 语法
[[toc]]
仅能在 Markdown 文件中使用。它是由 markdown-it 解析的,生成的目录是静态内容。组件
`,7),v=s("code",null,"linkClass",-1),m=s("code",null,"linkActiveClass",-1),g=o(`<Toc/>
既可以用在 Markdown 文件中,也可以用在 Vue 文件中。它是由 Vue 加载的,生成的目录是一个 Vue 组件。因此,该插件对于主题开发者来说更为有用。
# 配置项
# componentName
类型:
string
默认值:
'Toc'
详情:
指定目录组件的名称。
# defaultPropsOptions
类型:
Partial<TocPropsOptions>
默认值:
{}
详情:
覆盖组件 options Prop 的默认值。
# 组件 Props
目录组件可以通过 Props 来进行自定义。
<template> + <Toc :headers="headers" :options="options" /> +</template> +
# headers
- 类型:
PageHeader[]
interface PageHeader { + level: number; + title: string; + slug: string; + children: PageHeader[]; +} +
详情:
指定要渲染的标题数组。
如果该 Prop 没有被设置,默认会使用当前页面的标题。
# options
- 类型:
Partial<TocPropsOptions>
interface TocPropsOptions { + containerTag: string; + containerClass: string; + listClass: string; + itemClass: string; + linkTag: "a" | "RouterLink"; + linkClass: string; + linkActiveClass: string; + linkChildrenActiveClass: string; +} +
默认值:
下列默认值可以用过 defaultPropsOptions 来覆盖:
const defaultOptions = { + containerTag: "nav", + containerClass: "vuepress-toc", + listClass: "vuepress-toc-list", + itemClass: "vuepress-toc-item", + linkTag: "RouterLink", + linkClass: "vuepress-toc-link", + linkActiveClass: "active", + linkChildrenActiveClass: "active", +}; +
详情:
自定义目录组件。
如果
containerTag
设置为空字符串''
,那么最外层的<nav>
Container 会被完全移除。示例:
使用默认 options 的目录组件的渲染结果类似以下结构:
`,20);function b(h,q){const l=p("NpmBadge"),t=p("RouterLink");return i(),u("div",null,[d,a(l,{package:"@vuepress/plugin-toc"}),k,s("p",null,[n("该插件可以和 "),a(t,{to:"/zh/reference/plugin/active-header-links.html"},{default:e(()=>[n("@vuepress/plugin-active-header-links")]),_:1}),n(" 协同工作,你只需要将 "),a(t,{to:"/zh/reference/plugin/active-header-links.html#headerlinkselector"},{default:e(()=>[n("headerLinkSelector")]),_:1}),n(" 与该插件的 "),v,n(" 匹配即可。当页面滚动至某个标题锚点后,对应的链接就会被加上 "),m,n(" 类名。")]),g])}const _=c(r,[["render",b],["__file","toc.html.vue"]]);export{_ as default}; diff --git a/assets/usage-of-client-config.html-01b482fe.js b/assets/usage-of-client-config.html-01b482fe.js new file mode 100644 index 00000000..82303963 --- /dev/null +++ b/assets/usage-of-client-config.html-01b482fe.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-c03241b4","path":"/zh/advanced/cookbook/usage-of-client-config.html","title":"客户端配置的使用方法","lang":"zh-CN","frontmatter":{"icon":"fa6-solid:gear","description":"你可以直接在你的项目中使用 客户端配置文件 (../../guide/configuration.md#客户端配置文件) 。或者,在你的插件或者主题中,使用 clientConfigFile (../../reference/plugin-api.md#clientconfigfile) Hook 来指定客户端配置文件的路径: 在客户端配置文件中,@v...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/advanced/cookbook/usage-of-client-config.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/advanced/cookbook/usage-of-client-config.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"客户端配置的使用方法"}],["meta",{"property":"og:description","content":"你可以直接在你的项目中使用 客户端配置文件 (../../guide/configuration.md#客户端配置文件) 。或者,在你的插件或者主题中,使用 clientConfigFile (../../reference/plugin-api.md#clientconfigfile) Hook 来指定客户端配置文件的路径: 在客户端配置文件中,@v..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"客户端配置的使用方法\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"enhance","slug":"enhance","link":"#enhance","children":[{"level":3,"title":"注册 Vue 组件","slug":"注册-vue-组件","link":"#注册-vue-组件","children":[]},{"level":3,"title":"使用不支持 SSR 的功能","slug":"使用不支持-ssr-的功能","link":"#使用不支持-ssr-的功能","children":[]},{"level":3,"title":"使用 Router 方法","slug":"使用-router-方法","link":"#使用-router-方法","children":[]}]},{"level":2,"title":"setup","slug":"setup","link":"#setup","children":[{"level":3,"title":"使用组合式 API","slug":"使用组合式-api","link":"#使用组合式-api","children":[]},{"level":3,"title":"使用不支持 SSR 的功能","slug":"使用不支持-ssr-的功能-1","link":"#使用不支持-ssr-的功能-1","children":[]}]},{"level":2,"title":"layouts","slug":"layouts","link":"#layouts","children":[]},{"level":2,"title":"rootComponents","slug":"rootcomponents","link":"#rootcomponents","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":3.37,"words":1011},"filePathRelative":"zh/advanced/cookbook/usage-of-client-config.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/usage-of-client-config.html-02d1b251.js b/assets/usage-of-client-config.html-02d1b251.js new file mode 100644 index 00000000..9dc77c77 --- /dev/null +++ b/assets/usage-of-client-config.html-02d1b251.js @@ -0,0 +1,88 @@ +import{_ as i,W as u,X as l,$ as s,a0 as n,Y as a,Z as e,a1 as p,D as c}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"客户端配置的使用方法",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#客户端配置的使用方法","aria-hidden":"true"},"#"),n(" 客户端配置的使用方法")],-1),k=p(`<template> + <!-- container --> + <nav class="vuepress-toc"> + <!-- list --> + <ul class="vuepress-toc-list"> + <!-- item --> + <li class="vuepress-toc-item"> + <!-- link --> + <RouterLink class="vuepress-toc-link" to="#foo">Foo</RouterLink> + </li> + <!-- item with children --> + <li class="vuepress-toc-item"> + <!-- link (children active) --> + <RouterLink class="vuepress-toc-link active" to="#bar">Bar</RouterLink> + <!-- list (children) --> + <ul class="vuepress-toc-list"> + <!-- item --> + <li class="vuepress-toc-item"> + <!-- link (active) --> + <RouterLink class="vuepress-toc-link active" to="#bar-child" + >Bar Child</RouterLink + > + </li> + </ul> + </li> + </ul> + </nav> +</template> +
`,1),v=s("code",null,"@vuepress/client",-1),m=p(`import { path } from "@vuepress/utils"; +import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +const pluginOrTheme = { + clientConfigFile: path.resolve(__dirname, "./path/to/clientConfig.ts"), +}; +
import { defineClientConfig } from "@vuepress/client"; + +export default defineClientConfig({ + enhance({ app, router, siteData }) {}, + setup() {}, + layouts: {}, + rootComponents: [], +}); +
# enhance
`,3),f=s("code",null,"app",-1),h={href:"https://staging-cn.vuejs.org/api/application.html#create-app",target:"_blank",rel:"noopener noreferrer"},b=s("code",null,"router",-1),g={href:"https://router.vuejs.org/zh/api/index.html#createrouter",target:"_blank",rel:"noopener noreferrer"},_=s("code",null,"siteData",-1),y=s("p",null,[s("code",null,"enhance"),n(" 函数会在客户端应用创建后被调用,你可以对 Vue 应用添加各种能力。")],-1),w=s("h3",{id:"注册-vue-组件",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#注册-vue-组件","aria-hidden":"true"},"#"),n(" 注册 Vue 组件")],-1),C={href:"https://staging-cn.vuejs.org/api/application.html#app-component",target:"_blank",rel:"noopener noreferrer"},q=p(`
enhance
函数既可以是同步的,也可以是异步的。它接收一个 Context 参数,包含以下属性:import { defineClientConfig } from "@vuepress/client"; +import MyComponent from "./MyComponent.vue"; + +export default defineClientConfig({ + enhance({ app }) { + app.component("MyComponent", MyComponent); + }, +}); +
# 使用不支持 SSR 的功能
VuePress 会在构建过程中生成一个 SSR 应用,用以对页面进行预渲染。一般而言,如果一段代码在客户端应用 Mount 之前就使用了浏览器或 DOM API ,我们就认为其对 SSR 不友好,即不支持 SSR 。
`,3),x=s("code",null,"enhance",-1),S=s("code",null,[n("_"),s("wbr"),n("_VUEPRESS_SSR__")],-1),R=p(`import { defineClientConfig } from "@vuepress/client"; + +export default defineClientConfig({ + async enhance() { + if (!_
_VUEPRESS_SSR__) { + const nonSsrFriendlyModule = await import("non-ssr-friendly-module"); + // ... + } + }, +}); + # 使用 Router 方法
`,2),E={href:"https://router.vuejs.org/zh/api/index.html#router-%E6%96%B9%E6%B3%95",target:"_blank",rel:"noopener noreferrer"},z=p(`import { defineClientConfig } from "@vuepress/client"; + +export default defineClientConfig({ + enhance({ router }) { + router.beforeEach((to) => { + console.log("before navigation"); + }); + + router.afterEach((to) => { + console.log("after navigation"); + }); + }, +}); +
注意
我们不推荐使用
addRoute
方法来添加动态路由,因为这些路由记录 不会 在构建模式中被预渲染出来。当然,如果你了解了这种用法的缺点,你还是可以这样使用。
# setup
`,3),M=s("code",null,"setup",-1),V={href:"https://staging-cn.vuejs.org/api/composition-api-setup.html",target:"_blank",rel:"noopener noreferrer"},B=s("h3",{id:"使用组合式-api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#使用组合式-api","aria-hidden":"true"},"#"),n(" 使用组合式 API")],-1),P=s("code",null,"setup",-1),A={href:"https://staging-cn.vuejs.org/api/composition-api-setup.html",target:"_blank",rel:"noopener noreferrer"},D=p(`import { defineClientConfig } from "@vuepress/client"; +import { provide, ref } from "vue"; +import { useRoute, useRouter } from "vue-router"; + +export default defineClientConfig({ + setup() { + // 获取当前的路由位置 + const route = useRoute(); + // 或者 vue-router 实例 + const router = useRouter(); + // 供给一个值,可以被布局、页面和其他组件注入 + const count = ref(0); + provide("count", count); + }, +}); +
# 使用不支持 SSR 的功能
`,2),j=s("code",null,"setup",-1),I=s("code",null,[n("_"),s("wbr"),n("_VUEPRESS_SSR__")],-1),L={href:"https://staging-cn.vuejs.org/api/composition-api-lifecycle.html#onmounted",target:"_blank",rel:"noopener noreferrer"},O=p(`import { defineClientConfig } from "@vuepress/client"; +import { onMounted } from "vue"; + +export default defineClientConfig({ + setup() { + onMounted(() => { + // 在 mounted 之后使用 DOM API + document.querySelector("#app"); + }); + }, +}); +
# layouts
`,2),F=s("code",null,"layouts",-1),H=p(`import { defineClientConfig } from "@vuepress/client"; +import MyLayout from "./layouts/MyLayout.vue"; + +export default defineClientConfig({ + layouts: { + MyLayout, + }, +}); +
# rootComponents
rootComponents
是一个组件数组,它们将会直接被放置在客户端 Vue 应用的根节点下。该选项的典型使用方式就是放置一些全局的 UI 组件,比如全局弹窗等:
`,5);function N(U,G){const t=c("RouterLink"),o=c("ExternalLinkIcon");return u(),l("div",null,[d,s("p",null,[n("你可以直接在你的项目中使用 "),a(t,{to:"/zh/guide/configuration.html#%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"},{default:e(()=>[n("客户端配置文件")]),_:1}),n(" 。或者,在你的插件或者主题中,使用 "),a(t,{to:"/zh/reference/plugin-api.html#clientconfigfile"},{default:e(()=>[n("clientConfigFile")]),_:1}),n(" Hook 来指定客户端配置文件的路径:")]),k,s("p",null,[n("在客户端配置文件中,"),v,n(" 包提供了一个 "),a(t,{to:"/zh/reference/client-api.html#defineclientconfig"},{default:e(()=>[n("defineClientConfig")]),_:1}),n(" 函数来帮助你定义客户端配置:")]),m,s("ul",null,[s("li",null,[f,n(" 是由 "),s("a",h,[n("createApp"),a(o)]),n(" 创建的 Vue 应用实例。")]),s("li",null,[b,n(" 是由 "),s("a",g,[n("createRouter"),a(o)]),n(" 创建的路由实例。")]),s("li",null,[_,n(" 是一个根据用户配置生成的 Ref 对象,包含 "),a(t,{to:"/zh/reference/config.html#base"},{default:e(()=>[n("base")]),_:1}),n(", "),a(t,{to:"/zh/reference/config.html#lang"},{default:e(()=>[n("lang")]),_:1}),n(", "),a(t,{to:"/zh/reference/config.html#title"},{default:e(()=>[n("title")]),_:1}),n(", "),a(t,{to:"/zh/reference/config.html#description"},{default:e(()=>[n("description")]),_:1}),n(", "),a(t,{to:"/zh/reference/config.html#head"},{default:e(()=>[n("head")]),_:1}),n(" 和 "),a(t,{to:"/zh/reference/config.html#locales"},{default:e(()=>[n("locales")]),_:1}),n("。")])]),y,w,s("p",null,[n("你可以通过 "),s("a",C,[n("app.component"),a(o)]),n(" 方法来注册 Vue 全局组件:")]),q,s("p",null,[n("我们已经提供了一个 "),a(t,{to:"/zh/reference/components.html#clientonly"},{default:e(()=>[n("ClientOnly")]),_:1}),n(" 组件来包裹不支持 SSR 的内容。")]),s("p",null,[n("在 "),x,n(" 函数中,你可以使用 "),a(t,{to:"/zh/reference/client-api.html#ssr"},{default:e(()=>[S]),_:1}),n(" 标记来处理这种情况。")]),R,s("p",null,[n("你可以使用 vue-router 提供的 "),s("a",E,[n("Router 方法"),a(o)]),n(" 。例如,添加导航钩子:")]),z,s("p",null,[M,n(" 函数会在客户端 Vue 应用的 "),s("a",V,[n("setup"),a(o)]),n(" Hook 中被调用。")]),B,s("p",null,[n("你可以把 "),P,n(" 函数当作根组件的 "),s("a",A,[n("setup"),a(o)]),n(" Hook 中的一部分。因此,所有的组合式 API 都可以在这里使用。")]),D,s("p",null,[n("在 "),j,n(" 函数中,"),a(t,{to:"/zh/reference/client-api.html#ssr"},{default:e(()=>[I]),_:1}),n(" 标记同样可用。")]),s("p",null,[n("使用不支持 SSR 的功能的另一种方式就是将他们放在 "),s("a",L,[n("onMounted"),a(o)]),n(" Hook 中:")]),O,s("p",null,[F,n(" 配置项用于设置布局组件。你在此处注册布局后,用户就可以通过 "),a(t,{to:"/zh/reference/frontmatter.html#layout"},{default:e(()=>[n("layout")]),_:1}),n(" frontmatter 来使用它们。")]),H])}const W=i(r,[["render",N],["__file","usage-of-client-config.html.vue"]]);export{W as default}; diff --git a/assets/usage-of-client-config.html-77c30a87.js b/assets/usage-of-client-config.html-77c30a87.js new file mode 100644 index 00000000..a8256cdf --- /dev/null +++ b/assets/usage-of-client-config.html-77c30a87.js @@ -0,0 +1,87 @@ +import{_ as i,W as u,X as l,$ as s,a0 as n,Y as a,Z as t,a1 as o,D as c}from"./framework-46b0e263.js";const r={},d=s("h1",{id:"usage-of-client-config",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#usage-of-client-config","aria-hidden":"true"},"#"),n(" Usage of Client Config")],-1),k=o(`import { defineClientConfig } from "@vuepress/client"; +import GlobalPopup from "./components/GlobalPopup.vue"; + +export default defineClientConfig({ + rootComponents: [GlobalPopup], +}); +
`,1),v=s("code",null,"@vuepress/client",-1),m=o(`import { getDirname, path } from "@vuepress/utils"; + +const __dirname = getDirname(import.meta.url); + +const pluginOrTheme = { + clientConfigFile: path.resolve(__dirname, "./path/to/clientConfig.ts"), +}; +
import { defineClientConfig } from "@vuepress/client"; + +export default defineClientConfig({ + enhance({ app, router, siteData }) {}, + setup() {}, + layouts: {}, + rootComponents: [], +}); +
# enhance
The
`,3),f=s("code",null,"app",-1),h={href:"https://vuejs.org/api/application.html#createapp",target:"_blank",rel:"noopener noreferrer"},g=s("code",null,"router",-1),b={href:"https://router.vuejs.org/api/#createrouter",target:"_blank",rel:"noopener noreferrer"},y=s("code",null,"siteData",-1),_=s("p",null,[n("The "),s("code",null,"enhance"),n(" function will be invoked after the client app is created. It's possible to implement any enhancements to the Vue application.")],-1),w=s("h3",{id:"register-vue-components",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#register-vue-components","aria-hidden":"true"},"#"),n(" Register Vue Components")],-1),C={href:"https://vuejs.org/api/application.html#app-component",target:"_blank",rel:"noopener noreferrer"},q=o(`enhance
function could be either synchronous or asynchronous. It accepts a context param with following properties:import { defineClientConfig } from "@vuepress/client"; +import MyComponent from "./MyComponent.vue"; + +export default defineClientConfig({ + enhance({ app }) { + app.component("MyComponent", MyComponent); + }, +}); +
# Use Non-SSR-Friendly Features
VuePress will generate a SSR application to pre-render pages during build. Generally speaking, if a code snippet is using Browser / DOM APIs before client app is mounted, we call it non-SSR-friendly.
`,3),x=s("code",null,"enhance",-1),S=s("code",null,[n("_"),s("wbr"),n("_VUEPRESS_SSR__")],-1),R=o(`import { defineClientConfig } from "@vuepress/client"; + +export default defineClientConfig({ + async enhance() { + if (!_
_VUEPRESS_SSR__) { + const nonSsrFriendlyModule = await import("non-ssr-friendly-module"); + // ... + } + }, +}); + # Use Router Methods
`,2),M={href:"https://router.vuejs.org/api/#router-methods",target:"_blank",rel:"noopener noreferrer"},I=o(`import { defineClientConfig } from "@vuepress/client"; + +export default defineClientConfig({ + enhance({ router }) { + router.beforeEach((to) => { + console.log("before navigation"); + }); + + router.afterEach((to) => { + console.log("after navigation"); + }); + }, +}); +
Note
It's not recommended to use
addRoute
method to add dynamic routes here, because those routes will NOT be pre-rendered in build mode.But you can still do that if you understand the drawback.
# setup
`,3),V=s("code",null,"setup",-1),E={href:"https://vuejs.org/api/composition-api-setup.html",target:"_blank",rel:"noopener noreferrer"},P=s("h3",{id:"use-composition-api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#use-composition-api","aria-hidden":"true"},"#"),n(" Use Composition API")],-1),j=s("code",null,"setup",-1),T={href:"https://vuejs.org/api/composition-api-setup.html",target:"_blank",rel:"noopener noreferrer"},U=o(`import { defineClientConfig } from "@vuepress/client"; +import { provide, ref } from "vue"; +import { useRoute, useRouter } from "vue-router"; + +export default defineClientConfig({ + setup() { + // get the current route location + const route = useRoute(); + // get the vue-router instance + const router = useRouter(); + // provide a value that can be injected by layouts, pages and other components + const count = ref(0); + provide("count", count); + }, +}); +
# Use Non-SSR-Friendly Features
`,2),F=s("code",null,"setup",-1),N=s("code",null,[n("_"),s("wbr"),n("_VUEPRESS_SSR__")],-1),A={href:"https://vuejs.org/api/composition-api-lifecycle.html#onmounted",target:"_blank",rel:"noopener noreferrer"},D=o(`import { defineClientConfig } from "@vuepress/client"; +import { onMounted } from "vue"; + +export default defineClientConfig({ + setup() { + onMounted(() => { + // use DOM API after mounted + document.querySelector("#app"); + }); + }, +}); +
# layouts
`,2),L=s("code",null,"layouts",-1),O=o(`import { defineClientConfig } from "@vuepress/client"; +import MyLayout from "./layouts/MyLayout.vue"; + +export default defineClientConfig({ + layouts: { + MyLayout, + }, +}); +
# rootComponents
The
rootComponents
is a components array to be placed directly into the root node of the client vue app.Typical usage of this option is to put some global UI components, like global popup or so:
`,5);function B(Y,G){const e=c("RouterLink"),p=c("ExternalLinkIcon");return u(),l("div",null,[d,s("p",null,[n("You can make use of the "),a(e,{to:"/guide/configuration.html#client-config-file"},{default:t(()=>[n("client config file")]),_:1}),n(" directly in your project, or specify the file path in your plugin or theme via "),a(e,{to:"/reference/plugin-api.html#clientconfigfile"},{default:t(()=>[n("clientConfigFile")]),_:1}),n(" hook:")]),k,s("p",null,[n("Inside the client config file, "),v,n(" package provides a helper function "),a(e,{to:"/reference/client-api.html#defineclientconfig"},{default:t(()=>[n("defineClientConfig")]),_:1}),n(" to help you define the client config:")]),m,s("ul",null,[s("li",null,[f,n(" is the Vue application instance that created by "),s("a",h,[n("createApp"),a(p)]),n(".")]),s("li",null,[g,n(" is the Vue Router instance that created by "),s("a",b,[n("createRouter"),a(p)]),n(".")]),s("li",null,[y,n(" is a ref of an object that generated from user config, including "),a(e,{to:"/reference/config.html#base"},{default:t(()=>[n("base")]),_:1}),n(", "),a(e,{to:"/reference/config.html#lang"},{default:t(()=>[n("lang")]),_:1}),n(", "),a(e,{to:"/reference/config.html#title"},{default:t(()=>[n("title")]),_:1}),n(", "),a(e,{to:"/reference/config.html#description"},{default:t(()=>[n("description")]),_:1}),n(", "),a(e,{to:"/reference/config.html#head"},{default:t(()=>[n("head")]),_:1}),n(" and "),a(e,{to:"/reference/config.html#locales"},{default:t(()=>[n("locales")]),_:1}),n(".")])]),_,w,s("p",null,[n("You can register global Vue components via the "),s("a",C,[n("app.component"),a(p)]),n(" method:")]),q,s("p",null,[n("We already provides a "),a(e,{to:"/reference/components.html#clientonly"},{default:t(()=>[n("ClientOnly")]),_:1}),n(" component to wrap non-SSR-friendly content.")]),s("p",null,[n("In the "),x,n(" function, you can make use of the "),a(e,{to:"/reference/client-api.html#ssr"},{default:t(()=>[S]),_:1}),n(" flag for that purpose.")]),R,s("p",null,[n("You can make use of the "),s("a",M,[n("Router Methods"),a(p)]),n(" that provided by vue-router. For example, add navigation guard:")]),I,s("p",null,[n("The "),V,n(" function would be invoked inside the "),s("a",E,[n("setup"),a(p)]),n(" hook of the client vue app.")]),P,s("p",null,[n("You can take the "),j,n(" function as part of the "),s("a",T,[n("setup"),a(p)]),n(" hook of the root component. Thus, all composition APIs are available here.")]),U,s("p",null,[n("In the "),F,n(" function, the "),a(e,{to:"/reference/client-api.html#ssr"},{default:t(()=>[N]),_:1}),n(" flag is also available.")]),s("p",null,[n("Another way to use non-ssr-friendly features is to put them inside the "),s("a",A,[n("onMounted"),a(p)]),n(" hook:")]),D,s("p",null,[n("The "),L,n(" options is to set layout components. After layout components are registered here, users can use it via "),a(e,{to:"/reference/frontmatter.html#layout"},{default:t(()=>[n("layout")]),_:1}),n(" frontmatter.")]),O])}const X=i(r,[["render",B],["__file","usage-of-client-config.html.vue"]]);export{X as default}; diff --git a/assets/usage-of-client-config.html-7ce03b78.js b/assets/usage-of-client-config.html-7ce03b78.js new file mode 100644 index 00000000..db6b9d87 --- /dev/null +++ b/assets/usage-of-client-config.html-7ce03b78.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3d6c80f5","path":"/advanced/cookbook/usage-of-client-config.html","title":"Usage of Client Config","lang":"en-US","frontmatter":{"icon":"fa6-solid:gear","description":"You can make use of the client config file (../../guide/configuration.md#client-config-file) directly in your project, or specify the file path in your plugin or theme via clien...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/advanced/cookbook/usage-of-client-config.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/advanced/cookbook/usage-of-client-config.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Usage of Client Config"}],["meta",{"property":"og:description","content":"You can make use of the client config file (../../guide/configuration.md#client-config-file) directly in your project, or specify the file path in your plugin or theme via clien..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Usage of Client Config\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"enhance","slug":"enhance","link":"#enhance","children":[{"level":3,"title":"Register Vue Components","slug":"register-vue-components","link":"#register-vue-components","children":[]},{"level":3,"title":"Use Non-SSR-Friendly Features","slug":"use-non-ssr-friendly-features","link":"#use-non-ssr-friendly-features","children":[]},{"level":3,"title":"Use Router Methods","slug":"use-router-methods","link":"#use-router-methods","children":[]}]},{"level":2,"title":"setup","slug":"setup","link":"#setup","children":[{"level":3,"title":"Use Composition API","slug":"use-composition-api","link":"#use-composition-api","children":[]},{"level":3,"title":"Use Non-SSR-Friendly Features","slug":"use-non-ssr-friendly-features-1","link":"#use-non-ssr-friendly-features-1","children":[]}]},{"level":2,"title":"layouts","slug":"layouts","link":"#layouts","children":[]},{"level":2,"title":"rootComponents","slug":"rootcomponents","link":"#rootcomponents","children":[]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.48,"words":745},"filePathRelative":"advanced/cookbook/usage-of-client-config.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/vite.html-1cf3b6bd.js b/assets/vite.html-1cf3b6bd.js new file mode 100644 index 00000000..4d72c46d --- /dev/null +++ b/assets/vite.html-1cf3b6bd.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6ff623ea","path":"/zh/reference/bundler/vite.html","title":"Vite","lang":"zh-CN","frontmatter":{"icon":"simple-icons:vite","description":"Vite 打包工具是由 @vuepress/bundler-vite (https://www.npmjs.com/package/@vuepress/bundler-vite) 包提供的。它是 vuepress (https://www.npmjs.com/package/vuepress) 包的依赖之一,当然你也可以单独安装它: 配置项 Vite ...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/bundler/vite.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/bundler/vite.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Vite"}],["meta",{"property":"og:description","content":"Vite 打包工具是由 @vuepress/bundler-vite (https://www.npmjs.com/package/@vuepress/bundler-vite) 包提供的。它是 vuepress (https://www.npmjs.com/package/vuepress) 包的依赖之一,当然你也可以单独安装它: 配置项 Vite ..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Vite\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"viteOptions","slug":"viteoptions","link":"#viteoptions","children":[]},{"level":3,"title":"vuePluginOptions","slug":"vuepluginoptions","link":"#vuepluginoptions","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.5,"words":149},"filePathRelative":"zh/reference/bundler/vite.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/vite.html-27bceae1.js b/assets/vite.html-27bceae1.js new file mode 100644 index 00000000..d4e3960e --- /dev/null +++ b/assets/vite.html-27bceae1.js @@ -0,0 +1,11 @@ +import{_ as i,W as p,X as l,Y as s,$ as n,a0 as e,a1 as r,D as t}from"./framework-46b0e263.js";const c={},u=n("h1",{id:"vite",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vite","aria-hidden":"true"},"#"),e(" Vite")],-1),d={href:"https://www.npmjs.com/package/@vuepress/bundler-vite",target:"_blank",rel:"noopener noreferrer"},v={href:"https://www.npmjs.com/package/vuepress",target:"_blank",rel:"noopener noreferrer"},k=r(`import { defineClientConfig } from "@vuepress/client"; +import GlobalPopup from "./components/GlobalPopup.vue"; + +export default defineClientConfig({ + rootComponents: [GlobalPopup], +}); +
npm i -D @vuepress/bundler-vite@next +
# Options
Reference of vite bundler options:
import { viteBundler } from "@vuepress/bundler-vite"; +import { defineUserConfig } from "@vuepress/cli"; + +export default defineUserConfig({ + bundler: viteBundler({ + viteOptions: {}, + vuePluginOptions: {}, + }), +}); +
# viteOptions
`,5),h=n("li",null,[n("p",null,"Details:"),n("p",null,"Accepts all options of Vite.")],-1),_=n("p",null,"Also see:",-1),f={href:"https://vitejs.dev/config/",target:"_blank",rel:"noopener noreferrer"},m=n("h3",{id:"vuepluginoptions",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepluginoptions","aria-hidden":"true"},"#"),e(" vuePluginOptions")],-1),g=n("p",null,"Details:",-1),b={href:"https://www.npmjs.com/package/@vitejs/plugin-vue",target:"_blank",rel:"noopener noreferrer"},w=n("p",null,"Also see:",-1),x={href:"https://vitejs.dev/plugins/#vitejs-plugin-vue",target:"_blank",rel:"noopener noreferrer"};function y(V,j){const o=t("NpmBadge"),a=t("ExternalLinkIcon");return p(),l("div",null,[u,s(o,{package:"@vuepress/bundler-vite"}),n("p",null,[e("Vite bundler is provided by "),n("a",d,[e("@vuepress/bundler-vite"),s(a)]),e(" package. It is a dependency of the "),n("a",v,[e("vuepress"),s(a)]),e(" package, and you can also install it separately.")]),k,n("ul",null,[h,n("li",null,[_,n("ul",null,[n("li",null,[n("a",f,[e("Vite > Config"),s(a)])])])])]),m,n("ul",null,[n("li",null,[g,n("p",null,[e("Accepts all options of "),n("a",b,[e("@vitejs/plugin-vue"),s(a)]),e(".")])]),n("li",null,[w,n("ul",null,[n("li",null,[n("a",x,[e("Vite > Plugins > Official Plugins"),s(a)])])])])])])}const N=i(c,[["render",y],["__file","vite.html.vue"]]);export{N as default}; diff --git a/assets/vite.html-9326e178.js b/assets/vite.html-9326e178.js new file mode 100644 index 00000000..782fc04e --- /dev/null +++ b/assets/vite.html-9326e178.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-cf5a290e","path":"/reference/bundler/vite.html","title":"Vite","lang":"en-US","frontmatter":{"icon":"simple-icons:vite","description":"Vite bundler is provided by @vuepress/bundler-vite (https://www.npmjs.com/package/@vuepress/bundler-vite) package. It is a dependency of the vuepress (https://www.npmjs.com/pack...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/bundler/vite.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/bundler/vite.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Vite"}],["meta",{"property":"og:description","content":"Vite bundler is provided by @vuepress/bundler-vite (https://www.npmjs.com/package/@vuepress/bundler-vite) package. It is a dependency of the vuepress (https://www.npmjs.com/pack..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Vite\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"viteOptions","slug":"viteoptions","link":"#viteoptions","children":[]},{"level":3,"title":"vuePluginOptions","slug":"vuepluginoptions","link":"#vuepluginoptions","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":0.41,"words":122},"filePathRelative":"reference/bundler/vite.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/vite.html-a42b420e.js b/assets/vite.html-a42b420e.js new file mode 100644 index 00000000..1eb7346d --- /dev/null +++ b/assets/vite.html-a42b420e.js @@ -0,0 +1,11 @@ +import{_ as i,W as p,X as l,Y as s,$ as n,a0 as e,a1 as r,D as t}from"./framework-46b0e263.js";const c={},u=n("h1",{id:"vite",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vite","aria-hidden":"true"},"#"),e(" Vite")],-1),d={href:"https://www.npmjs.com/package/@vuepress/bundler-vite",target:"_blank",rel:"noopener noreferrer"},v={href:"https://www.npmjs.com/package/vuepress",target:"_blank",rel:"noopener noreferrer"},k=r(`npm i -D @vuepress/bundler-vite@next +
# 配置项
Vite 打包工具的配置项:
import { viteBundler } from "@vuepress/bundler-vite"; +import { defineUserConfig } from "@vuepress/cli"; + +export default defineUserConfig({ + bundler: viteBundler({ + viteOptions: {}, + vuePluginOptions: {}, + }), +}); +
# viteOptions
`,5),h=n("li",null,[n("p",null,"详情:"),n("p",null,"接收 Vite 的所有配置项。")],-1),_=n("p",null,"参考:",-1),m={href:"https://cn.vitejs.dev/config/",target:"_blank",rel:"noopener noreferrer"},f=n("h3",{id:"vuepluginoptions",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuepluginoptions","aria-hidden":"true"},"#"),e(" vuePluginOptions")],-1),g=n("p",null,"详情:",-1),b={href:"https://www.npmjs.com/package/@vitejs/plugin-vue",target:"_blank",rel:"noopener noreferrer"},w=n("p",null,"参考:",-1),x={href:"https://cn.vitejs.dev/plugins/#vitejsplugin-vue",target:"_blank",rel:"noopener noreferrer"};function V(j,y){const o=t("NpmBadge"),a=t("ExternalLinkIcon");return p(),l("div",null,[u,s(o,{package:"@vuepress/bundler-vite"}),n("p",null,[e("Vite 打包工具是由 "),n("a",d,[e("@vuepress/bundler-vite"),s(a)]),e(" 包提供的。它是 "),n("a",v,[e("vuepress"),s(a)]),e(" 包的依赖之一,当然你也可以单独安装它:")]),k,n("ul",null,[h,n("li",null,[_,n("ul",null,[n("li",null,[n("a",m,[e("Vite > Config"),s(a)])])])])]),f,n("ul",null,[n("li",null,[g,n("p",null,[e("接收 "),n("a",b,[e("@vitejs/plugin-vue"),s(a)]),e(" 的所有配置项。")])]),n("li",null,[w,n("ul",null,[n("li",null,[n("a",x,[e("Vite > 插件 > 官方插件"),s(a)])])])])])])}const N=i(c,[["render",V],["__file","vite.html.vue"]]);export{N as default}; diff --git a/assets/vuepress-core-process-3a7a342e.js b/assets/vuepress-core-process-3a7a342e.js new file mode 100644 index 00000000..948e92ec --- /dev/null +++ b/assets/vuepress-core-process-3a7a342e.js @@ -0,0 +1 @@ +const e="/images/guide/vuepress-architecture-overview.png",s="/images/guide/vuepress-core-process.png";export{e as _,s as a}; diff --git a/assets/webpack.html-52b8a648.js b/assets/webpack.html-52b8a648.js new file mode 100644 index 00000000..6029a9ef --- /dev/null +++ b/assets/webpack.html-52b8a648.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-dde74f12","path":"/zh/reference/bundler/webpack.html","title":"Webpack","lang":"zh-CN","frontmatter":{"icon":"mdi:webpack","description":"Webpack 打包工具是由 @vuepress/bundler-webpack (https://www.npmjs.com/package/@vuepress/bundler-webpack) 包提供的。它是 vuepress-webpack (https://www.npmjs.com/package/vuepress-webpack) 包的依赖...","head":[["link",{"rel":"alternate","hreflang":"en-us","href":"https://vuejs.press/reference/bundler/webpack.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/zh/reference/bundler/webpack.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Webpack"}],["meta",{"property":"og:description","content":"Webpack 打包工具是由 @vuepress/bundler-webpack (https://www.npmjs.com/package/@vuepress/bundler-webpack) 包提供的。它是 vuepress-webpack (https://www.npmjs.com/package/vuepress-webpack) 包的依赖..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"zh-CN"}],["meta",{"property":"og:locale:alternate","content":"en-US"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Webpack\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"配置项","slug":"配置项","link":"#配置项","children":[{"level":3,"title":"configureWebpack","slug":"configurewebpack","link":"#configurewebpack","children":[]},{"level":3,"title":"chainWebpack","slug":"chainwebpack","link":"#chainwebpack","children":[]},{"level":3,"title":"devServerSetupMiddlewares","slug":"devserversetupmiddlewares","link":"#devserversetupmiddlewares","children":[]},{"level":3,"title":"vue","slug":"vue","link":"#vue","children":[]},{"level":3,"title":"postcss","slug":"postcss","link":"#postcss","children":[]},{"level":3,"title":"stylus","slug":"stylus","link":"#stylus","children":[]},{"level":3,"title":"scss","slug":"scss","link":"#scss","children":[]},{"level":3,"title":"sass","slug":"sass","link":"#sass","children":[]},{"level":3,"title":"less","slug":"less","link":"#less","children":[]},{"level":3,"title":"evergreen","slug":"evergreen","link":"#evergreen","children":[]}]},{"level":2,"title":"常见问题","slug":"常见问题","link":"#常见问题","children":[{"level":3,"title":"在修改 base 后引用 Public 文件","slug":"在修改-base-后引用-public-文件","link":"#在修改-base-后引用-public-文件","children":[]},{"level":3,"title":"使用默认主题","slug":"使用默认主题","link":"#使用默认主题","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":2.13,"words":638},"filePathRelative":"zh/reference/bundler/webpack.md","localizedDate":"2023年2月22日","autoDesc":true}');export{e as data}; diff --git a/assets/webpack.html-bc54a5d7.js b/assets/webpack.html-bc54a5d7.js new file mode 100644 index 00000000..cae4f17c --- /dev/null +++ b/assets/webpack.html-bc54a5d7.js @@ -0,0 +1,11 @@ +import{_ as i,W as c,X as p,Y as s,$ as e,a0 as n,Z as d,a1 as o,D as l}from"./framework-46b0e263.js";const u={},h=e("h1",{id:"webpack",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#webpack","aria-hidden":"true"},"#"),n(" Webpack")],-1),_={href:"https://www.npmjs.com/package/@vuepress/bundler-webpack",target:"_blank",rel:"noopener noreferrer"},b={href:"https://www.npmjs.com/package/vuepress-webpack",target:"_blank",rel:"noopener noreferrer"},k=o(`npm i -D @vuepress/bundler-webpack@next +
# 配置项
Webpack 打包工具的配置项:
import { webpackBundler } from "@vuepress/bundler-webpack"; +import { defineUserConfig } from "@vuepress/cli"; + +export default defineUserConfig({ + bundler: webpackBundler({ + postcss: {}, + vue: {}, + }), +}); +
# configureWebpack
类型:
(config: WebpackConfiguration, isServer: boolean, isBuild: boolean) => WebpackConfiguration | void
详情:
用于修改内部的 Webpack 配置。
该配置项接收一个函数,该函数的第一个参数是 Webpack 配置对象,第二个参数是
isServer
标志位,第三个参数是isBuild
标志位。# chainWebpack
`,7),v=e("li",null,[e("p",null,[n("类型: "),e("code",null,"(config: WebpackChainConfig, isServer: boolean, isBuild: boolean) => void")])],-1),f=e("p",null,"详情:",-1),g={href:"https://github.com/mozilla-neutrino/webpack-chain",target:"_blank",rel:"noopener noreferrer"},m=e("p",null,[n("该配置项接收一个函数,该函数的第一个参数是由 "),e("code",null,"webpack-chain"),n(" 提供的 "),e("code",null,"Config"),n(" 实例,第二个参数是 "),e("code",null,"isServer"),n(" 标志位,第三个参数是 "),e("code",null,"isBuild"),n(" 标志位。")],-1),w=e("h3",{id:"devserversetupmiddlewares",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#devserversetupmiddlewares","aria-hidden":"true"},"#"),n(" devServerSetupMiddlewares")],-1),x=e("li",null,[e("p",null,[n("类型: "),e("code",null,"(middlewares: Middleware[], devServer: Server) => Middleware[]")])],-1),S=e("li",null,[e("p",null,"详情:"),e("p",null,[n("在 Webpack 的 "),e("code",null,"devServer.setupMiddlewares"),n(" 中调用的 Hook 。")]),e("p",null,[n("函数的参数即是 "),e("code",null,"devServer.setupMiddlewares"),n(" 的参数。")])],-1),y=e("p",null,"参考:",-1),W={href:"https://webpack.js.org/configuration/dev-server/#devserversetupmiddlewares",target:"_blank",rel:"noopener noreferrer"},B=e("h3",{id:"vue",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vue","aria-hidden":"true"},"#"),n(" vue")],-1),C=e("li",null,[e("p",null,[n("类型: "),e("code",null,"VueLoaderOptions")])],-1),L=e("li",null,[e("p",null,"详情:"),e("p",null,[e("code",null,"vue-loader"),n(" 的配置项。")])],-1),O=e("p",null,"参考:",-1),M={href:"https://vue-loader.vuejs.org/zh/options.html",target:"_blank",rel:"noopener noreferrer"},N=e("h3",{id:"postcss",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#postcss","aria-hidden":"true"},"#"),n(" postcss")],-1),V=e("li",null,[e("p",null,[n("类型: "),e("code",null,"PostcssLoaderOptions")])],-1),j=e("li",null,[e("p",null,"详情:"),e("p",null,[e("code",null,"postcss-loader"),n(" 的配置项。")])],-1),P=e("p",null,"参考:",-1),q={href:"https://github.com/webpack-contrib/postcss-loader#options",target:"_blank",rel:"noopener noreferrer"},z=e("h3",{id:"stylus",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#stylus","aria-hidden":"true"},"#"),n(" stylus")],-1),D=e("li",null,[e("p",null,[n("类型: "),e("code",null,"StylusLoaderOptions")])],-1),E=e("li",null,[e("p",null,"详情:"),e("p",null,[e("code",null,"stylus-loader"),n(" 的配置项。")])],-1),H=e("p",null,"参考:",-1),I={href:"https://github.com/webpack-contrib/stylus-loader#options",target:"_blank",rel:"noopener noreferrer"},R=e("h3",{id:"scss",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#scss","aria-hidden":"true"},"#"),n(" scss")],-1),U=e("li",null,[e("p",null,[n("类型: "),e("code",null,"SassLoaderOptions")])],-1),A=e("li",null,[e("p",null,"详情:"),e("p",null,[n("针对 "),e("code",null,".scss"),n(" 文件的 "),e("code",null,"sass-loader"),n(" 的配置项。")])],-1),T=e("p",null,"参考:",-1),X={href:"https://github.com/webpack-contrib/sass-loader#options",target:"_blank",rel:"noopener noreferrer"},Y=e("h3",{id:"sass",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#sass","aria-hidden":"true"},"#"),n(" sass")],-1),Z=e("li",null,[e("p",null,[n("类型: "),e("code",null,"SassLoaderOptions")])],-1),$=e("li",null,[e("p",null,"详情:"),e("p",null,[n("针对 "),e("code",null,".sass"),n(" 文件的 "),e("code",null,"sass-loader"),n(" 的配置项。")])],-1),F=e("p",null,"参考:",-1),G={href:"https://github.com/webpack-contrib/sass-loader#options",target:"_blank",rel:"noopener noreferrer"},J=e("h3",{id:"less",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#less","aria-hidden":"true"},"#"),n(" less")],-1),K=e("li",null,[e("p",null,[n("类型: "),e("code",null,"LessLoaderOptions")])],-1),Q=e("li",null,[e("p",null,"详情:"),e("p",null,[e("code",null,"less-loader"),n(" 的配置项。")])],-1),ee=e("p",null,"参考:",-1),ne={href:"https://github.com/webpack-contrib/less-loader#options",target:"_blank",rel:"noopener noreferrer"},se=o('# evergreen
类型:
boolean
默认值:
true
详情:
如果你的对象只有那些 “常青树” 浏览器,你可以将其设置成
true
。这将会禁用一些转译过程和 Polyfills ,带来更快的构建速度和更小的文件体积。# 常见问题
# 在修改
',4),ae=e("code",null,"base",-1),le=e("code",null,"base",-1),oe=e("h3",{id:"使用默认主题",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#使用默认主题","aria-hidden":"true"},"#"),n(" 使用默认主题")],-1),te={href:"https://sass-lang.com/",target:"_blank",rel:"noopener noreferrer"},re={href:"https://pnpm.io/",target:"_blank",rel:"noopener noreferrer"},ie={href:"https://www.npmjs.com/package/sass-loader",target:"_blank",rel:"noopener noreferrer"};function ce(pe,de){const t=l("NpmBadge"),a=l("ExternalLinkIcon"),r=l("RouterLink");return c(),p("div",null,[h,s(t,{package:"@vuepress/bundler-webpack"}),e("p",null,[n("Webpack 打包工具是由 "),e("a",_,[n("@vuepress/bundler-webpack"),s(a)]),n(" 包提供的。它是 "),e("a",b,[n("vuepress-webpack"),s(a)]),n(" 包的依赖之一,当然你也可以单独安装它:")]),k,e("ul",null,[v,e("li",null,[f,e("p",null,[n("通过 "),e("a",g,[n("webpack-chain"),s(a)]),n(" 来修改内部的 Webpack 配置。")]),m])]),w,e("ul",null,[x,S,e("li",null,[y,e("ul",null,[e("li",null,[e("a",W,[n("Webpack > Configuration > DevServer > devServer.setupMiddlewares"),s(a)])])])])]),B,e("ul",null,[C,L,e("li",null,[O,e("ul",null,[e("li",null,[e("a",M,[n("vue-loader > 选项参考"),s(a)])])])])]),N,e("ul",null,[V,j,e("li",null,[P,e("ul",null,[e("li",null,[e("a",q,[n("postcss-loader > Options"),s(a)])])])])]),z,e("ul",null,[D,E,e("li",null,[H,e("ul",null,[e("li",null,[e("a",I,[n("stylus-loader > Options"),s(a)])])])])]),R,e("ul",null,[U,A,e("li",null,[T,e("ul",null,[e("li",null,[e("a",X,[n("sass-loader > Options"),s(a)])])])])]),Y,e("ul",null,[Z,$,e("li",null,[F,e("ul",null,[e("li",null,[e("a",G,[n("sass-loader > Options"),s(a)])])])])]),J,e("ul",null,[K,Q,e("li",null,[ee,e("ul",null,[e("li",null,[e("a",ne,[n("less-loader > Options"),s(a)])])])])]),se,e("p",null,[n("与 Vite 不同, Webpack 不会为 Public 文件自动处理 "),ae,n("。因此如果你修改了网站的 "),le,n(",建议你在引用 Public 图片文件时使用 "),s(r,{to:"/zh/guide/assets.html#base-helper"},{default:d(()=>[n("Base Helper")]),_:1}),n("。")]),oe,e("p",null,[n("默认主题使用 "),e("a",te,[n("SASS"),s(a)]),n(" 作为 CSS 预处理器,因此你在使用 Webpack 时(特别是在使用 "),e("a",re,[n("pnpm"),s(a)]),n(" 时)可能需要手动安装 "),e("a",ie,[n("sass-loader"),s(a)]),n(" 来确保其正常工作。")])])}const he=i(u,[["render",ce],["__file","webpack.html.vue"]]);export{he as default}; diff --git a/assets/webpack.html-c03c48a3.js b/assets/webpack.html-c03c48a3.js new file mode 100644 index 00000000..4a34dd5b --- /dev/null +++ b/assets/webpack.html-c03c48a3.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-d4319af0","path":"/reference/bundler/webpack.html","title":"Webpack","lang":"en-US","frontmatter":{"icon":"mdi:webpack","description":"Webpack bundler is provided by @vuepress/bundler-webpack (https://www.npmjs.com/package/@vuepress/bundler-webpack) package. It is a dependency of the vuepress-webpack (https://w...","head":[["link",{"rel":"alternate","hreflang":"zh-cn","href":"https://vuejs.press/zh/reference/bundler/webpack.html"}],["meta",{"property":"og:url","content":"https://vuejs.press/reference/bundler/webpack.html"}],["meta",{"property":"og:site_name","content":"VuePress"}],["meta",{"property":"og:title","content":"Webpack"}],["meta",{"property":"og:description","content":"Webpack bundler is provided by @vuepress/bundler-webpack (https://www.npmjs.com/package/@vuepress/bundler-webpack) package. It is a dependency of the vuepress-webpack (https://w..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:locale","content":"en-US"}],["meta",{"property":"og:locale:alternate","content":"zh-CN"}],["meta",{"property":"og:updated_time","content":"2023-02-22T07:39:31.000Z"}],["meta",{"property":"article:modified_time","content":"2023-02-22T07:39:31.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"Webpack\\",\\"image\\":[\\"\\"],\\"dateModified\\":\\"2023-02-22T07:39:31.000Z\\",\\"author\\":[]}"]]},"headers":[{"level":2,"title":"Options","slug":"options","link":"#options","children":[{"level":3,"title":"configureWebpack","slug":"configurewebpack","link":"#configurewebpack","children":[]},{"level":3,"title":"chainWebpack","slug":"chainwebpack","link":"#chainwebpack","children":[]},{"level":3,"title":"devServerSetupMiddlewares","slug":"devserversetupmiddlewares","link":"#devserversetupmiddlewares","children":[]},{"level":3,"title":"vue","slug":"vue","link":"#vue","children":[]},{"level":3,"title":"postcss","slug":"postcss","link":"#postcss","children":[]},{"level":3,"title":"stylus","slug":"stylus","link":"#stylus","children":[]},{"level":3,"title":"scss","slug":"scss","link":"#scss","children":[]},{"level":3,"title":"sass","slug":"sass","link":"#sass","children":[]},{"level":3,"title":"less","slug":"less","link":"#less","children":[]},{"level":3,"title":"evergreen","slug":"evergreen","link":"#evergreen","children":[]}]},{"level":2,"title":"FAQ","slug":"faq","link":"#faq","children":[{"level":3,"title":"Referencing Public Files after Changing base","slug":"referencing-public-files-after-changing-base","link":"#referencing-public-files-after-changing-base","children":[]},{"level":3,"title":"Using with Default Theme","slug":"using-with-default-theme","link":"#using-with-default-theme","children":[]}]}],"git":{"createdTime":1677051571000,"updatedTime":1677051571000,"contributors":[{"name":"Mr.Hope","email":"mister-hope@outlook.com","commits":1}]},"readingTime":{"minutes":1.68,"words":504},"filePathRelative":"reference/bundler/webpack.md","localizedDate":"February 22, 2023","autoDesc":true}');export{e as data}; diff --git a/assets/webpack.html-c223bdb5.js b/assets/webpack.html-c223bdb5.js new file mode 100644 index 00000000..5b56d96d --- /dev/null +++ b/assets/webpack.html-c223bdb5.js @@ -0,0 +1,11 @@ +import{_ as r,W as c,X as p,Y as s,$ as e,a0 as n,Z as u,a1 as t,D as l}from"./framework-46b0e263.js";const d={},h=e("h1",{id:"webpack",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#webpack","aria-hidden":"true"},"#"),n(" Webpack")],-1),_={href:"https://www.npmjs.com/package/@vuepress/bundler-webpack",target:"_blank",rel:"noopener noreferrer"},b={href:"https://www.npmjs.com/package/vuepress-webpack",target:"_blank",rel:"noopener noreferrer"},f=t(`base
后引用 Public 文件npm i -D @vuepress/bundler-webpack@next +
# Options
Reference of webpack bundler options:
import { webpackBundler } from "@vuepress/bundler-webpack"; +import { defineUserConfig } from "@vuepress/cli"; + +export default defineUserConfig({ + bundler: webpackBundler({ + postcss: {}, + vue: {}, + }), +}); +
# configureWebpack
`,5),k=e("li",null,[e("p",null,[n("Type: "),e("code",null,"(config: WebpackConfiguration, isServer: boolean, isBuild: boolean) => WebpackConfiguration | void")])],-1),g=e("p",null,"Details:",-1),v=e("p",null,"Edit the internal webpack config.",-1),m=e("code",null,"isServer",-1),w=e("code",null,"isBuild",-1),y={href:"https://github.com/survivejs/webpack-merge",target:"_blank",rel:"noopener noreferrer"},x=e("h3",{id:"chainwebpack",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#chainwebpack","aria-hidden":"true"},"#"),n(" chainWebpack")],-1),S=e("li",null,[e("p",null,[n("Type: "),e("code",null,"(config: WebpackChainConfig, isServer: boolean, isBuild: boolean) => void")])],-1),O=e("p",null,"Details:",-1),D={href:"https://github.com/mozilla-neutrino/webpack-chain",target:"_blank",rel:"noopener noreferrer"},T=e("p",null,[n("This option accepts a function that will receive a "),e("code",null,"Config"),n(" instance that provided by "),e("code",null,"webpack-chain"),n(" as the 1st argument an "),e("code",null,"isServer"),n(" flag as the 2nd argument and an "),e("code",null,"isBuild"),n(" flag as the 3rd argument.")],-1),B=e("h3",{id:"devserversetupmiddlewares",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#devserversetupmiddlewares","aria-hidden":"true"},"#"),n(" devServerSetupMiddlewares")],-1),C=e("li",null,[e("p",null,[n("Type: "),e("code",null,"(middlewares: Middleware[], devServer: Server) => Middleware[]")])],-1),L=e("li",null,[e("p",null,"Details:"),e("p",null,[n("A hook to be called in "),e("code",null,"devServer.setupMiddlewares"),n(" of webpack.")]),e("p",null,[n("The arguments of the function are those of "),e("code",null,"devServer.setupMiddlewares"),n(".")])],-1),W=e("p",null,"Also see:",-1),A={href:"https://webpack.js.org/configuration/dev-server/#devserversetupmiddlewares",target:"_blank",rel:"noopener noreferrer"},j=e("h3",{id:"vue",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vue","aria-hidden":"true"},"#"),n(" vue")],-1),q=e("li",null,[e("p",null,[n("Type: "),e("code",null,"VueLoaderOptions")])],-1),M=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Options for "),e("code",null,"vue-loader"),n(".")])],-1),N=e("p",null,"Also see:",-1),V={href:"https://vue-loader.vuejs.org/options.html",target:"_blank",rel:"noopener noreferrer"},E=e("h3",{id:"postcss",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#postcss","aria-hidden":"true"},"#"),n(" postcss")],-1),R=e("li",null,[e("p",null,[n("Type: "),e("code",null,"PostcssLoaderOptions")])],-1),U=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Options for "),e("code",null,"postcss-loader"),n(".")])],-1),I=e("p",null,"Also see:",-1),F={href:"https://github.com/webpack-contrib/postcss-loader#options",target:"_blank",rel:"noopener noreferrer"},P=e("h3",{id:"stylus",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#stylus","aria-hidden":"true"},"#"),n(" stylus")],-1),Y=e("li",null,[e("p",null,[n("Type: "),e("code",null,"StylusLoaderOptions")])],-1),z=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Options for "),e("code",null,"stylus-loader"),n(".")])],-1),H=e("p",null,"Also see:",-1),Q={href:"https://github.com/webpack-contrib/stylus-loader#options",target:"_blank",rel:"noopener noreferrer"},X=e("h3",{id:"scss",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#scss","aria-hidden":"true"},"#"),n(" scss")],-1),Z=e("li",null,[e("p",null,[n("Type: "),e("code",null,"SassLoaderOptions")])],-1),$=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Options for "),e("code",null,"sass-loader"),n(" for "),e("code",null,".scss"),n(" files.")])],-1),G=e("p",null,"Also see:",-1),J={href:"https://github.com/webpack-contrib/sass-loader#options",target:"_blank",rel:"noopener noreferrer"},K=e("h3",{id:"sass",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#sass","aria-hidden":"true"},"#"),n(" sass")],-1),ee=e("li",null,[e("p",null,[n("Type: "),e("code",null,"SassLoaderOptions")])],-1),ne=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Options for "),e("code",null,"sass-loader"),n(" for "),e("code",null,".sass"),n(" files.")])],-1),se=e("p",null,"Also see:",-1),ae={href:"https://github.com/webpack-contrib/sass-loader#options",target:"_blank",rel:"noopener noreferrer"},le=e("h3",{id:"less",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#less","aria-hidden":"true"},"#"),n(" less")],-1),te=e("li",null,[e("p",null,[n("Type: "),e("code",null,"LessLoaderOptions")])],-1),oe=e("li",null,[e("p",null,"Details:"),e("p",null,[n("Options for "),e("code",null,"less-loader"),n(".")])],-1),ie=e("p",null,"Also see:",-1),re={href:"https://github.com/webpack-contrib/less-loader#options",target:"_blank",rel:"noopener noreferrer"},ce=t('# evergreen
Type:
boolean
Default:
true
Details:
Set to
true
if you are only targeting evergreen browsers. This will disable some transpilation and polyfills, and result in faster builds and smaller files.# FAQ
# Referencing Public Files after Changing
',4),pe=e("code",null,"base",-1),ue=e("code",null,"base",-1),de=e("h3",{id:"using-with-default-theme",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#using-with-default-theme","aria-hidden":"true"},"#"),n(" Using with Default Theme")],-1),he={href:"https://sass-lang.com/",target:"_blank",rel:"noopener noreferrer"},_e={href:"https://www.npmjs.com/package/sass-loader",target:"_blank",rel:"noopener noreferrer"},be={href:"https://pnpm.io/",target:"_blank",rel:"noopener noreferrer"};function fe(ke,ge){const o=l("NpmBadge"),a=l("ExternalLinkIcon"),i=l("RouterLink");return c(),p("div",null,[h,s(o,{package:"@vuepress/bundler-webpack"}),e("p",null,[n("Webpack bundler is provided by "),e("a",_,[n("@vuepress/bundler-webpack"),s(a)]),n(" package. It is a dependency of the "),e("a",b,[n("vuepress-webpack"),s(a)]),n(" package, and you can also install it separately.")]),f,e("ul",null,[k,e("li",null,[g,v,e("p",null,[n("This option accepts a function that will receive a webpack config object as the 1st argument, an "),m,n(" flag as the 2nd argument and an "),w,n(" flag as the 3rd argument. You can either mutate the config directly, or return an object to be merged by "),e("a",y,[n("webpack-merge"),s(a)]),n(".")])])]),x,e("ul",null,[S,e("li",null,[O,e("p",null,[n("Edit the internal webpack config with "),e("a",D,[n("webpack-chain"),s(a)]),n(".")]),T])]),B,e("ul",null,[C,L,e("li",null,[W,e("ul",null,[e("li",null,[e("a",A,[n("Webpack > Configuration > DevServer > devServer.setupMiddlewares"),s(a)])])])])]),j,e("ul",null,[q,M,e("li",null,[N,e("ul",null,[e("li",null,[e("a",V,[n("vue-loader > Options Reference"),s(a)])])])])]),E,e("ul",null,[R,U,e("li",null,[I,e("ul",null,[e("li",null,[e("a",F,[n("postcss-loader > Options"),s(a)])])])])]),P,e("ul",null,[Y,z,e("li",null,[H,e("ul",null,[e("li",null,[e("a",Q,[n("stylus-loader > Options"),s(a)])])])])]),X,e("ul",null,[Z,$,e("li",null,[G,e("ul",null,[e("li",null,[e("a",J,[n("sass-loader > Options"),s(a)])])])])]),K,e("ul",null,[ee,ne,e("li",null,[se,e("ul",null,[e("li",null,[e("a",ae,[n("sass-loader > Options"),s(a)])])])])]),le,e("ul",null,[te,oe,e("li",null,[ie,e("ul",null,[e("li",null,[e("a",re,[n("less-loader > Options"),s(a)])])])])]),ce,e("p",null,[n("Unlike Vite, Webpack won't handle "),pe,n(" for public files automatically. So if you change the "),ue,n(" of your site, you'd better to use "),s(i,{to:"/guide/assets.html#base-helper"},{default:u(()=>[n("Base Helper")]),_:1}),n(" when referencing an public image file.")]),de,e("p",null,[n("Default theme is using "),e("a",he,[n("SASS"),s(a)]),n(" as CSS pre-processor, so you might need to install "),e("a",_e,[n("sass-loader"),s(a)]),n(" as a peer dependency to make it work with Webpack, especially when you are using "),e("a",be,[n("pnpm"),s(a)]),n(".")])])}const me=r(d,[["render",fe],["__file","webpack.html.vue"]]);export{me as default}; diff --git a/contributing.html b/contributing.html new file mode 100644 index 00000000..992e4f13 --- /dev/null +++ b/contributing.html @@ -0,0 +1,43 @@ + + + + + + + +base
Contributing Guide | VuePress + + + + + + + + + + diff --git a/docs/.vuepress/components/NpmBadge.vue b/docs/.vuepress/components/NpmBadge.vue deleted file mode 100644 index 171047f3..00000000 --- a/docs/.vuepress/components/NpmBadge.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - - -- - - - diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts deleted file mode 100644 index 5edd8485..00000000 --- a/docs/.vuepress/config.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { createRequire } from 'node:module' -import process from 'node:process' -import { viteBundler } from '@vuepress/bundler-vite' -import { webpackBundler } from '@vuepress/bundler-webpack' -import { docsearchPlugin } from '@vuepress/plugin-docsearch' -import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' -import { registerComponentsPlugin } from '@vuepress/plugin-register-components' -import { shikiPlugin } from '@vuepress/plugin-shiki' -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' -import { getDirname, path } from 'vuepress/utils' -import { - head, - navbarEn, - navbarZh, - sidebarEn, - sidebarZh, -} from './configs/index.js' - -const __dirname = getDirname(import.meta.url) -const require = createRequire(import.meta.url) -const isProd = process.env.NODE_ENV === 'production' - -export default defineUserConfig({ - // set site base to default value - base: '/', - - // extra tags in `` - head, - - // site-level locales config - locales: { - '/': { - lang: 'en-US', - title: 'VuePress', - description: 'Vue-powered Static Site Generator', - }, - '/zh/': { - lang: 'zh-CN', - title: 'VuePress', - description: 'Vue 驱动的静态网站生成器', - }, - }, - - // specify bundler via environment variable - bundler: - process.env.DOCS_BUNDLER === 'webpack' ? webpackBundler() : viteBundler(), - - // configure default theme - theme: defaultTheme({ - hostname: 'https://vuepress.vuejs.org', - logo: '/images/hero.png', - repo: 'vuepress/core', - docsRepo: 'vuepress/docs', - docsDir: 'docs', - - // theme-level locales config - locales: { - /** - * English locale config - * - * As the default locale of @vuepress/theme-default is English, - * we don't need to set all of the locale fields - */ - '/': { - // navbar - navbar: navbarEn, - // sidebar - sidebar: sidebarEn, - // page meta - editLinkText: 'Edit this page on GitHub', - }, - - /** - * Chinese locale config - */ - '/zh/': { - // navbar - navbar: navbarZh, - selectLanguageName: '简体中文', - selectLanguageText: '选择语言', - selectLanguageAriaLabel: '选择语言', - // sidebar - sidebar: sidebarZh, - // page meta - editLinkText: '在 GitHub 上编辑此页', - lastUpdatedText: '上次更新', - contributorsText: '贡献者', - // custom containers - tip: '提示', - warning: '注意', - danger: '警告', - // 404 page - notFound: [ - '这里什么都没有', - '我们怎么到这来了?', - '这是一个 404 页面', - '看起来我们进入了错误的链接', - ], - backToHome: '返回首页', - // a11y - openInNewWindow: '在新窗口打开', - toggleColorMode: '切换颜色模式', - toggleSidebar: '切换侧边栏', - }, - }, - - themePlugins: { - // only enable git plugin in production mode - git: isProd, - // use shiki plugin in production mode instead - prismjs: !isProd, - }, - }), - - // configure markdown - markdown: { - importCode: { - handleImportPath: (importPath) => { - // handle @vuepress packages import path - if (importPath.startsWith('@vuepress/')) { - const packageName = importPath.match(/^(@vuepress\/[^/]*)/)![1] - return importPath - .replace( - packageName, - path.dirname(require.resolve(`${packageName}/package.json`)), - ) - .replace('/src/', '/lib/') - .replace(/hotKey\.ts$/, 'hotKey.d.ts') - } - return importPath - }, - }, - }, - - // use plugins - plugins: [ - docsearchPlugin({ - appId: '34YFD9IUQ2', - apiKey: '9a9058b8655746634e01071411c366b8', - indexName: 'vuepress', - searchParameters: { - facetFilters: ['tags:v2'], - }, - locales: { - '/zh/': { - placeholder: '搜索文档', - translations: { - button: { - buttonText: '搜索文档', - buttonAriaLabel: '搜索文档', - }, - modal: { - searchBox: { - resetButtonTitle: '清除查询条件', - resetButtonAriaLabel: '清除查询条件', - cancelButtonText: '取消', - cancelButtonAriaLabel: '取消', - }, - startScreen: { - recentSearchesTitle: '搜索历史', - noRecentSearchesText: '没有搜索历史', - saveRecentSearchButtonTitle: '保存至搜索历史', - removeRecentSearchButtonTitle: '从搜索历史中移除', - favoriteSearchesTitle: '收藏', - removeFavoriteSearchButtonTitle: '从收藏中移除', - }, - errorScreen: { - titleText: '无法获取结果', - helpText: '你可能需要检查你的网络连接', - }, - footer: { - selectText: '选择', - navigateText: '切换', - closeText: '关闭', - searchByText: '搜索提供者', - }, - noResultsScreen: { - noResultsText: '无法找到相关结果', - suggestedQueryText: '你可以尝试查询', - reportMissingResultsText: '你认为该查询应该有结果?', - reportMissingResultsLinkText: '点击反馈', - }, - }, - }, - }, - }, - }), - googleAnalyticsPlugin({ - // we have multiple deployments, which would use different id - id: process.env.DOCS_GA_ID ?? '', - }), - registerComponentsPlugin({ - componentsDir: path.resolve(__dirname, './components'), - }), - // only enable shiki plugin in production mode - isProd - ? shikiPlugin({ - langs: ['bash', 'diff', 'json', 'md', 'ts', 'vue'], - theme: 'dark-plus', - }) - : [], - ], -}) diff --git a/docs/.vuepress/configs/head.ts b/docs/.vuepress/configs/head.ts deleted file mode 100644 index 0d45b078..00000000 --- a/docs/.vuepress/configs/head.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { HeadConfig } from 'vuepress/core' - -// eslint-disable-next-line @typescript-eslint/naming-convention -export const head: HeadConfig[] = [ - [ - 'link', - { - rel: 'icon', - type: 'image/png', - sizes: '16x16', - href: `/images/icons/favicon-16x16.png`, - }, - ], - [ - 'link', - { - rel: 'icon', - type: 'image/png', - sizes: '32x32', - href: `/images/icons/favicon-32x32.png`, - }, - ], - ['link', { rel: 'manifest', href: '/manifest.webmanifest' }], - ['meta', { name: 'application-name', content: 'VuePress' }], - ['meta', { name: 'apple-mobile-web-app-title', content: 'VuePress' }], - ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }], - [ - 'link', - { rel: 'apple-touch-icon', href: `/images/icons/apple-touch-icon.png` }, - ], - [ - 'link', - { - rel: 'mask-icon', - href: '/images/icons/safari-pinned-tab.svg', - color: '#3eaf7c', - }, - ], - ['meta', { name: 'msapplication-TileColor', content: '#3eaf7c' }], - ['meta', { name: 'theme-color', content: '#3eaf7c' }], -] diff --git a/docs/.vuepress/configs/index.ts b/docs/.vuepress/configs/index.ts deleted file mode 100644 index b23dc923..00000000 --- a/docs/.vuepress/configs/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './head.js' -export * from './navbar/index.js' -export * from './sidebar/index.js' diff --git a/docs/.vuepress/configs/meta.ts b/docs/.vuepress/configs/meta.ts deleted file mode 100644 index 3b89a465..00000000 --- a/docs/.vuepress/configs/meta.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createRequire } from 'node:module' -import { fs } from 'vuepress/utils' - -const require = createRequire(import.meta.url) - -export const VERSION = ( - fs.readJsonSync(require.resolve('vuepress/package.json')) as { - version: string - } -).version diff --git a/docs/.vuepress/configs/navbar/en.ts b/docs/.vuepress/configs/navbar/en.ts deleted file mode 100644 index adc22769..00000000 --- a/docs/.vuepress/configs/navbar/en.ts +++ /dev/null @@ -1,117 +0,0 @@ -import type { NavbarOptions } from '@vuepress/theme-default' -import { VERSION } from '../meta.js' - -export const navbarEn: NavbarOptions = [ - { - text: 'Guide', - children: [ - '/guide/introduction.md', - '/guide/getting-started.md', - '/guide/configuration.md', - '/guide/page.md', - '/guide/markdown.md', - '/guide/assets.md', - '/guide/i18n.md', - '/guide/deployment.md', - '/guide/theme.md', - '/guide/plugin.md', - '/guide/bundler.md', - '/guide/migration.md', - '/guide/troubleshooting.md', - ], - }, - { - text: 'Reference', - children: [ - { - text: 'Core', - children: [ - { - text: 'CLI', - link: '/reference/cli.html', - }, - '/reference/config.md', - '/reference/frontmatter.md', - '/reference/components.md', - '/reference/plugin-api.md', - '/reference/theme-api.md', - '/reference/client-api.md', - '/reference/node-api.md', - ], - }, - { - text: 'Bundlers', - children: [ - '/reference/bundler/vite.md', - '/reference/bundler/webpack.md', - ], - }, - { - text: 'Ecosystem', - children: [ - { - text: 'Default Theme', - link: 'https://ecosystem.vuejs.press/themes/default/', - }, - { - text: 'Plugins', - link: 'https://ecosystem.vuejs.press/plugins/', - }, - ], - }, - ], - }, - - { - text: 'Learn More', - children: [ - { - text: 'Advanced', - children: [ - '/advanced/architecture.md', - '/advanced/plugin.md', - '/advanced/theme.md', - { - text: 'Cookbook', - link: '/advanced/cookbook/', - }, - ], - }, - { - text: 'Resources', - children: [ - { - text: 'Ecosystem', - link: 'https://ecosystem.vuejs.press/', - }, - { - text: 'MarketPlace', - link: 'https://marketplace.vuejs.press', - }, - { - text: 'Contributing Guide', - link: 'https://github.com/vuepress/core/blob/main/CONTRIBUTING.md', - }, - ], - }, - ], - }, - { - text: `v${VERSION}`, - children: [ - { - text: 'Changelog', - link: 'https://github.com/vuepress/core/blob/main/CHANGELOG.md', - }, - { - text: 'v1.x', - link: 'https://v1.vuepress.vuejs.org', - }, - { - text: 'v0.x', - link: 'https://v0.vuepress.vuejs.org', - }, - ], - }, - // TODO: remove the type assertion -] as NavbarOptions diff --git a/docs/.vuepress/configs/navbar/index.ts b/docs/.vuepress/configs/navbar/index.ts deleted file mode 100644 index 7183393c..00000000 --- a/docs/.vuepress/configs/navbar/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './en.js' -export * from './zh.js' diff --git a/docs/.vuepress/configs/navbar/zh.ts b/docs/.vuepress/configs/navbar/zh.ts deleted file mode 100644 index 47a3d994..00000000 --- a/docs/.vuepress/configs/navbar/zh.ts +++ /dev/null @@ -1,113 +0,0 @@ -import type { NavbarOptions } from '@vuepress/theme-default' -import { VERSION } from '../meta.js' - -export const navbarZh: NavbarOptions = [ - { - text: '指南', - children: [ - '/zh/guide/introduction.md', - '/zh/guide/getting-started.md', - '/zh/guide/configuration.md', - '/zh/guide/page.md', - '/zh/guide/markdown.md', - '/zh/guide/assets.md', - '/zh/guide/i18n.md', - '/zh/guide/deployment.md', - '/zh/guide/theme.md', - '/zh/guide/plugin.md', - '/zh/guide/bundler.md', - '/zh/guide/migration.md', - '/zh/guide/troubleshooting.md', - ], - }, - { - text: '参考', - children: [ - { - text: '核心', - children: [ - '/zh/reference/cli.md', - '/zh/reference/config.md', - '/zh/reference/frontmatter.md', - '/zh/reference/components.md', - '/zh/reference/plugin-api.md', - '/zh/reference/theme-api.md', - '/zh/reference/client-api.md', - '/zh/reference/node-api.md', - ], - }, - { - text: '打包工具', - children: [ - '/zh/reference/bundler/vite.md', - '/zh/reference/bundler/webpack.md', - ], - }, - { - text: '生态系统', - children: [ - { - text: '默认主题', - link: 'https://ecosystem.vuejs.press/zh/themes/default/', - }, - { - text: '插件', - link: 'https://ecosystem.vuejs.press/zh/plugins/', - }, - ], - }, - ], - }, - { - text: '了解更多', - children: [ - { - text: '深入', - children: [ - '/zh/advanced/architecture.md', - '/zh/advanced/plugin.md', - '/zh/advanced/theme.md', - { - text: 'Cookbook', - link: '/zh/advanced/cookbook/', - }, - ], - }, - { - text: '其他资源', - children: [ - { - text: '生态系统', - link: 'https://ecosystem.vuejs.press/zh/', - }, - { - text: '市场', - link: 'https://marketplace.vuejs.press/zh/', - }, - { - text: '贡献指南', - link: 'https://github.com/vuepress/core/blob/main/CONTRIBUTING_zh.md', - }, - ], - }, - ], - }, - { - text: `v${VERSION}`, - children: [ - { - text: '更新日志', - link: 'https://github.com/vuepress/core/blob/main/CHANGELOG.md', - }, - { - text: 'v1.x', - link: 'https://v1.vuepress.vuejs.org/zh/', - }, - { - text: 'v0.x', - link: 'https://v0.vuepress.vuejs.org/zh/', - }, - ], - }, - // TODO: remove the type assertion -] as NavbarOptions diff --git a/docs/.vuepress/configs/sidebar/en.ts b/docs/.vuepress/configs/sidebar/en.ts deleted file mode 100644 index 387003b7..00000000 --- a/docs/.vuepress/configs/sidebar/en.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { SidebarOptions } from '@vuepress/theme-default' - -export const sidebarEn: SidebarOptions = { - '/guide/': [ - { - text: 'Guide', - children: [ - '/guide/introduction.md', - '/guide/getting-started.md', - '/guide/configuration.md', - '/guide/page.md', - '/guide/markdown.md', - '/guide/assets.md', - '/guide/i18n.md', - '/guide/deployment.md', - '/guide/theme.md', - '/guide/plugin.md', - '/guide/bundler.md', - '/guide/migration.md', - '/guide/troubleshooting.md', - ], - }, - ], - '/advanced/': [ - { - text: 'Advanced', - children: [ - '/advanced/architecture.md', - '/advanced/plugin.md', - '/advanced/theme.md', - ], - }, - { - text: 'Cookbook', - children: [ - '/advanced/cookbook/README.md', - '/advanced/cookbook/usage-of-client-config.md', - '/advanced/cookbook/adding-extra-pages.md', - '/advanced/cookbook/making-a-theme-extendable.md', - '/advanced/cookbook/passing-data-to-client-code.md', - '/advanced/cookbook/markdown-and-vue-sfc.md', - '/advanced/cookbook/resolving-routes.md', - ], - }, - ], - '/reference/': [ - { - text: 'Core', - collapsible: true, - children: [ - '/reference/cli.md', - '/reference/config.md', - '/reference/frontmatter.md', - '/reference/components.md', - '/reference/plugin-api.md', - '/reference/theme-api.md', - '/reference/client-api.md', - '/reference/node-api.md', - ], - }, - { - text: 'Bundlers', - children: ['/reference/bundler/vite.md', '/reference/bundler/webpack.md'], - }, - { - text: 'Ecosystem', - children: [ - { - text: 'Default Theme', - link: 'https://ecosystem.vuejs.press/themes/default/', - }, - { - text: 'Plugins', - link: 'https://ecosystem.vuejs.press/plugins/', - }, - ], - }, - ], -} diff --git a/docs/.vuepress/configs/sidebar/index.ts b/docs/.vuepress/configs/sidebar/index.ts deleted file mode 100644 index 7183393c..00000000 --- a/docs/.vuepress/configs/sidebar/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './en.js' -export * from './zh.js' diff --git a/docs/.vuepress/configs/sidebar/zh.ts b/docs/.vuepress/configs/sidebar/zh.ts deleted file mode 100644 index 3955f70c..00000000 --- a/docs/.vuepress/configs/sidebar/zh.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { SidebarOptions } from '@vuepress/theme-default' - -export const sidebarZh: SidebarOptions = { - '/zh/guide/': [ - { - text: '指南', - children: [ - '/zh/guide/introduction.md', - '/zh/guide/getting-started.md', - '/zh/guide/configuration.md', - '/zh/guide/page.md', - '/zh/guide/markdown.md', - '/zh/guide/assets.md', - '/zh/guide/i18n.md', - '/zh/guide/deployment.md', - '/zh/guide/theme.md', - '/zh/guide/plugin.md', - '/zh/guide/bundler.md', - '/zh/guide/migration.md', - '/zh/guide/troubleshooting.md', - ], - }, - ], - '/zh/advanced/': [ - { - text: '深入', - children: [ - '/zh/advanced/architecture.md', - '/zh/advanced/plugin.md', - '/zh/advanced/theme.md', - ], - }, - { - text: 'Cookbook', - children: [ - '/zh/advanced/cookbook/README.md', - '/zh/advanced/cookbook/usage-of-client-config.md', - '/zh/advanced/cookbook/adding-extra-pages.md', - '/zh/advanced/cookbook/making-a-theme-extendable.md', - '/zh/advanced/cookbook/passing-data-to-client-code.md', - '/zh/advanced/cookbook/markdown-and-vue-sfc.md', - '/zh/advanced/cookbook/resolving-routes.md', - ], - }, - ], - '/zh/reference/': [ - { - text: '核心', - collapsible: true, - children: [ - '/zh/reference/cli.md', - '/zh/reference/config.md', - '/zh/reference/frontmatter.md', - '/zh/reference/components.md', - '/zh/reference/plugin-api.md', - '/zh/reference/theme-api.md', - '/zh/reference/client-api.md', - '/zh/reference/node-api.md', - ], - }, - { - text: '打包工具', - children: [ - '/zh/reference/bundler/vite.md', - '/zh/reference/bundler/webpack.md', - ], - }, - { - text: '生态系统', - children: [ - { - text: '默认主题', - link: 'https://ecosystem.vuejs.press/zh/themes/default/', - }, - { - text: '插件', - link: 'https://ecosystem.vuejs.press/zh/plugins/', - }, - ], - }, - ], -} diff --git a/docs/.vuepress/public/browserconfig.xml b/docs/.vuepress/public/browserconfig.xml deleted file mode 100644 index 5bdd109f..00000000 --- a/docs/.vuepress/public/browserconfig.xml +++ /dev/null @@ -1,9 +0,0 @@ - -
- diff --git a/docs/.vuepress/public/images/guide/vuepress-architecture-overview.png b/docs/.vuepress/public/images/guide/vuepress-architecture-overview.png deleted file mode 100644 index 572bf1a4..00000000 Binary files a/docs/.vuepress/public/images/guide/vuepress-architecture-overview.png and /dev/null differ diff --git a/docs/.vuepress/public/new.html b/docs/.vuepress/public/new.html deleted file mode 100644 index b83ab7cb..00000000 --- a/docs/.vuepress/public/new.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/docs/.vuepress/styles/index.scss b/docs/.vuepress/styles/index.scss deleted file mode 100644 index 9eed395a..00000000 --- a/docs/.vuepress/styles/index.scss +++ /dev/null @@ -1,14 +0,0 @@ -:root { - scroll-behavior: smooth; -} - -@media (min-width: 751px) { - #docsearch-container:lang(zh-CN) { - min-width: 184.66px; - } -} - -// FIXME: Workaround solution -div[class*='language-'] pre code { - color: var(--code-c-text); -} diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 4b49d110..00000000 --- a/docs/README.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -home: true -title: Home -heroImage: /images/hero.png -actions: - - text: Get Started - link: /guide/getting-started.html - type: primary - - - text: Introduction - link: /guide/introduction.html - type: secondary - -features: - - title: Simplicity First - details: Minimal setup with markdown-centered project structure helps you focus on writing. - - - title: Vue-Powered - details: Enjoy the dev experience of Vue, use Vue components in markdown, and develop custom themes with Vue. - - - title: Performant - details: VuePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded. - - - title: Themes - details: Providing a default theme out of the box. You can also choose a community theme or create your own one. - - - title: Plugins - details: Flexible plugin API, allowing plugins to provide lots of plug-and-play features for your site. - - - title: Bundlers - details: Recommended bundler is Vite, while Webpack is also supported. Choose the one you like! - -footer: MIT Licensed | Copyright © 2018-present VuePress Community ---- diff --git a/docs/advanced/architecture.md b/docs/advanced/architecture.md deleted file mode 100644 index 0a3ecdbe..00000000 --- a/docs/advanced/architecture.md +++ /dev/null @@ -1,36 +0,0 @@ -# Architecture - -## Overview - - - -The above figure shows a brief overview of the VuePress architecture: - -- Node App will generate temp files, including the pages, routes, etc. -- Bundler will handle Client App together with the temp files, just like a common Vue app. - -As a developer, you must be aware of that VuePress has two main parts: **Node App** and **Client App**, which is important when developing plugins and themes: - -- The entry file of a plugin or a theme will be loaded in Node App. -- Client files will be loaded in Client App, which will be handled by bundler. For example, components, client config files, etc. - -## Core Process and Hooks - - - -The above figure shows the core process of VuePress Node App and the hooks of [Plugin API](../reference/plugin-api.md): - -- In the **init** stage: - - Theme and plugins will be loaded. That means all the plugins should be used before initialization. - - As we are using markdown-it to parse the markdown file, so we need to create markdown-it instance before loading pages: - - [extendsMarkdownOptions](../reference/plugin-api.md#extendsmarkdownoptions) hook will be processed to create markdown-it instance. - - [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) hook will be processed extends markdown-it instance. - - Page files will be loaded: - - [extendsPageOptions](../reference/plugin-api.md#extendspageoptions) hook will be processed to create pages. - - [extendsPage](../reference/plugin-api.md#extendspage) hook will be processed to extends page object. -- In the **prepare** stage: - - Temp files will be generated, so all hooks related to client files will be processed here. -- In the **dev / build** stage: - - Bundler will be resolved: - - [extendsBundlerOptions](../reference/plugin-api.md#extendsbundleroptions) hook will be processed to create bundler configuration. - - [alias](../reference/plugin-api.md#alias) hook and [define](../reference/plugin-api.md#define) hook would be used in bundler configuration, so they will be processed here. diff --git a/docs/advanced/cookbook/README.md b/docs/advanced/cookbook/README.md deleted file mode 100644 index da53257d..00000000 --- a/docs/advanced/cookbook/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Introduction - -## What's the Cookbook for? - -- We are introducing essential concepts in the **Guide**, but you may not know how to dig deeper. -- We are listing APIs in the **Reference**, but you may not know how to take full advantage of them. - -So here comes the Cookbook. - -Each recipe will focus on one specific aspect, providing more detailed examples to show you the usages and possibilities of VuePress. diff --git a/docs/advanced/cookbook/adding-extra-pages.md b/docs/advanced/cookbook/adding-extra-pages.md deleted file mode 100644 index 9dc5ada9..00000000 --- a/docs/advanced/cookbook/adding-extra-pages.md +++ /dev/null @@ -1,38 +0,0 @@ -# Adding Extra Pages - -Sometimes you might want to add some extra pages without creating a markdown file in the source directory. - -With the help of [Plugin API](../../reference/plugin-api.md) and [Node API](../../reference/node-api.md), we can do that with ease. - -## Add a Default Homepage - -As a theme author, you may not require users to create a `/README.md` file as the homepage, but you want to provide a default one: - -```ts -import { createPage } from 'vuepress/core' - -export default { - // all pages have been loaded after initialization - async onInitialized(app) { - // if the homepage does not exist - if (app.pages.every((page) => page.path !== '/')) { - // create a homepage - const homepage = await createPage(app, { - path: '/', - // set frontmatter - frontmatter: { - layout: 'Layout', - }, - // set markdown content - content: `\ -# Welcome to ${app.options.title} - -This is the default homepage -`, - }) - // add it to `app.pages` - app.pages.push(homepage) - } - }, -} -``` diff --git a/docs/advanced/cookbook/making-a-theme-extendable.md b/docs/advanced/cookbook/making-a-theme-extendable.md deleted file mode 100644 index c14ee0c7..00000000 --- a/docs/advanced/cookbook/making-a-theme-extendable.md +++ /dev/null @@ -1,64 +0,0 @@ -# Making a Theme Extendable - -Sometimes users might want make some minor changes to a theme, but they don't want to fork and modify the entire project. - -With the help of [Theme API](../../reference/theme-api.md), you can make your theme extendable, allowing users to make their own modifications easily. - -You must have known that how to [extend default theme](https://ecosystem.vuejs.press/themes/default/extending.html). Here we'll introduce how to make your own theme extendable like default theme. - -## Layout Slots - -This approach requires you to determine which parts of your theme could be extended. It is more suitable for those common customizations like page footer or header. - -You just need to provide slots in your layouts, and tell users how to make use of them: - -```vue - -- -- -- #ffffff --- -``` - -## Component Aliases - -This approach requires you to consider which components of your theme should be replaceable, and you also need to split components into a suitable granularity. - -First, set `alias` for replaceable components of you theme: - -```ts -import type { Theme } from 'vuepress/core' -import { getDirname } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export const fooTheme = (options): Theme => ({ - name: 'vuepress-theme-foo', - alias: { - // set alias for replaceable components - '@theme/Navbar.vue': path.resolve(__dirname, 'components/Navbar.vue'), - '@theme/Sidebar.vue': path.resolve(__dirname, 'components/Sidebar.vue'), - }, -}) -``` - -Next, use those components via aliases in your theme: - -```vue - - - -- - - -- -``` - -Then, users can replace specific components by overriding the `alias` when extending or using your theme. diff --git a/docs/advanced/cookbook/markdown-and-vue-sfc.md b/docs/advanced/cookbook/markdown-and-vue-sfc.md deleted file mode 100644 index 4fec769f..00000000 --- a/docs/advanced/cookbook/markdown-and-vue-sfc.md +++ /dev/null @@ -1,80 +0,0 @@ -# Markdown and Vue SFC - -Each Markdown file is first compiled into HTML, and then converted to a Vue SFC. In other words, you can write a Markdown file like a Vue SFC: - -- Blocks ` - - -``` - -**Output** - -_Hello, {{ msg }}_ - -- - - - -_Current count is: {{ count }}_ - - - - - - - - diff --git a/docs/advanced/cookbook/passing-data-to-client-code.md b/docs/advanced/cookbook/passing-data-to-client-code.md deleted file mode 100644 index 39b919b4..00000000 --- a/docs/advanced/cookbook/passing-data-to-client-code.md +++ /dev/null @@ -1,66 +0,0 @@ -# Passing Data to Client Code - -As we know, VuePress plugin entries and theme entries are processed in Node side, but sometimes you might need to pass data to client side. For example, you want to generate different data when users use different options. - -## Use `define` Hook - -Plugin API provides a [define](../../reference/plugin-api.md#define) hook to define global constants for client code. You can make use of it to pass data to client. - -First, define some constants in `define` hook: - -```ts -export default (options) => ({ - define: { - __FOO__: options.foo || 'str', - __OBJ__: { - bar: options.bar || 123, - }, - }, -}) -``` - -Then use them in client code directly: - -```ts -const foo = __FOO__ -const obj = __OBJ__ -``` - -If you are using TypeScript in client code, you may need to declare the types of the global constants manually: - -```ts -declare const __FOO__: string -declare const __OBJ__: { bar: number } -``` - -## Write and Load Temp Files - -If you need to achieve some more complex features, you can write temp files and load them dynamically in client code. - -First, write a temp file `foo.js`, which will be generated in the [temp](../../reference/config.md#temp) directory: - -```ts -export default (options) => ({ - async onPrepared(app) { - // write temp file - await app.writeTemp( - 'foo.js', - `export const foo = ${JSON.stringify(options.foo)}`, - ) - }, -}) -``` - -Then, load the temp file via `@temp` alias in client code: - -```ts -import { foo } from '@temp/foo' -``` - -If you are using TypeScript in client code, you may need to declare the type of the temp module manually: - -```ts -declare module '@temp/foo' { - export const foo: string -} -``` diff --git a/docs/advanced/cookbook/resolving-routes.md b/docs/advanced/cookbook/resolving-routes.md deleted file mode 100644 index 4f3d55b1..00000000 --- a/docs/advanced/cookbook/resolving-routes.md +++ /dev/null @@ -1,50 +0,0 @@ -# Resolving Routes - -## Getting all routes - -You can make use of [useRoutes](../../reference/client-api.md#useroutes) to get all routes information. - -The return value of `useRoutes` is a Ref object containing all routes. The keys are route paths of each route, and the values are the corresponding route information. - -```ts -import { useRoutes } from 'vuepress/client' - -const routes = useRoutes() -// { -// '/': { meta: { title: 'Home' }, loader: HomePageLoader }, -// '/404.html': { meta: { title: 'Not Found' }, loader: NotFoundPageLoader }, -// ... -// } - -const routePaths = computed(() => Object.keys(routes.value)) -// => ['/‘, '/404.html', '/foo/', '/bar/', ...] -``` - -## Resolving route path - -You can make use of [resolveRoutePath](../../reference/client-api.md#resolveroutepath) to resolve the route path of the given link. - -`resolveRoutePath` receives a link and an optional base path, and returns the resolved route path: - -```ts -import { resolveRoutePath } from 'vuepress/client' - -const routePath = resolveRoutePath('/foo/') // => '/foo/' -const routePath = resolveRoutePath('baz.html', '/foo/bar.html') // => '/foo/baz.html' -``` - -## Resolving route information - -You can make use of [resolveRoute](../../reference/client-api.md#resolveroute) to resolve route information for a given link. - -`resolveRoute` receives a link and an optional base path, and returns the resolved route information: - -```ts -import { resolveRoute } from 'vuepress/client' - -const route = resolveRoute('/foo/') // => { notFound: false, path: '/foo/', meta: { title: 'Foo' }, loader: FooPageLoader } -const route = resolveRoute('baz.html', '/foo/bar.html') // => { notFound: false, path: '/foo/baz.html', meta: { title: 'Baz' }, loader: BazPageLoader } -const route = resolveRoute('/not-exist.html') // => { notFound: true, path: '/not-exist.html', meta: { title: 'Not Found' }, loader: NotFoundPageLoader } -``` - -There is a `notFound` field in the returned information, which is used to indicate whether a corresponding route exists for a given path. When the route does not exist, the `notFound` field would be `true`, the `path` field would be the normalized path, and the `meta` and `loader` fields would point to the default 404 page. diff --git a/docs/advanced/cookbook/usage-of-client-config.md b/docs/advanced/cookbook/usage-of-client-config.md deleted file mode 100644 index 56ca2fc0..00000000 --- a/docs/advanced/cookbook/usage-of-client-config.md +++ /dev/null @@ -1,174 +0,0 @@ -# Usage of Client Config - -You can make use of the [client config file](../../guide/configuration.md#client-config-file) directly in your project, or specify the file path in your plugin or theme via [clientConfigFile](../../reference/plugin-api.md#clientconfigfile) hook: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -const pluginOrTheme = { - clientConfigFile: path.resolve(__dirname, './path/to/clientConfig.ts'), -} -``` - -Inside the client config file, `vuepress/client` provides a helper function [defineClientConfig](../../reference/client-api.md#defineclientconfig) to help you define the client config: - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ app, router, siteData }) {}, - setup() {}, - layouts: {}, - rootComponents: [], -}) -``` - -## enhance - -The `enhance` function could be either synchronous or asynchronous. It accepts a context param with following properties: - -- `app` is the Vue application instance that created by [createApp](https://vuejs.org/api/application.html#createapp). -- `router` is the Vue Router instance that created by [createRouter](https://router.vuejs.org/api/#createrouter). -- `siteData` is a ref of an object that generated from user config, including [base](../../reference/config.md#base), [lang](../../reference/config.md#lang), [title](../../reference/config.md#title), [description](../../reference/config.md#description), [head](../../reference/config.md#head) and [locales](../../reference/config.md#locales). - -The `enhance` function will be invoked after the client app is created. It's possible to implement any enhancements to the Vue application. - -### Register Vue Components - -You can register global Vue components via the [app.component](https://vuejs.org/api/application.html#app-component) method: - -```ts -import { defineClientConfig } from 'vuepress/client' -import MyComponent from './MyComponent.vue' - -export default defineClientConfig({ - enhance({ app }) { - app.component('MyComponent', MyComponent) - }, -}) -``` - -### Use Non-SSR-Friendly Features - -VuePress will generate a SSR application to pre-render pages during build. Generally speaking, if a code snippet is using Browser / DOM APIs before client app is mounted, we call it non-SSR-friendly. - -We already provides a [ClientOnly](../../reference/components.md#clientonly) component to wrap non-SSR-friendly content. - -In the `enhance` function, you can make use of the [`__VUEPRESS_SSR__`](../../reference/client-api.md#ssr) flag for that purpose. - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - async enhance() { - if (!__VUEPRESS_SSR__) { - const nonSsrFriendlyModule = await import('non-ssr-friendly-module') - // ... - } - }, -}) -``` - -### Use Router Methods - -You can make use of the [Router Methods](https://router.vuejs.org/api/#router-methods) that provided by vue-router. For example, add navigation guard: - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ router }) { - router.beforeEach((to) => { - console.log('before navigation') - }) - - router.afterEach((to) => { - console.log('after navigation') - }) - }, -}) -``` - -::: warning -It's not recommended to use `addRoute` method to add dynamic routes here, because those routes will **NOT** be pre-rendered in build mode. - -But you can still do that if you understand the drawback. -::: - -## setup - -The `setup` function would be invoked inside the [setup](https://vuejs.org/api/composition-api-setup.html) hook of the client vue app. - -### Use Composition API - -You can take the `setup` function as part of the [setup](https://vuejs.org/api/composition-api-setup.html) hook of the root component. Thus, all composition APIs are available here. - -```ts -import { provide, ref } from 'vue' -import { useRoute, useRouter } from 'vue-router' -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - setup() { - // get the current route location - const route = useRoute() - // get the vue-router instance - const router = useRouter() - // provide a value that can be injected by layouts, pages and other components - const count = ref(0) - provide('count', count) - }, -}) -``` - -### Use Non-SSR-Friendly Features - -In the `setup` function, the [`__VUEPRESS_SSR__`](../../reference/client-api.md#ssr) flag is also available. - -Another way to use non-ssr-friendly features is to put them inside the [onMounted](https://vuejs.org/api/composition-api-lifecycle.html#onmounted) hook: - -```ts -import { onMounted } from 'vue' -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - setup() { - onMounted(() => { - // use DOM API after mounted - document.querySelector('#app') - }) - }, -}) -``` - -## layouts - -The `layouts` options is to set layout components. After layout components are registered here, users can use it via [layout](../../reference/frontmatter.md#layout) frontmatter. - -```ts -import { defineClientConfig } from 'vuepress/client' -import MyLayout from './layouts/MyLayout.vue' - -export default defineClientConfig({ - layouts: { - MyLayout, - }, -}) -``` - -## rootComponents - -The `rootComponents` is a components array to be placed directly into the root node of the client vue app. - -Typical usage of this option is to put some global UI components, like global popup or so: - -```ts -import { defineClientConfig } from 'vuepress/client' -import GlobalPopup from './components/GlobalPopup.vue' - -export default defineClientConfig({ - rootComponents: [GlobalPopup], -}) -``` diff --git a/docs/advanced/plugin.md b/docs/advanced/plugin.md deleted file mode 100644 index f3aac5a2..00000000 --- a/docs/advanced/plugin.md +++ /dev/null @@ -1,53 +0,0 @@ -# Writing a Plugin - -::: tip -Before reading this guide, you'd better learn the VuePress [architecture](./architecture.md) first. -::: - -## Create a Plugin - -A plugin should be a plain JavaScript object that satisfies the [Plugin API](../reference/plugin-api.md), which is called a _Plugin Object_: - -```ts -const fooPlugin = { - name: 'vuepress-plugin-foo', - // ... -} -``` - -A plugin could also be a function that receives the [app instance](../reference/node-api.md#app) as the param and returns a _Plugin Object_, which is called a _Plugin Function_: - -```ts -const barPlugin = (app) => ({ - name: 'vuepress-plugin-bar', - // ... -}) -``` - -A plugin usually needs to allow user options, so we typically provide users with a function to receive options, and returns a _Plugin Object_ or a _Plugin Function_. Then your plugin should be converted like this: - -```ts -const fooPlugin = (options) => ({ - name: 'vuepress-plugin-foo', - // ... -}) - -const barPlugin = (options) => (app) => ({ - name: 'vuepress-plugin-bar', - // ... -}) -``` - -## Publish to NPM - -After creating a plugin, you should follow some conventions in the [package.json](https://docs.npmjs.com/cli/v8/configuring-npm/package-json) file before publishing it to NPM: - -```json -{ - "name": "vuepress-plugin-foo", - "keywords": ["vuepress-plugin"] -} -``` - -- Set `name` to follow the naming convention, i.e. `vuepress-plugin-xxx` or `@org/vuepress-plugin-xxx`, which should be consistent with the [name](../reference/plugin-api.md#name) field of the _Plugin Object_. -- Set `keywords` to include `vuepress-plugin`, so that users can search your plugin on NPM. diff --git a/docs/advanced/theme.md b/docs/advanced/theme.md deleted file mode 100644 index 9ceae09a..00000000 --- a/docs/advanced/theme.md +++ /dev/null @@ -1,95 +0,0 @@ -# Writing a Theme - -::: tip -Before reading this guide, you'd better learn the guide of [Writing a Plugin](./plugin.md) first. -::: - -## Create a Theme - -A VuePress theme is a special plugin, which should satisfy the [Theme API](../reference/theme-api.md). Like plugins, a theme should also be a _Theme Object_ or a _Theme Function_, and could be wrapped with a function to receive options: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -const fooTheme = (options) => - // returns a theme object - ({ - name: 'vuepress-theme-foo', - - // path to the client config of your theme - clientConfigFile: path.resolve(__dirname, 'client.js'), - - // set custom dev / build template - // if the template is not specified, the default template - templateBuild: path.resolve(__dirname, 'templates/build.html'), - templateDev: path.resolve(__dirname, 'templates/dev.html'), - - // use plugins - plugins: [ - // ... - ], - - // other plugin APIs are also available - }) - -const barTheme = - (options) => - // returns a theme function - (app) => ({ - name: 'vuepress-theme-bar', - // ... - }) -``` - -Then, create theme's client config file `client.js` : - -```ts -import { defineClientConfig } from 'vuepress/client' -import Layout from './layouts/Layout.vue' -import NotFound from './layouts/NotFound.vue' - -export default defineClientConfig({ - layouts: { - Layout, - NotFound, - }, -}) -``` - -The `layouts` field declares the layouts provided by your theme. A theme must provide at least two layouts: `Layout` and `NotFound`. The former is to provide default layout for common pages, while the latter is to provide layout for 404-not-found page. - -The `Layout` layout should contain the [Content](../reference/components.md#content) component to display the markdown content: - -```vue - --- -``` - -The `NotFound` layout will be used for the `404.html` page: - -```vue - -- 404 Not Found- -``` - -You can provide more layouts, and users can change layout via [layout](../reference/frontmatter.md#layout) frontmatter. - -## Publish to NPM - -Also, there are some conventions for theme in [package.json](https://docs.npmjs.com/cli/v8/configuring-npm/package-json): - -```json -{ - "name": "vuepress-theme-foo", - "keywords": ["vuepress-theme"] -} -``` - -- Set `name` to follow the naming convention: `vuepress-theme-xxx` or `@org/vuepress-theme-xxx`, which should be consistent with the [name](../reference/theme-api.md#name) field of the _Theme Object_. -- Set `keywords` to include `vuepress-theme`, so that users can search your theme on NPM. diff --git a/docs/guide/assets.md b/docs/guide/assets.md deleted file mode 100644 index 93618ad1..00000000 --- a/docs/guide/assets.md +++ /dev/null @@ -1,126 +0,0 @@ -# Assets - -## Relative URLs - -You can reference any assets using relative URLs in your Markdown content: - -```md - -``` - -or - -```md - -``` - -This is generally the suggested way to import images, as users usually place images near the Markdown file that references them. - -## Public Files - -You can put some static assets inside public directory, and they will be copied to the root of the generated directory. - -The default public directory is `.vuepress/public`, which can be changed by [public](../reference/config.md#public) option. - -It would be useful in some cases: - -- You may need to provide static assets that are not directly referenced in any of your Markdown files, for example, favicon and PWA icons. -- You may need to serve some shared static assets, which may even be referenced outside your site, for example, logo images. -- You may want to reference images using absolute URLs in your Markdown content. - -Take our documentation source files as an example, we are putting the logo of VuePress inside the public directory: - -```bash -└─ docs - ├─ .vuepress - | └─ public - | └─ images - | └─ hero.png # <- Logo file - └─ guide - └─ assets.md # <- Here we are -``` - -We can reference our logo in current page like this: - -**Input** - -```md - -``` - -**Output** - - - -### Base Helper - -If your site is deployed to a non-root URL, for example, `https://foo.github.io/bar/`, then the [base](../reference/config.md#base) should be set to `'/bar/'`. Obviously, your public files would be served like `https://foo.github.io/bar/images/hero.png` after deployment. - -In most cases, you don't need to worry about the reference path of those public files, as VuePress will automatically handle `base` for you: - -```md - - - -``` - -::: tip -When using [webpack bundler](../reference/bundler/webpack.md), you need to set [markdown.assets.absolutePathPrependBase](../reference/config.md#markdown-assets) to `true` to automatically prepend base to markdown images. -::: - -However, sometimes you may have some dynamical links referencing public files, especially when you are authoring a custom theme. In such case, the `base` could not be handled automatically. To help with that, VuePress provides a [withBase](../reference/client-api.md#withbase) helper to prepend `base` for you: - -```vue - - - -- -``` - -You can also access the helper by `$withBase` directly: - -```md -
-``` - -## Packages and Path Aliases - -Although it is not a common usage, you can reference images from dependent packages: - -```bash -npm install -D package-name -``` - -Since markdown image syntax regards image links as relative paths by default, you need to use `
` tag: - -```md -
-``` - -The path aliases that set in config file are also supported: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - alias: { - '@alias': path.resolve(__dirname, './path/to/some/dir'), - }, -} -``` - -```md -
-``` - -::: tip -Config reference: [alias](../reference/plugin-api.md#alias) -::: diff --git a/docs/guide/bundler.md b/docs/guide/bundler.md deleted file mode 100644 index 443e46a0..00000000 --- a/docs/guide/bundler.md +++ /dev/null @@ -1,59 +0,0 @@ -# Bundler - -VuePress supports using [Webpack](https://webpack.js.org/) or [Vite](https://vite.dev/) to dev and build sites. You can choose which bundler to use according to your preference, and no extra configuration is required. - -## Install a Bundler - -When installing the [vuepress](https://www.npmjs.com/package/vuepress) package, no bundlers will be installed. You need to choose a bundler to install. - -::: code-tabs#shell - -@tab pnpm - -```bash -# install vite bundler -pnpm add -D vuepress@next @vuepress/bundler-vite@next -# install webpack bundler -pnpm add -D vuepress@next @vuepress/bundler-webpack@next -``` - -@tab yarn - -```bash -# install vite bundler -yarn add -D vuepress@next @vuepress/bundler-vite@next -# install webpack bundler -yarn add -D vuepress@next @vuepress/bundler-webpack@next -``` - -@tab npm - -```bash -# install vite bundler -npm install -D vuepress@next @vuepress/bundler-vite@next -# install webpack bundler -npm install -D vuepress@next @vuepress/bundler-webpack@next -``` - -::: - -## Use a Bundler - -Generally, you could use a bundler without extra configuration, because we have already configured them properly to work with VuePress. - -You can use a bundler via the [bundler](../reference/config.md#bundler) option: - -```ts -import { viteBundler } from '@vuepress/bundler-vite' -// import { webpackBundler } from '@vuepress/bundler-webpack' - -export default { - bundler: viteBundler(), - // bundler: webpackBundler(), -} -``` - -When you need to customize the bundler, you can set the corresponding options: - -- [Bundlers > Vite](../reference/bundler/vite.md) -- [Bundlers > Webpack](../reference/bundler/webpack.md) diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md deleted file mode 100644 index a750472f..00000000 --- a/docs/guide/configuration.md +++ /dev/null @@ -1,86 +0,0 @@ -# Configuration - -## Config File - -The essential file for configuring a VuePress site is `.vuepress/config.js`, while TypeScript config file is also supported. You can use `.vuepress/config.ts` instead to get better types hint for VuePress config. - -To be more specific, we have a convention for config file paths (in order of precedence): - -- In current working directory `cwd`: - - `vuepress.config.ts` - - `vuepress.config.js` - - `vuepress.config.mjs` -- In source directory `sourceDir`: - - `.vuepress/config.ts` - - `.vuepress/config.js` - - `.vuepress/config.mjs` - -You can also specify the config file via `--config` option of [CLI](../reference/cli.md): - -```bash -vuepress dev docs --config my-config.ts -``` - -A basic config file looks like this: - -```ts -import { viteBundler } from '@vuepress/bundler-vite' -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler(), - theme: defaultTheme(), - - lang: 'en-US', - title: 'Hello VuePress', - description: 'Just playing around', -}) -``` - -::: tip -Check out the [Config Reference](../reference/config.md) for a full list of VuePress config. -::: - -## Client Config File - -In most cases, the config file is sufficient to configure your VuePress site. However, sometimes users may want to add some client-side code directly. To help with this, VuePress also supports a client config file: - -``` -├─ docs -│ ├─ .vuepress -│ │ ├─ client.js <--- client config file -│ │ └─ config.js <--- config file -│ └─ README.md -├─ .gitignore -└─ package.json -``` - -Similarly, we also have a convention for client config file paths (in order of precedence): - -- In current working directory `cwd`: - - `vuepress.client.ts` - - `vuepress.client.js` - - `vuepress.client.mjs` -- In source directory `sourceDir`: - - `.vuepress/client.ts` - - `.vuepress/client.js` - - `.vuepress/client.mjs` - -A basic client config file looks like this: - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ app, router, siteData }) {}, - setup() {}, - rootComponents: [], -}) -``` - -::: tip -Unlike config file, client config file could not be specified via CLI options. - -To learn more about client config file, see [Advanced > Cookbook > Usage of Client Config](../advanced/cookbook/usage-of-client-config.md) -::: diff --git a/docs/guide/deployment.md b/docs/guide/deployment.md deleted file mode 100644 index fbb96d0d..00000000 --- a/docs/guide/deployment.md +++ /dev/null @@ -1,232 +0,0 @@ -# Deployment - -The following guides are based on some shared assumptions: - -- You are placing your Markdown source files inside the `docs` directory of your project; -- You are using the default build output location (`.vuepress/dist`); -- You are using [pnpm](https://pnpm.io) as package manager, while npm and yarn are also supported; -- VuePress is installed as a local dependency in your project, and you have setup the following script in `package.json`: - -```json -{ - "scripts": { - "docs:build": "vuepress build docs" - } -} -``` - -## GitHub Pages - -1. Set the correct [base](../reference/config.md#base) config. - - If you are deploying to `https://
.github.io/`, you can omit this step as `base` defaults to `"/"`. - - If you are deploying to `https:// .github.io/ /`, for example your repository is at `https://github.com/ / `, then set `base` to `"/ /"`. - -2. Choose your preferred CI tools. Here we take [GitHub Actions](https://github.com/features/actions) as an example. - - Create `.github/workflows/docs.yml` to set up the workflow. - -::: details Click to expand sample config - -```yaml -name: docs - -on: - # trigger deployment on every push to main branch - push: - branches: [main] - # trigger deployment manually - workflow_dispatch: - -jobs: - docs: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - # fetch all commits to get last updated time or other git log info - fetch-depth: 0 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - # choose node.js version to use - node-version: 22 - # cache deps for pnpm - cache: pnpm - - - name: Install deps - run: pnpm install --frozen-lockfile - - # run build script - - name: Build VuePress site - run: pnpm docs:build - - # please check out the docs of the workflow for more details - # @see https://github.com/crazy-max/ghaction-github-pages - - name: Deploy to GitHub Pages - uses: crazy-max/ghaction-github-pages@v4 - with: - # deploy to gh-pages branch - target_branch: gh-pages - # deploy the default output dir of VuePress - build_dir: docs/.vuepress/dist - env: - # @see https://docs.github.com/en/actions/reference/authentication-in-a-workflow#about-the-github_token-secret - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -``` - -::: - -::: tip -Please refer to [GitHub Pages official guide](https://pages.github.com/) for more details. -::: - -## GitLab Pages - -1. Set the correct [base](../reference/config.md#base) config. - - If you are deploying to `https:// .gitlab.io/`, you can omit `base` as it defaults to `"/"`. - - If you are deploying to `https:// .gitlab.io/ /`, for example your repository is at `https://gitlab.com/ / `, then set `base` to `"/ /"`. - -2. Create `.gitlab-ci.yml` to set up [GitLab CI](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/) workflow. - -::: details Click to expand sample config - -```yaml -# choose a docker image to use -image: node:18-buster - -pages: - # trigger deployment on every push to main branch - only: - - main - - # cache node_modules - cache: - key: - files: - - pnpm-lock.yaml - paths: - - .pnpm-store - - # Install pnpm - before_script: - - curl -fsSL https://get.pnpm.io/install.sh | sh - - - pnpm config set store-dir .pnpm-store - - # install dependencies and run build script - script: - - pnpm i --frozen-lockfile - - pnpm docs:build --dest public - - artifacts: - paths: - - public -``` - -::: - -::: tip -Please refer to [GitLab Pages official guide](https://docs.gitlab.com/ce/user/project/pages/#getting-started) for more details. -::: - -## Google Firebase - -1. Make sure you have [firebase-tools](https://www.npmjs.com/package/firebase-tools) installed. - -2. Create `firebase.json` and `.firebaserc` at the root of your project with the following content: - -`firebase.json`: - -```json -{ - "hosting": { - "public": "./docs/.vuepress/dist", - "ignore": [] - } -} -``` - -`.firebaserc`: - -```json -{ - "projects": { - "default": " " - } -} -``` - -3. After running `pnpm docs:build`, deploy using the command `firebase deploy`. - -::: tip -Please refer to [Firebase CLI official guide](https://firebase.google.com/docs/cli) for more details. -::: - -## Heroku - -1. Install [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli). - -2. Create a Heroku account by [signing up](https://signup.heroku.com). - -3. Run `heroku login` and fill in your Heroku credentials: - -```bash -heroku login -``` - -4. Create a file called `static.json` in the root of your project with the below content: - -`static.json`: - -```json -{ - "root": "./docs/.vuepress/dist" -} -``` - -This is the configuration of your site; read more at [heroku-buildpack-static](https://github.com/heroku/heroku-buildpack-static). - -## Kinsta - -See [Set Up VuePress on Kinsta](https://kinsta.com/docs/vuepress-application/). - -## Edgio - -See [Edgio Documentation > Framework Guides > VuePress](https://docs.edg.io/guides/vuepress). - -## Netlify - -1. On [Netlify](https://netlify.com), set up a new project from GitHub with the following settings: - - - **Build Command:** `pnpm docs:build` - - **Publish directory:** `docs/.vuepress/dist` - -2. Set [Environment variables](https://docs.netlify.com/configure-builds/environment-variables) to choose node version: - - - `NODE_VERSION`: 20 - -3. Hit the deploy button. - -::: note - -You should disable Pretty URLs in the "Site Configuration" → "Build & Deploy" → "Post processing". - -::: - -## Vercel - -1. Go to [Vercel](https://vercel.com), set up a new project from GitHub with the following settings: - - - **FRAMEWORK PRESET:** `Other` - - **BUILD COMMAND:** `pnpm docs:build` - - **OUTPUT DIRECTORY:** `docs/.vuepress/dist` - -2. Hit the deploy button. diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md deleted file mode 100644 index 1a18b706..00000000 --- a/docs/guide/getting-started.md +++ /dev/null @@ -1,252 +0,0 @@ -# Getting Started - -::: warning -VuePress v2 is currently in RC (Release Candidate) stage. It's ready to be used for building your site, but the config and API are not stable enough, which is possibly to have minor breaking changes. So make sure to read the [changelog](https://github.com/vuepress/core/blob/main/CHANGELOG.md) carefully each time you upgrade a RC version. -::: - -## Try It Online - -You can try VuePress directly in your browser on [StackBlitz](https://stackblitz.com/fork/vuepress). - -## Installation - -### Prerequisites - -- [Node.js v20.6.0+](https://nodejs.org/) -- Package manager like [pnpm](https://pnpm.io), [yarn](https://classic.yarnpkg.com/en/), [npm](https://www.npmjs.com), etc. - -::: tip - -- When using [pnpm](https://pnpm.io/), you need to install `vue` as peer-dependencies. -- When using [yarn 2+](https://yarnpkg.com/), you need to set `nodeLinker: 'node-modules'` in your [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc#nodeLinker) file. - -::: - -### Project Setup - -#### Setup via CLI - -You can use [create-vuepress](https://www.npmjs.com/package/create-vuepress) to generate a template directly. - -::: code-tabs#shell - -@tab pnpm - -```bash -pnpm create vuepress vuepress-starter -``` - -@tab yarn - -```bash -yarn create vuepress vuepress-starter -``` - -@tab npm - -```bash -npm init vuepress vuepress-starter -``` - -::: - -#### Setup Manually - -This section will help you build a basic VuePress documentation site from ground up. - -- Create and change into a new directory - -```bash -mkdir vuepress-starter -cd vuepress-starter -``` - -- Initialize your project - -::: code-tabs#shell - -@tab pnpm - -```bash -git init -pnpm init -``` - -@tab yarn - -```bash -git init -yarn init -``` - -@tab npm - -```bash -git init -npm init -``` - -::: - -- Install VuePress - -::: code-tabs#shell - -@tab pnpm - -```bash -# install vuepress and vue -pnpm add -D vuepress@next vue -# install bundler and theme -pnpm add -D @vuepress/bundler-vite@next @vuepress/theme-default@next -``` - -@tab yarn - -```bash -# install vuepress -yarn add -D vuepress@next -# install bundler and theme -yarn add -D @vuepress/bundler-vite@next @vuepress/theme-default@next -``` - -@tab npm - -```bash -# install vuepress -npm install -D vuepress@next -# install bundler and theme -npm install -D @vuepress/bundler-vite@next @vuepress/theme-default@next -``` - -::: - -- Create `docs` directory and `docs/.vuepress` directory - -```bash -mkdir docs -mkdir docs/.vuepress -``` - -- Create the VuePress config file `docs/.vuepress/config.js` - -```ts -import { viteBundler } from '@vuepress/bundler-vite' -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler(), - theme: defaultTheme(), -}) -``` - -- Create your first document - -```bash -echo '# Hello VuePress' > docs/README.md -``` - -## Directory Structure - -After the setup, the minimal structure of your project should look like this: - -``` -├─ docs -│ ├─ .vuepress -│ │ └─ config.js -│ └─ README.md -└─ package.json -``` - -The `docs` directory is where you put your markdown files, and it will be used as the source directory of VuePress. - -The `docs/.vuepress` directory, i.e. the `.vuepress` directory in the source directory, is where all VuePress-specific files will be placed. Currently there is only one config file in it. By default, the temp, cache and output directory will also be generated inside this directory. It is suggested to add them to your `.gitignore` file. - -::: details Example `.gitignore` file - -``` -# VuePress default temp directory -.vuepress/.temp -# VuePress default cache directory -.vuepress/.cache -# VuePress default build output directory -.vuepress/dist -``` - -::: - -## Work with VuePress - -### Start Dev Server - -You can add some [scripts](https://classic.yarnpkg.com/en/docs/package-json#toc-scripts) to `package.json`: - -```json -{ - "scripts": { - "docs:dev": "vuepress dev docs", - "docs:build": "vuepress build docs" - } -} -``` - -Then, run `docs:dev` script to start the dev server: - -::: code-tabs#shell - -@tab pnpm - -```bash -pnpm docs:dev -``` - -@tab yarn - -```bash -yarn docs:dev -``` - -@tab npm - -```bash -npm run docs:dev -``` - -::: - -VuePress will start a hot-reloading development server at [http://localhost:8080](http://localhost:8080). When you modify your markdown files, the content in the browser will be auto updated. - -### Build Your Site - -To build your site, run `docs:build` script: - -::: code-tabs#shell - -@tab pnpm - -```bash -pnpm docs:build -``` - -@tab yarn - -```bash -yarn docs:build -``` - -@tab npm - -```bash -npm run docs:build -``` - -::: - -You will see the generated static files in the `docs/.vuepress/dist` directory. You can check out [deployment](./deployment.md) for how to deploy them. - -## Learn More about VuePress - -By now, you should have a basic but functional VuePress site. But you may still need to read the subsequent guide to learn more about VuePress. - -Next step, learn more about the [configuration](./configuration.md). diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md deleted file mode 100644 index bf572ef0..00000000 --- a/docs/guide/i18n.md +++ /dev/null @@ -1,78 +0,0 @@ -# I18n - -## Site I18n Config - -To take advantage of multi-language support in VuePress, you first need to use the following file and directory structure: - -``` -docs -├─ README.md -├─ foo.md -├─ nested -│ └─ README.md -└─ zh - ├─ README.md - ├─ foo.md - └─ nested - └─ README.md -``` - -Then, specify the `locales` option in your [config file](./configuration.md#config-file): - -```ts -export default { - locales: { - // The key is the path for the locale to be nested under. - // As a special case, the default locale can use '/' as its path. - '/': { - lang: 'en-US', - title: 'VuePress', - description: 'Vue-powered Static Site Generator', - }, - '/zh/': { - lang: 'zh-CN', - title: 'VuePress', - description: 'Vue 驱动的静态网站生成器', - }, - }, -} -``` - -If a locale does not have a `lang`, `title`, `description` or `head`, VuePress will fallback to the root-level values. You can omit the root level config as long as they are provided in each locale. - -::: tip -Config reference: [locales](../reference/config.md#locales) -::: - -## Theme I18n Config - -VuePress does not restrict how themes provide multi-language support, so each theme may have different way to handle i18n, and some themes may not provide multi-language support at all. You'd better refer to the theme documentation for detailed guide. - -If you are using default theme, the multi-language support is the same as above: - -```ts -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - theme: defaultTheme({ - locales: { - '/': { - selectLanguageName: 'English', - }, - '/zh/': { - selectLanguageName: '简体中文', - }, - }, - }), -}) -``` - -::: tip - -Config reference: - -- [Default Theme > Config](https://ecosystem.vuejs.press/themes/default/config.html) -- [Default Theme > Locale config](https://ecosystem.vuejs.press/themes/default/locale.html) - -::: diff --git a/docs/guide/introduction.md b/docs/guide/introduction.md deleted file mode 100644 index d04f0854..00000000 --- a/docs/guide/introduction.md +++ /dev/null @@ -1,39 +0,0 @@ -# Introduction - -VuePress is a markdown-centered static site generator. You can write your content (documentations, blogs, etc.) in [Markdown](https://en.wikipedia.org/wiki/Markdown), then VuePress will help you to generate a static site to host them. - -The purpose of creating VuePress was to support the documentation of Vue.js and its sub-projects, but now it has been helping a large amount of users to build their documentation, blogs, and other static sites. - -## How It Works - -A VuePress site is in fact a single-page application (SPA) powered by [Vue](https://vuejs.org/) and [Vue Router](https://router.vuejs.org). - -Routes are generated according to the relative path of your markdown files. Each Markdown file is compiled into HTML with [markdown-it](https://github.com/markdown-it/markdown-it) and then processed as the template of a Vue component. This allows you to directly use Vue inside your Markdown files and is great when you need to embed dynamic content. - -During development, we start a normal dev-server, and serve the VuePress site as a normal SPA. If you’ve used Vue before, you will notice the familiar development experience when you are writing and developing with VuePress. - -During build, we create a server-rendered version of the VuePress site and render the corresponding HTML by virtually visiting each route. This approach is inspired by [Nuxt](https://nuxtjs.org/)'s `nuxt generate` command and other projects like [Gatsby](https://www.gatsbyjs.org/). - -## Why Not ...? - -### Nuxt - -Nuxt is an outstanding Vue SSR framework, and it is capable of doing what VuePress does. But Nuxt is designed for building applications, while VuePress is more lightweight and focused on content-centric static sites. - -### VitePress - -VitePress is the little brother of VuePress. It's also created and maintained by our Vue.js team. It's even more lightweight and faster than VuePress. However, as a tradeoff, it's more opinionated and less configurable. For example, it does not support plugins. But VitePress is powerful enough to make your content online if you don't need advanced customizations. - -It might not be an appropriate comparison, but you can take VuePress and VitePress as Laravel and Lumen. - -### Docsify / Docute - -Both are great projects and also Vue-powered. Except they are both fully runtime-driven and therefore not SEO-friendly. If you don’t care for SEO and don’t want to mess with installing dependencies, these are still great choices. - -### Hexo - -Hexo has been serving the Vue 2.x docs well. The biggest problem is that its theming system is static and string-based - we want to take advantage of Vue for both the layout and the interactivity. Also, Hexo’s Markdown rendering isn’t the most flexible to configure. - -### GitBook - -We’ve been using GitBook for most of our sub project docs. The primary problem with GitBook is that its development reload performance is intolerable with a large amount of files. The default theme also has a pretty limiting navigation structure, and the theming system is, again, not Vue based. The team behind GitBook is also more focused on turning it into a commercial product rather than an open-source tool. diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md deleted file mode 100644 index 3d24a946..00000000 --- a/docs/guide/markdown.md +++ /dev/null @@ -1,508 +0,0 @@ -# Markdown - -Make sure you already know Markdown well before reading this section. If not, please learn some [Markdown tutorials](https://commonmark.org/help/) first. - -## Syntax Extensions - -The Markdown content in VuePress will be parsed by [markdown-it](https://github.com/markdown-it/markdown-it), which supports [syntax extensions](https://github.com/markdown-it/markdown-it#syntax-extensions) via markdown-it plugins. - -This section will introduce built-in Markdown syntax extensions of VuePress. - -You can also configure those built-in extensions, load more markdown-it plugins and implement your own extensions via [markdown](../reference/config.md#markdown) option and [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) option. - -### Embedded - -Embedded by markdown-it: - -- [Tables](https://help.github.com/articles/organizing-information-with-tables/) (GFM) -- [Strikethrough](https://help.github.com/articles/basic-writing-and-formatting-syntax/#styling-text) (GFM) - -### Header Anchors - -You might have noticed that, a `#` anchor is displayed when you hover the mouse on the headers of each section. By clicking the `#` anchor, you can jump to the section directly. - -::: tip -This header anchors extension is supported by [markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor). - -Config reference: [markdown.anchor](../reference/config.md#markdown-anchor) -::: - -### Links - -When using Markdown [link syntax](https://spec.commonmark.org/0.29/#link-reference-definitions), VuePress will implement some conversions for you. - -Take our documentation source files as an example: - -```bash -└─ docs - ├─ guide - │ ├─ getting-started.md - │ ├─ introduction.md - │ └─ markdown.md # <- Here we are - ├─ reference - │ └─ config.md - └─ README.md -``` - -**Raw Markdown** - -```md - - -[Home](../README.md) -[Config Reference](../reference/config.md) -[Getting Started](./getting-started.md) - - - -[Guide > Introduction](/guide/introduction.md) -[Config Reference > markdown.links](/reference/config.md#links) - - - -[GitHub](https://github.com) -``` - -**Converted to** - -```vue - - Home -Config Reference -Getting Started -Guide > Introduction -- Config Reference > markdown.links - - - GitHub - - -``` - -**Rendered as** - -[Home](../README.md) -[Config Reference](../reference/config.md) -[Getting Started](./getting-started.md) -[Guide > Introduction](/guide/introduction.md) -[Config Reference > markdown.links](/reference/config.md#links) -[GitHub](https://github.com) - -**Explanation** - -- Internal links will be converted to [RouteLink](../reference/components.md#routelink) for SPA navigation. -- Internal links to `.md` files will be converted to the [page route path](./page.md#routing), and both absolute path and relative path are supported. -- External links will get `target="_blank" rel="noopener noreferrer"` attrs. - -**Suggestion** - -Try to use relative paths instead of absolute paths for internal links to markdown files. - -- Relative paths are a valid links to the target files, and they can navigate correctly when browsing the source files in your editor or repository. -- Relative paths are consistent in different locales, so you don't need to change the locale path when translating your content. - -::: tip -This links extension is supported by our built-in plugin. - -Config reference: [markdown.links](../reference/config.md#markdown-links) -::: - -### Emoji :tada: - -You can add emoji to your Markdown content by typing `:EMOJICODE:`. - -For a full list of available emoji and codes, check out [emoji-cheat-sheet](https://github.com/ikatyang/emoji-cheat-sheet). - -**Input** - -```md -VuePress 2 is out :tada: ! -``` - -**Output** - -VuePress 2 is out :tada: ! - -::: tip -This emoji extension is supported by [markdown-it-emoji](https://github.com/markdown-it/markdown-it-emoji). - -Config reference: [markdown.emoji](../reference/config.md#markdown-emoji) -::: - -### Table of Contents - -If you want to put the table of contents (TOC) of your current page inside your Markdown content, you can use the `[[toc]]` syntax. - -**Input** - -```md -[[toc]] -``` - -**Output** - -[[toc]] - -The headers in TOC will link to the corresponding [header anchors](#header-anchors), so TOC won't work well if you disable header anchors. - -::: tip -This toc extension is supported by [@mdit-vue/plugin-toc](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc). - -Config reference: [markdown.toc](../reference/config.md#markdown-toc) -::: - -### Code Blocks - -Following code blocks extensions are implemented during markdown parsing in Node side. That means, the code blocks won't be processed in client side. - -With [@vuepress/plugin-prismjs][prismjs] and [@vuepress/plugin-shiki][shiki], you can highlight code blocks with [Prism](https://prismjs.com/) or [Shiki](https://shiki.style/). - -#### Code Title - -You can specify the title of the code block by adding a `title` key-value mark in your fenced code blocks. - -**Input** - -````md -```ts title=".vuepress/config.ts" -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: 'Hello, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` -```` - -**Output** - -```ts title=".vuepress/config.ts" -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: 'Hello, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` - -::: tip - -Code title is supported by highlight plugins by default. It can be used in combination with the other marks below. Please leave a space between them. - -::: - -#### Line Highlighting - -You can highlight specified lines of your code blocks by adding line ranges mark in your fenced code blocks. - -**Input** - -````md -```ts{1,7-9} -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: 'Hello, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` -```` - -**Output** - -```ts{1,7-9} -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: 'Hello, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` - -Examples for line ranges mark: - -- Line ranges: `{5-8}` -- Multiple single lines: `{4,7,9}` -- Combined: `{4,7-13,16,23-27,40}` - -::: tip - -Line highlighting extension is supported by highlighter plugins. - -Config reference: [prism line highlighting](https://ecosystem.vuejs.press/plugins/markdown/prismjs.html#highlightlines) and [shiki highlighting](https://ecosystem.vuejs.press/plugins/markdown/shiki.html#highlightlines). - -::: - -#### Line Numbers - -You must have noticed that the number of lines is displayed on the left side of code blocks. - -You can add `:line-numbers` / `:no-line-numbers` mark in your fenced code blocks to override the value set in config. - -**Input** - -````md -```ts -// line-numbers is enabled by default -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` - -```ts:no-line-numbers -// line-numbers is disabled -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` -```` - -**Output** - -```ts -// line-numbers is enabled by default -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` - -```ts:no-line-numbers -// line-numbers is disabled -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` - -::: tip - -Line numbers extension is supported by highlighter plugins. - -Config reference: [prism line numbers](https://ecosystem.vuejs.press/plugins/markdown/prismjs.html#linenumbers) and [shiki line numbers](https://ecosystem.vuejs.press/plugins/markdown/shiki.html#linenumbers). - -::: - -#### Wrap with v-pre - -As [template syntax is allowed in Markdown](#template-syntax), it would also work in code blocks, too. - -To avoid your code blocks being compiled by Vue, VuePress will add [v-pre](https://vuejs.org/api/built-in-directives.html#v-pre) directive to your code blocks by default, which can be disabled in config. - -You can add `:v-pre` / `:no-v-pre` mark in your fenced code blocks to override the value set in config. - -::: warning -The template syntax characters, for example, the "Mustache" syntax (double curly braces) might be parsed by the syntax highlighter. Thus, as the following example, `:no-v-pre` might not work well in some languages. - -If you want to make Vue syntax work in those languages anyway, try to disable the default syntax highlighting and implement your own syntax highlighting in client side. -::: - -**Input** - -````md -```md - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - -```md:no-v-pre - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - -```js:no-v-pre -// This won't be compiled correctly because of js syntax highlighting -const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} -``` -```` - -**Output** - -```md - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - -```md:no-v-pre - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - - - -```js -// This won't be compiled correctly because of js syntax highlighting -const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} -``` - -::: tip - -This v-pre extension is supported by our built-in plugin. - -Config reference: [markdown.vPre.block](../reference/config.md#markdown-vpre-block) - -::: - -### Import Code Blocks - -You can import code blocks from files with following syntax: - -```md - - -@[code](../foo.js) -``` - -If you want to partially import the file: - -```md - - -@[code{1-10}](../foo.js) -``` - -The code language is inferred from the file extension, while it is recommended to specify it explicitly: - -```md - - -@[code js](../foo.js) -``` - -In fact, the second part inside the `[]` will be treated as the mark of the code fence, so it supports all the syntax mentioned in the above [Code Blocks](#code-blocks) section: - -```md - - -@[code js{2,4-5}](../foo.js) -``` - -Here is a complex example: - -- import line 3 to line 10 of the `'../foo.js'` file -- specify the language as `'js'` -- highlight line 3 of the imported code, i.e. line 5 of the `'../foo.js'` file -- disable line numbers - -```md -@[code{3-10} js{3}:no-line-numbers](../foo.js) -``` - -Notice that path aliases are not available in import code syntax. You can use following config to handle path alias yourself: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - markdown: { - importCode: { - handleImportPath: (str) => - str.replace(/^@src/, path.resolve(__dirname, 'path/to/src')), - }, - }, -} -``` - -```md - - -@[code](@src/foo.js) -``` - -::: tip -This import code extension is supported by our built-in plugin. - -Config reference: [markdown.importCode](../reference/config.md#markdown-importcode) -::: - -## Using Vue in Markdown - -This section will introduce some basic usage of Vue in Markdown. - -Check out [Cookbook > Markdown and Vue SFC](../advanced/cookbook/markdown-and-vue-sfc.md) for more details. - -### Template Syntax - -As we know: - -- HTML is allowed in Markdown. -- Vue template syntax is compatible with HTML. - -That means, [Vue template syntax](https://vuejs.org/guide/essentials/template-syntax.html) is allowed in Markdown. - -**Input** - -```md -One plus one equals: {{ 1 + 1 }} - - span: {{ i }} -``` - -**Output** - -One plus one equals: {{ 1 + 1 }} - - span: {{ i }} - -### Components - -You can use Vue components directly in Markdown. - -**Input** - -```md -This is default theme built-in `` component -``` - -**Output** - -This is default theme built-in ` ` component - -::: tip -Check out the [Built-in Components](../reference/components.md) for a full list of built-in components. - -Check out the [Default Theme > Built-in Components](https://ecosystem.vuejs.press/themes/default/components.html) for a full list of default theme built-in components. -::: - -## Markdown Plugins - -You can explore more markdown plugins at [VuePress Marketplace](https://marketplace.vuejs.press/plugins/markdown.html). - -## Cautions - -### Non-Standard HTML Tags - -Non-standard HTML tags would not be recognized as native HTML tags by Vue template compiler. Instead, Vue will try to resolve those tags as Vue components, and obviously these components usually don't exist. For example: - -- Deprecated HTML tags such as [\ ](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/center) and [\](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font). -- [MathML tags](https://developer.mozilla.org/en-US/docs/Web/MathML), which might be used by some markdown-it LaTeX plugin. - -If you want to use those tags anyway, try either of the following workarounds: - -- Adding a [v-pre](https://vuejs.org/api/built-in-directives.html#v-pre) directive to skip the compilation of the element and its children. Notice that the template syntax would also be invalid. -- Using [compilerOptions.isCustomElement](https://vuejs.org/api/application.html#app-config-compileroptions) to tell Vue template compiler not try to resolve them as components. - - For `@vuepress/bundler-webpack`, set [vue.compilerOptions](../reference/bundler/webpack.md#vue) - - For `@vuepress/bundler-vite`, set [vuePluginOptions.template.compilerOptions](../reference/bundler/vite.md#vuepluginoptions) - -[prismjs]: https://ecosystem.vuejs.press/plugins/markdown/prismjs.html -[shiki]: https://ecosystem.vuejs.press/plugins/markdown/shiki.html diff --git a/docs/guide/migration.md b/docs/guide/migration.md deleted file mode 100644 index 48434049..00000000 --- a/docs/guide/migration.md +++ /dev/null @@ -1,443 +0,0 @@ -# Migrating from v1 - -::: warning -Plugins and themes of VuePress v1 are not compatible with VuePress v2. You need to update them to corresponding v2 version. -::: - -Some major changes and enhancements of VuePress v2: - -- VuePress v2 is now using Vue 3, so make sure your components and other client files are compatible with Vue 3. -- VuePress v2 is developed with TypeScript, so it provides better TS support now. It's highly recommended to use TypeScript to develop plugins and themes. VuePress config file also supports TypeScript, and you can use `.vuepress/config.ts` directly. -- VuePress v2 supports both Webpack and Vite as bundler. You can choose the bundler you like in your config file. -- VuePress v2 is now released as pure ESM packages, and CommonJS config files are no longer supported. - -Core ideas and processes of VuePress v2 are the same with v1, while v2 API has been re-designed and becomes more normalized. So you might encounter breaking changes when migrating an existing v1 project to v2. This guide is here to help you migrating v1 sites / plugins / themes to v2. - -- If you are a common user, you need to read the guide [for users](#for-users). -- If you are a plugin author, you need to read the guide [for plugin authors](#for-plugin-authors). -- If you are a theme author, you need to read the guide [for theme authors](#for-theme-authors). - -## For Users - -### User Config Change - -Config file should be in ESM format, and CommonJS format config file is no longer supported. - -```diff title=".vuepress/config.ts" -- module.exports = { -- // user config -- } - -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ // user config -+ }) -``` - -#### bundler - -Now we support using different bundlers. - -Install and use the vite bundler in your config file: - -```bash -npm i -D @vuepress/bundler-vite@next -``` - -```ts title=".vuepress/config.ts" -import { viteBundler } from '@vuepress/bundler-vite' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler(), -}) -``` - -Or using the webpack bundler: - -```bash -npm i -D @vuepress/bundler-webpack@next -``` - -```ts title=".vuepress/config.ts" -import { webpackBundler } from '@vuepress/bundler-webpack' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: webpackBundler(), -}) -``` - -#### theme - -Using a theme via string is not supported, and the default theme is not integrated into vuepress package by default. - -Install and use the default theme in your config file: - -```bash -npm i -D @vuepress/theme-default@next -``` - -```diff title=".vuepress/config.ts" -- module.exports = { -- theme: '@vuepress/theme-default', -- themeConfig: { -- // default theme config -- }, -- } - -+ import { defaultTheme } from '@vuepress/theme-default' -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ theme: defaultTheme({ -+ // default theme config -+ }), -+ }) -``` - -#### themeConfig - -Removed. Set config to the theme directly. - -#### plugins - -Using a plugin via string is not supported. Import the plugin directly. - -```diff title=".vuepress/config.ts" -- module.exports = { -- plugins: [ -- [ -- '@vuepress/plugin-google-analytics', -- { -- id: 'G-XXXXXXXXXX', -- }, -- ], -- ], -- } - -+ import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ plugins: [ -+ googleAnalyticsPlugin({ -+ id: 'G-XXXXXXXXXX', -+ }), -+ ], -+ }) -``` - -#### shouldPrefetch - -Default value is changed from `() => true` to `true`. - -#### extraWatchFiles - -Removed. - -You can watch files manually in [onWatched](../reference/plugin-api.md#onwatched) hook. - -#### patterns - -Renamed to `pagePatterns` - -#### markdown.lineNumbers - -Removed. - -The same feature is implemented in [@vuepress/plugin-prismjs][prismjs] and [@vuepress/plugin-shiki][shiki]. - -#### markdown.pageSuffix - -Removed. - -#### markdown.externalLinks - -Moved to [markdown.links.externalAttrs](../reference/config.md#markdown-links). - -#### markdown.toc - -Changed. - -See [Config > markdown.toc](../reference/config.md#markdown-toc) - -#### markdown.plugins - -Removed. - -Use markdown-it plugins in [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) hook. - -#### markdown.extendMarkdown - -Removed. - -Use [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) hook. - -#### markdown.extractHeaders - -Moved to [markdown.headers](../reference/config.md#markdown-headers). - -#### Webpack Related Configs - -All webpack related configs are moved to options of `@vuepress/bundler-webpack`, including: - -- `postcss` -- `stylus` -- `scss` -- `sass` -- `less` -- `chainWebpack` -- `configureWebpack` -- `evergreen`: default value is changed from `false` to `true` - -```diff title=".vuepress/config.ts" -- module.exports = { -- sass: { /* ... */ }, -- } - -+ import { webpackBundler } from '@vuepress/bundler-webpack' -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ bundler: webpackBundler({ -+ sass: { /* ... */ }, -+ }), -+ }) -``` - -Please refer to [Guide > Bundler](./bundler.md). - -### Frontmatter Change - -#### meta - -Removed. - -Use [head](../reference/frontmatter.md#head) instead. For example: - -```yaml -head: - - - meta - - name: foo - content: bar - - - link - - rel: canonical - href: foobar - - - script - - {} - - console.log('hello from frontmatter'); -``` - -Has the same structure with: - -```ts title=".vuepress/config.ts" -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - // ... - head: [ - ['meta', { name: 'foo', content: 'bar' }], - ['link', { rel: 'canonical', href: 'foobar' }], - ['script', {}, `console.log('hello from frontmatter');`], - ], - // ... -}) -``` - -### Permalink Patterns Change - -- `:i_month`: removed -- `:i_day`: removed -- `:minutes`: removed (undocumented in v1) -- `:seconds`: removed (undocumented in v1) -- `:regular`: renamed to `:raw` - -See [Frontmatter > permalinkPattern](../reference/frontmatter.md#permalinkpattern). - -### Palette System Change - -The stylus palette system of VuePress v1 (i.e. `styles/palette.styl` and `styles/index.styl`) is no longer provided by VuePress Core. - -The palette system is extracted to [@vuepress/plugin-palette](https://ecosystem.vuejs.press/plugins/palette.html). - -Theme authors can use their own way to allow users to customize styles, and not be limited with stylus. - -If you are using default theme, the palette system is still available but migrated to SASS, while most variables have been migrated to CSS variables. See [Default Theme > Styles](https://ecosystem.vuejs.press/themes/default/styles.html). - -### Conventional Files Change - -#### .vuepress/enhanceApp.js - -Renamed to `.vuepress/client.{js,ts}`, and the usage has been changed, too. - -See [Advanced > Cookbook > Usage of Client Config](../advanced/cookbook/usage-of-client-config.md). - -#### .vuepress/components/ - -Files in this directory will not be registered as Vue components automatically. - -You need to use [@vuepress/plugin-register-components](https://ecosystem.vuejs.press/plugins/register-components.html), or register your components manually in `.vuepress/client.{js,ts}`. - -#### .vuepress/theme/ - -This directory will not be used as local theme implicitly if it is existed. - -You need to import and set your local theme via [theme](../reference/config.md#theme) option. - -### Markdown Change - -- Markdown slot is no longer supported. -- Markdown image syntax does not support webpack aliases anymore. Links without `./` prefix are also treated as relative links, which is aligned with the behavior of the native markdown image syntax. If you want to use aliases in image paths, or use images from external packages, you should use ` ` tag instead. - -```diff --  --  - -+
-+
-``` - -### CLI Change - -#### eject command - -Removed. - -#### cache options - -- `-c, --cache [cache]`: changed to `--cache
`, which means that the shorthand `-c` is not for `cache` option, and the value of `cache` option is not optional. -- `--no-cache`: renamed to `--clean-cache` . - -### Default Theme Change - -#### Built-in Components - -- ` ` and ` ` are replaced by [code tab feature](https://ecosystem.vuejs.press/themes/default/markdown.html#code-tabs) -- ` ` - - `$badgeErrorColor` palette variable renamed to `$badgeDangerColor` - - `type` prop only accepts `tip`, `warning` and `danger` now - -#### Palette System - -The palette system of default theme has migrated to SASS and CSS variables. - -See [Default Theme > Styles](https://ecosystem.vuejs.press/themes/default/styles.html). - -#### Theme Config - -Default theme config has been changed a lot. You'd better check the config reference of v2 default theme to migrate it properly. - -See [Default Theme > Config](https://ecosystem.vuejs.press/themes/default/config.html). - -Here we list some notable changes: - -##### Sidebar Config - -```diff -- sidebar: { -- title: 'Foo Bar', -- path: '/foo/bar.html', -- collapsable: true, -- children: [ -- ['/baz', 'Baz'], -- ], -- } - -+ sidebar: { -+ text: 'Foo Bar', -+ link: '/foo/bar.html', -+ collapsible: true, -+ children: [ -+ { -+ text: 'Baz', -+ link: '/baz', -+ } -+ ], -+ } -``` - -### Official Plugins Change - -Check the v2 docs of official plugins. - -### Community Themes and Plugins - -Themes and plugins of v1 are not compatible with v2. - -Please make sure that those themes and plugins you are using have supported v2, and refer to their own documentation for migration guide. - -## For Plugin Authors - -Some major breaking changes: - -- You cannot use other plugins in your plugin anymore, which avoids lots of potential issues caused by plugin nesting. If your plugin depends on other plugins, you could list them in the docs to ask users import them manually. Alternatively, you can provide users with an array of plugins for convenience. -- Most of the v1 hooks have equivalents in v2. The only exception is `extendsCli`, which has been removed. -- Webpack related hooks are removed, because VuePress Core has decoupled with webpack. You can try to use [extendsBundlerOptions](../reference/plugin-api.md#extendsbundleroptions) hook for similar purpose, and make sure to work with all bundlers. - -For more detailed guide about how to write a plugin in v2, see [Advanced > Writing a Plugin](../advanced/plugin.md). - -### Plugin API Change - -- `plugins`: removed -- `ready`: renamed to `onPrepared` -- `updated`: renamed to `onWatched` -- `generated`: renamed to `onGenerated` -- `additionalPages`: removed, use `app.pages.push(createPage())` in `onInitialized` hook -- `clientDynamicModules`: removed, use `app.writeTemp()` in `onPrepared` hook -- `enhanceAppFiles`: removed, use `clientConfigFile` hook -- `globalUIComponents`: removed, use `clientConfigFile` hook -- `clientRootMixin`: removed, use `clientConfigFile` hook -- `extendMarkdown`: renamed to `extendsMarkdown` -- `chainMarkdown`: removed -- `extendPageData`: renamed to `extendsPage` -- `extendsCli`: removed -- `configureWebpack`: removed -- `chainWebpack`: removed -- `beforeDevServer`: removed -- `afterDevServer`: removed - -See [Plugin API](../reference/plugin-api.md). - -## For Theme Authors - -Although we do not allow using other plugins in a plugin anymore, you can still use plugins in your theme. - -Some major breaking changes: - -- There is no **conventional theme directory structure** anymore. - - The file `theme/enhanceApp.js` will not be used as client app enhance file implicitly. You need to specify it explicitly in `clientConfigFile` hook. - - Files in `theme/global-components/` directory will not be registered as Vue components automatically. You need to use [@vuepress/plugin-register-components](https://ecosystem.vuejs.press/plugins/register-components.html), or register components manually in `clientConfigFile`. - - Files in `theme/layouts/` directory will not be registered as layout components automatically. You need to specify it explicitly in `layouts` option in `clientConfigFile`. - - Files in `theme/templates/` directory will not be used as dev / ssr template automatically. You need to specify theme explicitly in `templateBuild` and `templateDev` option. - - Always provide a valid js entry file, and do not use `"main": "layouts/Layout.vue"` as the theme entry anymore. -- `themeConfig` is removed from user config and site data. To access the `themeConfig` as you would via `this.$site.themeConfig` in v1, we now recommend using the [@vuepress/plugin-theme-data](https://ecosystem.vuejs.press/plugins/theme-data.html) plugin and its `useThemeData` composition API. -- Stylus is no longer the default CSS pre-processor, and the stylus palette system is not embedded. If you still want to use similar palette system as v1, [@vuepress/plugin-palette](https://ecosystem.vuejs.press/plugins/palette.html) may help. -- Markdown code blocks syntax highlighting by Prism.js is not embedded by default. You can use either [@vuepress/plugin-prismjs][prismjs] or [@vuepress/plugin-shiki][shiki], or implement syntax highlighting in your own way. -- For scalability concerns, `this.$site.pages` is not available any more. See [Advanced > Cookbook > Resolving Routes](../advanced/cookbook/resolving-routes.md) for how to retrieve pages data in v2. - -For more detailed guide about how to write a theme in v2, see [Advanced > Writing a Theme](../advanced/theme.md). - -### Theme API Change - -#### layouts - -Removed. - -Now you need to specify layout component in the client config file of your theme. - -See [Advanced > Writing a theme](../advanced/theme.md). - -#### extend - -Renamed to `extends`. - -You can still inherit a parent theme with `extends: parentTheme()`, which will extends the plugins, layouts, etc. - -You can refer to [Default Theme > Extending](https://ecosystem.vuejs.press/themes/default/extending.html) for how to extend default theme. - -The `@theme` and `@parent-theme` aliases are removed by default, but you can still make a extendable theme with similar approach, see [Advanced > Cookbook > Making a Theme Extendable](../advanced/cookbook/making-a-theme-extendable.md). - -[prismjs]: https://ecosystem.vuejs.press/plugins/prismjs.html -[shiki]: https://ecosystem.vuejs.press/plugins/shiki.html diff --git a/docs/guide/page.md b/docs/guide/page.md deleted file mode 100644 index f16469fd..00000000 --- a/docs/guide/page.md +++ /dev/null @@ -1,64 +0,0 @@ -# Page - -VuePress is markdown-centered. Each markdown file inside your project is a standalone page. - -## Routing - -By default, the route path of a page is determined by the relative path of your markdown file. - -Assuming this is the directory structure of your markdown files: - -``` -└─ docs - ├─ guide - │ ├─ getting-started.md - │ └─ README.md - ├─ contributing.md - └─ README.md -``` - -Take the `docs` directory as your [sourceDir](../reference/cli.md), e.g. you are running `vuepress dev docs` command. Then the route paths of your markdown files would be: - -| Relative Path | Route Path | -| --------------------------- | ----------------------------- | -| `/README.md` | `/` | -| `/index.md` | `/` | -| `/contributing.md` | `/contributing.html` | -| `/guide/README.md` | `/guide/` | -| `/guide/getting-started.md` | `/guide/getting-started.html` | - -::: tip -By default, both `README.md` and `index.md` would be converted to `index.html` and generate a slash-ending route path. However, it might cause conflicts if you want to keep both of the two files. - -In such case, you can set the [pagePatterns](../reference/config.md#pagepatterns) to avoid one of them being processed by VuePress, e.g. use `['**/*.md', '!**/README.md', '!.vuepress', '!node_modules']` to exclude all `README.md` files. - -Also, some symbols like `:` and `+` may have special meanings for vue-router, so you should avoid using them, see [vue-router docs](https://router.vuejs.org/guide/essentials/route-matching-syntax.html) for more details. -::: - -## Frontmatter - -A markdown file could contain a [YAML](https://yaml.org/) frontmatter. The frontmatter must be at the top of the Markdown file and must be wrapped with a couple of triple-dashed lines. Here is a basic example: - -```md ---- -lang: en-US -title: Title of this page -description: Description of this page ---- -``` - -You must have noticed that those fields are similar with the [Site Config](./configuration.md#site-config) in the [Config File](./configuration.md#config-file). You can override `lang`, `title`, `description`, etc., of current page via frontmatter. So you can take frontmatter as page scope config. - -Also, VuePress has built-in support for some frontmatter fields, and your theme may have its own special frontmatter, too. - -::: tip -Check out the [Frontmatter Reference](../reference/frontmatter.md) for a full list of VuePress built-in frontmatter. - -Check out the [Default Theme > Frontmatter Reference](https://ecosystem.vuejs.press/themes/default/frontmatter.html) for the frontmatter of default theme. -::: - -## Content - -The main content of your page is written in Markdown. VuePress will firstly transform your Markdown to HTML code, then treat the HTML code as `` of Vue SFC. - -With the power of [markdown-it](https://github.com/markdown-it/markdown-it) and Vue template syntax, the basic Markdown can be extended a lot. Next, check out the [Markdown](./markdown.md) guide for all the extensions of Markdown in VuePress. diff --git a/docs/guide/plugin.md b/docs/guide/plugin.md deleted file mode 100644 index 255d0214..00000000 --- a/docs/guide/plugin.md +++ /dev/null @@ -1,51 +0,0 @@ -# Plugin - -With the help of [Plugin API](../reference/plugin-api.md), VuePress plugin can provide different features for you. - -## Official Plugin - -VuePress team provides some official plugins. - -You need to import and use them in your config file via the [plugins](../reference/config.md#plugins) option. For example, use the [@vuepress/plugin-google-analytics](https://ecosystem.vuejs.press/plugins/analytics/google-analytics.html) to integrate Google Analytics: - -```ts -import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' - -export default { - plugins: [ - googleAnalyticsPlugin({ - id: 'G-XXXXXXXXXX', - }), - ], -} -``` - -::: tip -Most plugins can only be used once. If the same plugin is used multiple times, only the last one will take effect. - -However, some plugins can be used multiple times (e.g. [@vuepress/plugin-container](https://ecosystem.vuejs.press/plugins/container.html)), and you should check the documentation of the plugin itself for detailed guide. -::: - -## Community Plugin - -Community users have created lots of plugins and published them to [NPM](https://www.npmjs.com/search?q=keywords:vuepress-plugin). You should check the plugin's own documentation for detailed guide. - -You can explore more plugins in [VuePress Marketplace](https://marketplace.vuejs.press/plugins/). - -## Local Plugin - -If you want to use your own plugin but don't want to publish it, you can create a local plugin. - -It is recommended to use the [Config File](./configuration.md#config-file) directly as a plugin, because [almost all of the Plugin APIs are available](../reference/config.md#plugin-api), which would be more convenient in most cases. - -But if you have too many things to do in your config file, you can consider to extract them into separate plugins, and use them in your config file: - -```ts -import myPlugin from './path/to/my-plugin.js' - -export default { - plugins: [myPlugin()], -} -``` - -You can refer to [Advanced > Writing a Plugin](../advanced/plugin.md) for how to write your own plugin. diff --git a/docs/guide/theme.md b/docs/guide/theme.md deleted file mode 100644 index a1767d16..00000000 --- a/docs/guide/theme.md +++ /dev/null @@ -1,40 +0,0 @@ -# Theme - -VuePress theme can provide layouts, styles and many other features for you, helping you to focus on writing Markdown content. - -## Default Theme - -VuePress provides a default theme, which is applied to our documentation site you are currently browsing. - -You need to import and use it in your config file via the [theme](../reference/config.md#theme) option: - -```ts -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - theme: defaultTheme({ - // default theme config - navbar: [ - { - text: 'Home', - link: '/', - }, - ], - }), -}) -``` - -The default theme provides basic but useful features for documentation site, you can check out [Default Theme Config Reference](https://ecosystem.vuejs.press/themes/default/config.html) for a full list of config. - -However, you might think it is not good enough. Or, you want to build a different type of site, for example, a blog, instead of a documentation. Then, you can try to use a community theme or create a local theme. - -## Community Theme - -Community users have created lots of theme and published them to [NPM](https://www.npmjs.com/search?q=keywords:vuepress-theme). You should check the theme's own documentation for detailed guide. - -You can explore more themes in [VuePress Marketplace](https://marketplace.vuejs.press/themes/). - -## Local Theme - -If you want to use your own custom theme but don't want to publish it, you can create a local theme. Refer to [Advanced > Writing a Theme](../advanced/theme.md) for how to write your own theme. diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md deleted file mode 100644 index 160afa12..00000000 --- a/docs/guide/troubleshooting.md +++ /dev/null @@ -1,14 +0,0 @@ -# Troubleshooting - -## The bundler / theme option is missing? - -You need to set the bundler and theme to use explicitly in your config file. - -See the bundler reference for how to configure bundlers properly: - -- [Bundlers > Vite](../reference/bundler/vite.md) -- [Bundlers > Webpack](../reference/bundler/webpack.md) - -See the default theme reference for how to configure the default theme properly: - -- [Default Theme > Config](https://ecosystem.vuejs.press/themes/default/) diff --git a/docs/reference/bundler/vite.md b/docs/reference/bundler/vite.md deleted file mode 100644 index 846ba2da..00000000 --- a/docs/reference/bundler/vite.md +++ /dev/null @@ -1,47 +0,0 @@ -# Vite - - - -Vite bundler is provided by [@vuepress/bundler-vite](https://www.npmjs.com/package/@vuepress/bundler-vite) package. - -## Usage - -Install the bundler package: - -```bash -npm i -D @vuepress/bundler-vite@next -``` - -Specify the bundler option in your config file: - -```ts title=".vuepress/config.ts" -import { viteBundler } from '@vuepress/bundler-vite' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler({ - viteOptions: {}, - vuePluginOptions: {}, - }), -}) -``` - -## Options - -### viteOptions - -- Details: - - Accepts all options of Vite. - -- Also see: - - [Vite > Config](https://vite.dev/config/) - -### vuePluginOptions - -- Details: - - Accepts all options of [@vitejs/plugin-vue](https://www.npmjs.com/package/@vitejs/plugin-vue). - -- Also see: - - [Vite > Plugins > Official Plugins](https://vite.dev/plugins/#vitejs-plugin-vue) diff --git a/docs/reference/bundler/webpack.md b/docs/reference/bundler/webpack.md deleted file mode 100644 index eb30bd70..00000000 --- a/docs/reference/bundler/webpack.md +++ /dev/null @@ -1,148 +0,0 @@ -# Webpack - - - -Webpack bundler is provided by [@vuepress/bundler-webpack](https://www.npmjs.com/package/@vuepress/bundler-webpack) package. - -## Usage - -Install the bundler package: - -```bash -npm i -D @vuepress/bundler-webpack@next -``` - -Specify the bundler option in your config file: - -```ts title=".vuepress/config.ts" -import { webpackBundler } from '@vuepress/bundler-webpack' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: webpackBundler({ - postcss: {}, - vue: {}, - }), -}) -``` - -## Options - -### configureWebpack - -- Type: `(config: WebpackConfiguration, isServer: boolean, isBuild: boolean) => WebpackConfiguration | void` - -- Details: - - Edit the internal webpack config. - - This option accepts a function that will receive a webpack config object as the 1st argument, an `isServer` flag as the 2nd argument and an `isBuild` flag as the 3rd argument. You can either mutate the config directly, or return an object to be merged by [webpack-merge](https://github.com/survivejs/webpack-merge). - -### chainWebpack - -- Type: `(config: WebpackChainConfig, isServer: boolean, isBuild: boolean) => void` - -- Details: - - Edit the internal webpack config with [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain). - - This option accepts a function that will receive a `Config` instance that provided by `webpack-chain` as the 1st argument an `isServer` flag as the 2nd argument and an `isBuild` flag as the 3rd argument. - -### devServerSetupMiddlewares - -- Type: `(middlewares: Middleware[], devServer: Server) => Middleware[]` - -- Details: - - A hook to be called in `devServer.setupMiddlewares` of webpack. - - The arguments of the function are those of `devServer.setupMiddlewares`. - -- Also see: - - [Webpack > Configuration > DevServer > devServer.setupMiddlewares](https://webpack.js.org/configuration/dev-server/#devserversetupmiddlewares) - -### vue - -- Type: `VueLoaderOptions` - -- Details: - - Options for `vue-loader`. - -- Also see: - - [vue-loader > Options Reference](https://vue-loader.vuejs.org/options.html) - -### postcss - -- Type: `PostcssLoaderOptions` - -- Details: - - Options for `postcss-loader`. - -- Also see: - - [postcss-loader > Options](https://github.com/webpack-contrib/postcss-loader#options) - -### stylus - -- Type: `StylusLoaderOptions` - -- Details: - - Options for `stylus-loader`. - -- Also see: - - [stylus-loader > Options](https://github.com/webpack-contrib/stylus-loader#options) - -### scss - -- Type: `SassLoaderOptions` - -- Details: - - Options for `sass-loader` for `.scss` files. - -- Also see: - - [sass-loader > Options](https://github.com/webpack-contrib/sass-loader#options) - -### sass - -- Type: `SassLoaderOptions` - -- Details: - - Options for `sass-loader` for `.sass` files. - -- Also see: - - [sass-loader > Options](https://github.com/webpack-contrib/sass-loader#options) - -### less - -- Type: `LessLoaderOptions` - -- Details: - - Options for `less-loader`. - -- Also see: - - [less-loader > Options](https://github.com/webpack-contrib/less-loader#options) - -### evergreen - -- Type: `boolean` - -- Default: `true` - -- Details: - - Set to `true` if you are only targeting evergreen browsers. This will disable some transpilation and polyfills, and result in faster builds and smaller files. - -## FAQ - -### Referencing Public Files after Changing `base` - -Unlike Vite, Webpack won't handle `base` for public files automatically. So if you change the `base` of your site, you'd better to use [Base Helper](../../guide/assets.md#base-helper) when referencing an public image file. - -### Using with Default Theme - -Default theme is using [SASS](https://sass-lang.com/) as CSS pre-processor, so you might need to install [sass-loader](https://www.npmjs.com/package/sass-loader) as a peer dependency to make it work with Webpack, especially when you are using [pnpm](https://pnpm.io/). diff --git a/docs/reference/cli.md b/docs/reference/cli.md deleted file mode 100644 index 115bb0cc..00000000 --- a/docs/reference/cli.md +++ /dev/null @@ -1,85 +0,0 @@ -# Command Line Interface - -Run `vuepress --help` to get following help messages: - -``` -Usage: - $ vuepress [options] - -Commands: - dev [sourceDir] Start development server - build [sourceDir] Build to static site - info Display environment information - -For more info, run any command with the `--help` flag: - $ vuepress dev --help - $ vuepress build --help - $ vuepress info --help - -Options: - -v, --version Display version number - -h, --help Display this message -``` - -::: tip -VuePress is using [debug](https://www.npmjs.com/package/debug) module. - -Set environment variable `DEBUG=vuepress*` to enable debug logs. -::: - -## dev - -Start a development server to develop your VuePress site locally. - -``` -Usage: - $ vuepress dev [sourceDir] - -Options: - -c, --config Set path to config file - -p, --port Use specified port (default: 8080) - -t, --temp Set the directory of the temporary files - --host Use specified host (default: 0.0.0.0) - --cache Set the directory of the cache files - --clean-temp Clean the temporary files before dev - --clean-cache Clean the cache files before dev - --open Open browser when ready - --debug Enable debug mode - --no-watch Disable watching page and config files (default: true) - -v, --version Display version number - -h, --help Display this message -``` - -::: tip -Options set by CLI will override those options with the same name in your config file. -::: - -## build - -Build your VuePress site to static files, which are ready for [deployment](../guide/deployment.md). - -``` -Usage: - $ vuepress build [sourceDir] - -Options: - -c, --config Set path to config file - -d, --dest Set the directory build output (default: .vuepress/dist) - -t, --temp Set the directory of the temporary files - --cache Set the directory of the cache files - --clean-temp Clean the temporary files before build - --clean-cache Clean the cache files before build - --debug Enable debug mode - -v, --version Display version number - -h, --help Display this message -``` - -::: tip -Options set by CLI will override those options with the same name in your config file. -::: - -## info - -Outputs information about your system and dependencies. - -This command would be helpful when you want to check your environment or report an issue. diff --git a/docs/reference/client-api.md b/docs/reference/client-api.md deleted file mode 100644 index 3ce23a00..00000000 --- a/docs/reference/client-api.md +++ /dev/null @@ -1,238 +0,0 @@ -# Client API - -Client API can be imported from `vuepress/client`. - -## Composition API - -### useClientData - -- Details: - - Returns all the client data ref objects. - - Each property can also be accessed by the following composition APIs. - -- Example: - -```vue - -``` - -### usePageData - -- Details: - - Returns the page data ref object of current page. - -- Also see: - - [Node API > Page Properties > data](./node-api.md#data) - - [Plugin API > extendsPage](./plugin-api.md#extendspage) - -### usePageFrontmatter - -- Details: - - Returns the frontmatter ref object of current page. - - The value is the `frontmatter` property of the page data. - -### usePageHead - -- Details: - - Returns the head config ref object of current page. - - The value is obtained by merging and deduplicating [head](./frontmatter.md#head) frontmatter and [head](./config.md#head) config. - -### usePageHeadTitle - -- Details: - - Returns the head title ref object of current page. - - The value is obtained by joining the page title and site title. - -### usePageLang - -- Details: - - Returns the language ref object of current page. - - The value is the `lang` property of the page data. - -### useRoutes - -- Details: - - Returns the routes ref object. - - The value is the `routes` property of the site data. - -- Also see: - - [Advanced > Cookbook > Resolving Routes](../advanced/cookbook/resolving-routes.md) - -### useRouteLocale - -- Details: - - Returns the locale path ref object of current route. - - The value is one of the keys of the [locales](./config.md#locales) config. - -### useSiteData - -- Details: - - Returns the site data ref object. - -### useSiteLocaleData - -- Details: - - Returns the site data ref object of current locale. - - The properties of current locale have been merged into the root-level properties. - -### onContentUpdated - -- Details: - - When the content of the markdown file changes, the callback is triggered. - - This function can only be called during the `setup` phase of the component. - - ```vue - - ``` - -## Helpers - -### defineClientConfig - -- Details: - - Helper for creating [clientConfigFile](./plugin-api.md#clientconfigfile). - -- Also see: - - [Advanced > Cookbook > Usage of Client Config](../advanced/cookbook/usage-of-client-config.md) - -### resolveRoute - -- Details: - - Parses the route of the given link. - -- Also see: - - [Advanced > Cookbook > Resolving Routes](../advanced/cookbook/resolving-routes.md) - -### resolveRoutePath - -- Details: - - Parses the route path of the given link. - -- Also see: - - [Advanced > Cookbook > Resolving Routes](../advanced/cookbook/resolving-routes.md) - -### withBase - -- Details: - - Prefix URL with site [base](./config.md#base). - -- Also see: - - [Guide > Assets > Base Helper](../guide/assets.md#base-helper) - -## Constants - -There are some constants that available in the client side code. - -To shim the types of these constants in client side code, add `vuepress/client-types` to your `tsconfig.json`: - -```json -{ - "compilerOptions": { - "types": ["vuepress/client-types"] - } -} -``` - -### `__VUEPRESS_VERSION__` - -- Type: `string` - -- Details: - - Version of VuePress core package. - -### `__VUEPRESS_BASE__` - -- Type: `string` - -- Details: - - The [base](./config.md#base) option from config. - -### `__VUEPRESS_DEV__` - -- Type: `boolean` - -- Details: - - An environment flag indicating whether it is currently running in `dev` mode. - -### `__VUEPRESS_SSR__` - -- Type: `boolean` - -- Details: - - An environment flag indicating whether it is currently running in server-side-rendering (SSR) build. - -## Advanced - -### resolvers - -- Type: `Record ` - -- Details: - - An reactive object, methods of which determining how to resolve global computed. - -- Example: - -Customizing the format of ` ` in client config file: - -```ts -import { defineClientConfig, resolvers } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ app, router, siteData }) { - resolvers.resolvePageHeadTitle = (page, siteLocale) => - `${siteLocale.title} > ${page.title}` - }, -}) -``` - -::: danger -`resolvers` will affect the basic functionality of VuePress. Please make sure you have fully understood its purpose before modifying it. -::: diff --git a/docs/reference/components.md b/docs/reference/components.md deleted file mode 100644 index 210062a1..00000000 --- a/docs/reference/components.md +++ /dev/null @@ -1,158 +0,0 @@ -# Built-in Components - -## AutoLink - -- Props: - - - config - - Type: `AutoLinkConfig` - - Required: `true` - -```ts -interface AutoLinkConfig { - /** - * Pattern to determine if the link should be active, which has higher priority than `exact` - */ - activeMatch?: RegExp | string - - /** - * The `aria-label` attribute - */ - ariaLabel?: string - - /** - * Whether the link should be active only if the url is an exact match - */ - exact?: boolean - - /** - * URL of the auto link - */ - link: string - - /** - * The `rel` attribute - */ - rel?: string - - /** - * The `target` attribute - */ - target?: string - - /** - * Text of the auto link - */ - text: string -} -``` - -- Usage: - -```md - - - - default slot - - -- before slot - after slot - - -- {{ config.text }} - - -- {{ config.text }} - -``` - -- Details: - - This component will automatically render internal link as ``, and render external link as ``. It will also add necessary attributes correspondingly. - - You can make use of the `before` and `after` slots to render content before and after the text. Also, you can use the `default` slot to render the text (default text is `config.text`). - - This component is mainly for developing themes. Users won't need it in most cases. For theme authors, it's recommended to use this component to render links that could be either internal or external. - -## ClientOnly - -- Usage: - -```md - - -``` - -- Details: - - This component and its children will only be rendered in client-side. That means, it will not be rendered to HTML during build (SSR). - - If a component is trying to access Browser / DOM APIs directly in `setup()`, an error will occur during build because those APIs are unavailable in Node.js environment. In such case, you could do either: - - - Modify the component to only access Browser / DOM APIs in `onBeforeMount()` or `onMounted()` hook. - - Wrap the component with `- `. - -:::tip -Since Vue 3.5, if you only want to avoid hydration mismatch, you can try the new [data-allow-mismatch](https://blog.vuejs.org/posts/vue-3-5#data-allow-mismatch) attribute instead of ` ` component. -::: - -## Content - -- Props: - - - path - - Type: `string` - - Required: `false` - -- Usage: - -```md - -``` - -- Details: - - This component will render the Markdown content of a page. - - If the `path` prop is not provided, it will render the page content of current route. - - This component is mainly for developing themes. You won't need it in most cases. - -- Also see: - - [Node API > Page Properties > path](./node-api.md#path) - -## RouteLink - -- Props: - - - to - - Type: `string` - - Required: `true` - - active - - Type: `boolean` - - Required: `false` - - Default: `false` - - activeClass - - Type: `string` - - Required: `false` - - Default: `'route-link-active'` - -- Usage: - -```md - target page -current page -``` - -- Details: - - This component will render a link to the target page. - - If the `active` prop is set to `true`, the link will have an extra `activeClass`. Notice that the active status won't be updated automatically when the route changes. - - This component is mainly for developing themes. Users won't need it in most cases. For theme authors, it's recommended to use this component to render internal links instead of the `` component from `vue-router`. diff --git a/docs/reference/config.md b/docs/reference/config.md deleted file mode 100644 index 8addf8f9..00000000 --- a/docs/reference/config.md +++ /dev/null @@ -1,635 +0,0 @@ -# Config - -## Site Config - -### base - -- Type: `string` - -- Default: `/` - -- Details: - - The base URL the site will be deployed at. - - You will need to set this if you plan to deploy your site under a sub path. It should always start and end with a slash. For example, if you plan to deploy your site to GitHub pages at `https://foo.github.io/bar/`, then you should set `base` to `"/bar/"`. - - The `base` is automatically prepended to the URLs that start with `/` in other options, so you only need to specify it once. (Except for attrs of [head](#head)) - - Notice that `base` should be an absolute URL pathname starting and ending with `/` . - -- Also see: - - [Guide > Assets > Base Helper](../guide/assets.md#base-helper) - - [Guide > Deployment](../guide/deployment.md) - -### lang - -- Type: `string` - -- Default: `en-US` - -- Details: - - Language for the site. - - This will be the `lang` attribute of the `` tag in the rendered HTML. - - This can be specified in different locales. - -- Also see: - - [Config > locales](#locales) - - [Frontmatter > lang](./frontmatter.md#lang) - -### title - -- Type: `string` - -- Default: `''` - -- Details: - - Title for the site. - - This will be the suffix for all page titles, and displayed in the navbar in the default theme. - - This can be specified in different locales. - -- Also see: - - [Config > locales](#locales) - -### description - -- Type: `string` - -- Default: `''` - -- Details: - - Description for the site. - - This will be the `content` attribute of `` tag in the rendered HTML, which will be overrode by the `description` field of page frontmatter. - - This can be specified in different locales. - -- Also see: - - [Config > locales](#locales) - - [Frontmatter > description](./frontmatter.md#description) - -### head - -- Type: `HeadConfig[]` - -- Default: `[]` - -- Details: - - Extra tags to inject into the `` tag in the rendered HTML. - - You can specify each tag in the form of `[tagName, { attrName: attrValue }, innerHTML?]`. - - This can be specified in different locales. - - Notice that if the `attrValue` is a pathname, it will be kept as-is without prepending [base](#base) automatically, so remember to prepend it manually if needed. - -- Example: - - To add a custom favicon: - -```ts -export default { - head: [['link', { rel: 'icon', href: '/images/logo.png' }]], -} -``` - -Rendered as: - -```html - - - -``` - -- Also see: - - [Config > locales](#locales) - - [Frontmatter > head](./frontmatter.md#head) - -### locales - -- Type: `{ [path: string]: Partial }` - -- Default: `{}` - -- Details: - - Specify locales for i18n support. - - Acceptable fields: - - - [lang](#lang) - - [title](#title) - - [description](#description) - - [head](#head) - -- Also see: - - [Guide > I18n](../guide/i18n.md) - -## Theme Config - -### theme - -- Type: `Theme` - -- Details: - - Set the theme of your site. - - If this option is not set, the default theme will be used. - -- Also see: - - [Guide > Theme](../guide/theme.md) - - [Default Theme > Config](https://ecosystem.vuejs.press/themes/default/config.html) - -## Bundler Config - -### bundler - -- Type: `Bundler` - -- Details: - - Set the bundler of your site. - - If this option is not set, the default bundler will be used: - - - With `vuepress` or `vuepress-vite`, the default bundler is vite. - - With `vuepress-webpack`, the default bundler is webpack. - -- Also see: - - [Guide > Bundler](../guide/bundler.md) - - [Bundlers > Vite](./bundler/vite.md) - - [Bundlers > Webpack](./bundler/webpack.md) - -## Common Config - -### dest - -- Type: `string` - -- Default: `` `${sourceDir}/.vuepress/dist` `` - -- Details: - - Specify the output directory for `vuepress build` command. - -### temp - -- Type: `string` - -- Default: `` `${sourceDir}/.vuepress/.temp` `` - -- Details: - - Specify the directory for temporary files. - -::: warning -Since VuePress will load temp files during dev and build, the temp directory should be inside project root to resolve dependencies correctly. -::: - -### cache - -- Type: `string` - -- Default: `` `${sourceDir}/.vuepress/.cache` `` - -- Details: - - Specify the directory for cache files. - -### public - -- Type: `string` - -- Default: `` `${sourceDir}/.vuepress/public` `` - -- Details: - - Specify the directory for public files. - -- Also see: - - [Guide > Assets > Public Files](../guide/assets.md#public-files) - -### debug - -- Type: `boolean` - -- Default: `false` - -- Details: - - Enable debug mode or not. - - This would be helpful for developers. Also, we are using [debug](https://github.com/visionmedia/debug) package for debug logging, which can be enabled via `DEBUG=vuepress*` environment variable. - -### pagePatterns - -- Type: `string[]` - -- Default: `['**/*.md', '!.vuepress', '!node_modules']` - -- Details: - - Specify the patterns of files you want to be resolved as pages. The patterns are relative to the source directory. - -### permalinkPattern - -- Type: `string | null` - -- Default: `null` - -- Details: - - Specify the pattern to generate permalink. - - This will be overrode by the `permalinkPattern` field of page frontmatter. - -- Also see: - - [Frontmatter > permalinkPattern](./frontmatter.md#permalinkpattern) - -## Dev Config - -### host - -- Type: `string` - -- Default: `'0.0.0.0'` - -- Details: - - Specify the host to use for the dev server. - -### port - -- Type: `number` - -- Default: `8080` - -- Details: - - Specify the port to use for the dev server. - -### open - -- Type: `boolean` - -- Default: `false` - -- Details: - - Whether to open the browser after dev-server had been started. - -### templateDev - -- Type: `string` - -- Default: `'@vuepress/client/templates/dev.html'` - -- Details: - - Specify the path of the HTML template to be used for dev. - -## Build Config - -### shouldPreload - -- Type: `((file: string, type: string) => boolean)) | boolean` - -- Default: `true` - -- Details: - - A function to control what files should have `` resource hints generated. Set to `true` or `false` to enable or disable totally. - - By default, only those files that are required by current page will be preloaded. So you can keep it `true` in most cases. - -### shouldPrefetch - -- Type: `((file: string, type: string) => boolean)) | boolean` - -- Default: `true` - -- Details: - - A function to control what files should have `` resource hints generated. Set to `true` or `false` to enable or disable for all files. - - If you set it to `true`, all files that required by other pages will be prefetched. This is good for small sites, which will speed up the navigation, but it might not be a good idea if you have lots of pages in your site. - -### templateBuild - -- Type: `string` - -- Default: `'@vuepress/client/templates/build.html'` - -- Details: - - Specify the path of the HTML template to be used for build. - -### templateBuildRenderer - -- Type: `TemplateRenderer` - -- Default: `templateRenderer` - -- Details: - - Specify the HTML template renderer to be used for build. - -## Markdown Config - -### markdown - -- Type: `MarkdownOptions` - -- Default: `{}` - -- Details: - - Configure VuePress built-in Markdown syntax extensions. - - It accepts all options of [markdown-it](https://github.com/markdown-it/markdown-it), and the following additional options. - -- Also see: - - [markdown-it > Init with presets and options](https://github.com/markdown-it/markdown-it#init-with-presets-and-options) - - [Guide > Markdown > Syntax Extensions](../guide/markdown.md#syntax-extensions) - -### markdown.anchor - -- Type: `AnchorPluginOptions | false` - -- Default: - -```ts -const defaultOptions = { - level: [1, 2, 3, 4, 5, 6], - permalink: anchorPlugin.permalink.headerLink({ - class: 'header-anchor', - safariReaderFix: true, - }), -} -``` - -- Details: - - Options for [markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor). - - Set to `false` to disable this plugin. - -- Also see: - - [Guide > Markdown > Syntax Extensions > Header Anchors](../guide/markdown.md#header-anchors) - -### markdown.assets - -- Type: `AssetsPluginOptions | false` - -- Details: - - Options for VuePress built-in markdown-it assets plugin. - - Set to `false` to disable this plugin. - -::: danger -You should not configure it unless you understand what it is for. -::: - -### markdown.component - -- Type: `undefined | false` - -- Details: - - Options for [@mdit-vue/plugin-component](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-component). - - Set to `false` to disable this plugin. - -::: danger -You should not configure it unless you understand what it is for. -::: - -### markdown.emoji - -- Type: `EmojiPluginOptions | false` - -- Details: - - Options for [markdown-it-emoji](https://github.com/markdown-it/markdown-it-emoji). - - Set to `false` to disable this plugin. - -- Also see: - - [Guide > Markdown > Syntax Extensions > Emoji](../guide/markdown.md#emoji) - -### markdown.frontmatter - -- Type: `FrontmatterPluginOptions | false` - -- Details: - - Options for [@mdit-vue/plugin-frontmatter](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-frontmatter). - - Set to `false` to disable this plugin. - -- Also see: - - [Guide > Page > Frontmatter](../guide/page.md#frontmatter) - - [Node API > Page Properties > frontmatter](./node-api.md#frontmatter) - -::: danger -You should not configure it unless you understand what it is for. -::: - -### markdown.headers - -- Type: `HeadersPluginOptions | false` - -- Default: - -```ts -const defaultOptions = { - level: [2, 3], -} -``` - -- Details: - - Options for [@mdit-vue/plugin-headers](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers). - - Set to `false` to disable this plugin. - -- Also see: - - [Node API > Page Properties > headers](./node-api.md#headers) - -### markdown.importCode - -- Type: `ImportCodePluginOptions | false` - -- Details: - - Options for VuePress built-in markdown-it import-code plugin. - - Set to `false` to disable this plugin. - -- Also see: - - [Guide > Markdown > Syntax Extensions > Import Code Blocks](../guide/markdown.md#import-code-blocks) - -#### markdown.importCode.handleImportPath - -- Type: `(str: string) => string` - -- Default: `(str) => str` - -- Details: - - A function to handle the import path of the import code syntax. - -### markdown.links - -- Type: `LinksPluginOptions | false` - -- Details: - - Options for VuePress built-in markdown-it links plugin. - - It will convert the tag of internal links to [internalTag](#markdownlinksinternaltag), and add extra attributes and icon to external links. - - Set to `false` to disable this plugin. - -- Also see: - - [Guide > Markdown > Syntax Extensions > Links](../guide/markdown.md#links) - -#### markdown.links.internalTag - -- Type: `'a' | 'RouteLink' | 'RouterLink'` - -- Default: `'RouteLink'` - -- Details: - - Tag for internal links. - - By default, this plugin will transform internal links to [RouteLink](./components.md#routelink). - -#### markdown.links.externalAttrs - -- Type: `Record ` - -- Default: `{ target: '_blank', rel: 'noopener noreferrer' }` - -- Details: - - Additional attributes for external links. - -### markdown.sfc - -- Type: `SfcPluginOptions | false` - -- Details: - - Options for [@mdit-vue/plugin-sfc](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc). - - Set to `false` to disable this plugin. - -- Also see: - - [Cookbook > Markdown and Vue SFC](../advanced/cookbook/markdown-and-vue-sfc.md) - - [Node API > Page Properties > sfcBlocks](./node-api.md#sfcblocks) - -::: danger -You should not configure it unless you understand what it is for. -::: - -### markdown.slugify - -- Type: `(str: string) => string` - -- Details: - - The default slugify function. - -### markdown.title - -- Type: `undefined | false` - -- Details: - - Options for [@mdit-vue/plugin-title](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-title). - - Set to `false` to disable this plugin. - -::: danger -You should not configure it unless you understand what it is for. -::: - -### markdown.toc - -- Type: `TocPluginOptions | false` - -- Default: - -```ts -const defaultOptions = { - level: [2, 3], -} -``` - -- Details: - - Options for [@mdit-vue/plugin-toc](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc). - - Set to `false` to disable this plugin. - -- Also see: - - [Guide > Markdown > Syntax Extensions > Table of Contents](../guide/markdown.md#table-of-contents) - -#### markdown.vPre.block - -- Type: `boolean` - -- Default: `true` - -- Details: - - Add `v-pre` directive to ` ` tag of code block or not. - -- Also see: - - [Guide > Markdown > Syntax Extensions > Code Blocks > Wrap with v-pre](../guide/markdown.md#wrap-with-v-pre) - -#### markdown.vPre.inline - -- Type: `boolean` - -- Default: `true` - -- Details: - - Add `v-pre` directive to `` tag of inline code or not. - -- Also see: - - [Guide > Markdown > Syntax Extensions > Code Blocks > Wrap with v-pre](../guide/markdown.md#wrap-with-v-pre) - -## Plugin Config - -### plugins - -- Type: `(Plugin | Plugin[])[]` - -- Details: - - Plugins to use. - - This option accepts an array, each item of which could be a plugin or an array of plugins. - -- Also see: - - [Guide > Plugin](../guide/plugin.md) - -## Plugin API - -User config file also works as a VuePress plugin, so all of the Plugin APIs are available except the `name` and `multiple` options. - -Please check out [Plugin API Reference](./plugin-api.md) for a full list of Plugin APIs. diff --git a/docs/reference/frontmatter.md b/docs/reference/frontmatter.md deleted file mode 100644 index ac0a4c04..00000000 --- a/docs/reference/frontmatter.md +++ /dev/null @@ -1,213 +0,0 @@ -# Frontmatter - -## date - -- Type: `string` - -- Details: - - Created date for the page. - - You should specify the date in the form of `yyyy-MM-dd`, or follow the [YAML Timestamp Type](https://yaml.org/type/timestamp.html). - -- Also see: - - [Node API > Page Properties > date](./node-api.md#date) - -## description - -- Type: `string` - -- Details: - - Description for the page. - - This will override the `description` option in your site config. - -- Also see: - - [Config > description](./config.md#description) - -## head - -- Type: `HeadConfig[]` - -- Details: - - Extra tags in `` tag for the page. - -- Example: - -```md ---- -head: - - - meta - - name: foo - content: yaml array syntax - - [meta, { name: bar, content: square brackets syntax }] ---- -``` - -Rendered as: - -```html - - - - -``` - -- Also see: - - [Config > head](./config.md#head) - -## lang - -- Type: `string` - -- Details: - - Language for the page. - - This will override the `lang` option in your site config. - -- Also see: - - [Config > lang](./config.md#lang) - - [Node API > Page Properties > lang](./node-api.md#lang) - -## layout - -- Type: `string` - -- Details: - - Layout for the page. - - Layouts are provided by theme. If you don't specify this frontmatter, the default layout will be used. You should refer to the theme's own documentation to find what layouts it provides. - - If the theme layouts cannot meet your needs, you can use a custom layout component. - -- Example: - -Register a layout component in `.vuepress/client.ts` file: - -```ts -import { defineClientConfig } from 'vuepress/client' -import CustomLayout from './CustomLayout.vue' - -export default defineClientConfig({ - layouts: { - CustomLayout, - }, -}) -``` - -Set custom layout in frontmatter: - -```md ---- -layout: CustomLayout ---- -``` - -## permalink - -- Type: `string | null` - -- Details: - - Permalink for the page. - - This will override the default route path that determined by the file path of the page. - - When it is set to `null`, the permalink of the page will be disabled. - -- Also see: - - [Frontmatter > permalinkPattern](#permalinkpattern) - - [Guide > Page > Routing](../guide/page.md#routing) - - [Node API > Page Properties > permalink](./node-api.md#permalink) - -## permalinkPattern - -- Type: `string | null` - -- Details: - - Pattern to generate permalink for the page. - - This will override the `permalinkPattern` option in your site config. - - This won't take effect if the `permalink` frontmatter has been set. - -- Usage: - - | Pattern | Description | - | -------- | -------------------------- | - | `:year` | Year part of created date | - | `:month` | Month part of created date | - | `:day` | Day part of created date | - | `:slug` | Slug of page filename | - | `:raw` | Raw route path | - - The `:year`, `:month` and `:day` patterns are resolved according to the following priority: - - - The `date` frontmatter. - - The filename that matches the date pattern `yyyy-MM-dd-foobar.md` or `yyyy-MM-foobar.md`. - - The dirname that matches the date pattern `yyyy/MM/dd/foobar.md` or `yyyy/MM/foobar.md`. - - Fallback to `0000-00-00`. - -- Example 1: - - The page filename is `foo-bar.md`. - - The page frontmatter is: - -```md ---- -date: 2021-01-03 -permalinkPattern: :year/:month/:day/:slug.html ---- -``` - -Then the permalink of the page would be `2021/01/03/foo-bar.html`. - -- Example 2: - - The page filename is `2021-01-03-bar-baz.md`. - - The page frontmatter is: - -```md ---- -permalinkPattern: :year/:month/:day/:slug.html ---- -``` - -Then the permalink of the page would be `2021/01/03/bar-baz.html`. - -- Also see: - - [Config > permalinkPattern](./config.md#permalinkpattern) - - [Frontmatter > date](#date) - - [Frontmatter > permalink](#permalink) - - [Node API > Page Properties > permalink](./node-api.md#permalink) - -## routeMeta - -- Type: `Record
` - -- Details: - - Custom data to be attached to the page route. - -- Also see: - - [Node API > Page Properties > routeMeta](./node-api.md#routeMeta) - -## title - -- Type: `string` - -- Details: - - Title for the page. - - If you don't specify `title` in frontmatter, content of the first level-one header (i.e. `# title`) will be used as the title. - -- Also see: - - [Node API > Page Properties > title](./node-api.md#title) diff --git a/docs/reference/node-api.md b/docs/reference/node-api.md deleted file mode 100644 index 003b7df8..00000000 --- a/docs/reference/node-api.md +++ /dev/null @@ -1,643 +0,0 @@ -# Node API - -Node API can be imported from `vuepress/core`. - -## App - -The app instance is available in all hooks of [Plugin API](./plugin-api.md). - -The `BuildApp` and `DevApp` share almost the same properties and methods, except [build](#build) and [dev](#dev) method. - -### createBuildApp - -- Signature: - -```ts -const createBuildApp: (config: AppConfig) => BuildApp -``` - -- Parameters: - -| Parameter | Type | Description | -| --------- | ----------- | -------------------------------- | -| config | `AppConfig` | Config to create a VuePress app. | - -- Details: - - Create a build mode app instance, which is used for building static files. - -- Example: - -```ts -const build = async () => { - const app = createBuildApp({ - // ...options - }) - - // initialize and prepare - await app.init() - await app.prepare() - - // build - await app.build() - - // process onGenerated hook - await app.pluginApi.hooks.onGenerated.process(app) -} -``` - -- Also see: - - [Node API > App Methods > build](#build) - -### createDevApp - -- Signature: - -```ts -const createDevApp: (config: AppConfig) => DevApp -``` - -- Parameters: - -| Parameter | Type | Description | -| --------- | ----------- | -------------------------------- | -| config | `AppConfig` | Config to create a VuePress app. | - -- Details: - - Create a dev mode app instance, which is used for starting a dev server. - -- Example: - -```ts -const dev = async () => { - const app = createDevApp({ - // ...options - }) - - // initialize and prepare - await app.init() - await app.prepare() - - // start dev server - const closeDevServer = await app.dev() - - // set up file watchers - const watchers = [] - - // restart dev server - const restart = async () => { - await Promise.all([ - // close all watchers - ...watchers.map((item) => item.close()), - // close current dev server - closeDevServer(), - ]) - await dev() - } - - // process onWatched hook - await app.pluginApi.hooks.onWatched.process(app, watchers, restart) -} -``` - -- Also see: - - [Node API > App Methods > dev](#dev) - -## App Properties - -### options - -- Type: `AppOptions` - -- Details: - - Options of VuePress app. - - The options come from the `config` argument in [createBuildApp](#createbuildapp) / [createDevApp](#createdevapp), while all optional fields will be filled with a default value. - -### siteData - -- Type: `SiteData` - -- Details: - - Site data that set by user, including all the [site config](./config.md#site-config), which will be used in client side. - -### version - -- Type: `string` - -- Details: - - Version of VuePress app, i.e. version of `@vuepress/core` package. - -### env.isBuild - -- Type: `boolean` - -- Details: - - Environment flag used to identify whether the app is running in build mode, i.e. whether a [BuildApp](#createbuildapp) instance. - -### env.isDev - -- Type: `boolean` - -- Details: - - Environment flag used to identify whether the app is running in dev mode, i.e. whether a [DevApp](#createdevapp) instance. - -### env.isDebug - -- Type: `boolean` - -- Details: - - Environment flag used to identify whether the debug mode is enabled. - -### markdown - -- Type: `MarkdownIt` - -- Details: - - The [markdown-it](https://github.com/markdown-it/markdown-it) instance used for parsing markdown content. - - It is only available in and after [onInitialized](./plugin-api.md#oninitialized) hook. - -### pages - -- Type: `Page[]` - -- Details: - - The [Page](#page) object array. - - It is only available in and after [onInitialized](./plugin-api.md#oninitialized) hook. - -## App Methods - -### dir - -- Utils: - - - `dir.cache()`: resolve to cache directory - - `dir.temp()`: resolve to temp directory - - `dir.source()`: resolve to source directory - - `dir.dest()`: resolve to dest directory - - `dir.client()`: resolve to `@vuepress/client` directory - - `dir.public()`: resolve to public directory - -- Signature: - -```ts -type AppDirFunction = (...args: string[]) => string -``` - -- Details: - - Utils to resolve the absolute file path in corresponding directory. - - If you don't provide any arguments, it will return the absolute path of the directory. - -- Example: - -```ts -// resolve the absolute file path of the `${sourceDir}/README.md` -const homeSourceFile = app.dir.source('README.md') -``` - -### writeTemp - -- Signature: - -```ts -declare const writeTemp = (file: string, content: string) => Promise -``` - -- Parameters: - -| Parameter | Type | Description | -| --------- | -------- | ------------------------------------------------------------------------------- | -| file | `string` | Filepath of the temp file that going to be written. Relative to temp directory. | -| content | `string` | Content of the temp file that going to be written. | - -- Details: - - A method to write temp file. - - The written file could be imported via `@temp` alias in client files. - -- Example: - -```ts -export default { - // write temp file in onPrepared hook - async onPrepared() { - await app.writeTemp('foo.js', "export const foo = 'bar'") - }, -} -``` - -```ts -// import temp file in client code -import { foo } from '@temp/foo' -``` - -### init - -- Signature: - -```ts -declare const init = () => Promise -``` - -- Details: - - Initialize VuePress app. - -- Also see: - - [Advanced > Architecture > Core Process and Hooks](../advanced/architecture.md#core-process-and-hooks) - -### prepare - -- Signature: - -```ts -declare const prepare = () => Promise -``` - -- Details: - - Prepare client temp files. - -- Also see: - - [Advanced > Architecture > Core Process and Hooks](../advanced/architecture.md#core-process-and-hooks) - -### build - -- Signature: - -```ts -declare const build = () => Promise -``` - -- Details: - - Generate static site files. - - This method is only available in `BuildApp`. - -- Also see: - - [Node API > App > createBuildApp](#createbuildapp) - - [Advanced > Architecture > Core Process and Hooks](../advanced/architecture.md#core-process-and-hooks) - -### dev - -- Signature: - -```ts -declare const dev = () => Promise<() => Promise > -``` - -- Details: - - Start dev server. - - This method is only available in `DevApp`. - -- Also see: - - [Node API > App > createDevApp](#createdevapp) - - [Advanced > Architecture > Core Process and Hooks](../advanced/architecture.md#core-process-and-hooks) - -## Page - -### createPage - -- Signature: - -```ts -const createPage: (app: App, options: PageOptions) => Promise -``` - -- Parameters: - -| Parameter | Type | Description | -| --------- | ------------- | -------------------------------- | -| app | `App` | The VuePress app instance. | -| options | `PageOptions` | Options to create VuePress page. | - -- Details: - - Create a VuePress page object. - -- Example: - -```ts -import { createPage } from 'vuepress/core' - -export default { - // create an extra page in onInitialized hook - async onInitialized(app) { - app.pages.push( - await createPage(app, { - path: '/foo.html', - frontmatter: { - layout: 'Layout', - }, - content: `\ -# Foo Page - -Hello, world. -`, - }), - ) - }, -} -``` - -- Also see: - - [Node API > App Properties > pages](#pages) - - [Cookbook > Adding Extra Pages](../advanced/cookbook/adding-extra-pages.md) - -## Page Properties - -### path - -- Type: `string` - -- Details: - - Route path of the page. - -- Also see: - - [Guide > Page > Routing](../guide/page.md#routing) - - [Node API > Page Properties > pathInferred](#pathinferred) - -### title - -- Type: `string` - -- Details: - - Title of the page. - -- Also see: - - [Frontmatter > title](./frontmatter.md#title) - -### lang - -- Type: `string` - -- Details: - - Language of the page. - -- Example: - - - `'en-US'` - - `'zh-CN'` - -- Also see: - - [Frontmatter > lang](./frontmatter.md#title) - -### frontmatter - -- Type: `PageFrontmatter` - -- Details: - - Frontmatter of the page. - -- Also see: - - [Frontmatter](./frontmatter.md) - -### headers - -- Type: `PageHeader[]` - -```ts -interface PageHeader { - level: number - title: string - slug: string - children: PageHeader[] -} -``` - -- Details: - - Headers of the page. - -- Also see: - - [Config > markdown.headers](./config.md#markdown-headers) - -### data - -- Type: `PageData` - -```ts -interface PageData { - path: string - title: string - lang: string - frontmatter: PageFrontmatter -} -``` - -- Details: - - Data of the page. - - Page data would be available in client side. - -- Also see: - - [Client API > usePageData](./client-api.md#usepagedata) - - [Plugin API > extendsPage](./plugin-api.md#extendspage) - -### content - -- Type: `string` - -- Details: - - Raw content of the page. - -### contentRendered - -- Type: `string` - -- Details: - - Rendered content of the page. - -### date - -- Type: `string` - -- Details: - - Date of the page, in 'yyyy-MM-dd' format. - -- Example: - - - `'0000-00-00'` - - `'2021-08-16`' - -- Also see: - - [Frontmatter > date](./frontmatter.md#date) - -### deps - -- Type: `string[]` - -- Details: - - Dependencies of the page. - - For example, if users import code snippet in the page, the absolute file path of the imported file would be added to `deps`. - -- Also see: - - [Config > markdown.importCode](./config.md#markdown-importcode) - -### links - -- Type: `MarkdownLink[]` - -```ts -interface MarkdownLink { - raw: string - relative: string - absolute: string -} -``` - -- Details: - - Links included in the page content. - -### markdownEnv - -- Type: `Record ` - -- Details: - - The `env` object when parsing markdown content with markdown-it. - - Some markdown-it plugins may store extra information inside this object, and you can make use of them for advanced customization. - - Notice that some other page properties are also extracted from the original `env` object. Those properties have already been removed from `page.markdownEnv`. - -- Also see: - - [markdown-it > API Documentation > MarkdownIt > parse](https://markdown-it.github.io/markdown-it/#MarkdownIt.parse) - -### pathInferred - -- Type: `string | null` - -- Details: - - Route path of the page that inferred from file path. - - By default, the route path is inferred from the relative file path of the Markdown source file. However, users may explicitly set the route path, e.g. [permalink](#permalink), which would be used as the final route path of the page. So we keep the inferred path as a page property in case you may need it. - - It would be `null` if the page does not come from a Markdown source file. - -- Example: - - - `'/'` - - `'/foo.html'` - -- Also see: - - [Guide > Page > Routing](../guide/page.md#routing) - - [Node API > Page Properties > path](#path) - -### pathLocale - -- Type: `string` - -- Details: - - Locale prefix of the page route path. - - It is inferred from the relative file path of the Markdown source file and the key of `locales` option in user config. - -- Example: - - - `'/'` - - `'/en/'` - - `'/zh/'` - -- Also see: - - [Config > locales](./config.md#locales) - -### permalink - -- Type: `string | null` - -- Details: - - Permalink of the page. - -- Also see: - - [Frontmatter > permalink](./frontmatter.md#permalink) - - [Frontmatter > permalinkPattern](./frontmatter.md#permalinkpattern) - -### routeMeta - -- Type: `Record ` - -- Details: - - Custom data to be attached to the page route. - -- Also see: - - [Frontmatter > routeMeta](./frontmatter.md#routemeta) - -::: tip What's the difference between route meta and page data? -Both [route meta](#routemeta) and [page data](#data) is available in client side. However, route meta is attached to the page route record, so the route meta of all pages would be loaded at once when users enter your site. In the contrast, page data is saved in separated files, which would be loaded only when users enter the corresponding page. - -Therefore, it's not recommended to store large amounts of info into route meta, otherwise the initial loading speed will be affected a lot when your site has a large number of pages. -::: - -### sfcBlocks - -- Type: `MarkdownSfcBlocks` - -- Details: - - Extracted vue SFC blocks of the page. - -- Also see: - - [Config > markdown.sfc](./config.md#markdown-sfc) - -### slug - -- Type: `string` - -- Details: - - Slug of the page. - - It is inferred from the filename of the Markdown source file. - -### filePath - -- Type: `string | null` - -- Details: - - Absolute path of the Markdown source file of the page. - - It would be `null` if the page does not come from a Markdown source file. - -### filePathRelative - -- Type: `string | null` - -- Details: - - Relative path of the Markdown source file of the page. - - It would be `null` if the page does not come from a Markdown source file. diff --git a/docs/reference/plugin-api.md b/docs/reference/plugin-api.md deleted file mode 100644 index 0c5f5307..00000000 --- a/docs/reference/plugin-api.md +++ /dev/null @@ -1,363 +0,0 @@ -# Plugin API - -You could check out [Node API](./node-api.md) for how to use the VuePress app instance in plugin hooks. - -## Overview - -Plugins should be used before initialization. The basic options will be handled once the plugin is used: - -- [name](#name) -- [multiple](#multiple) - -The following hooks will be processed when initializing app: - -- [extendsMarkdownOptions](#extendsmarkdownoptions) -- [extendsMarkdown](#extendsmarkdown) -- [extendsPageOptions](#extendspageoptions) -- [extendsPage](#extendspage) -- [onInitialized](#oninitialized) - -The following hooks will be processed when preparing files: - -- [clientConfigFile](#clientconfigfile) -- [onPrepared](#onprepared) - -The following hooks will be processed in dev / build: - -- [extendsBundlerOptions](#extendsbundleroptions) -- [alias](#alias) -- [define](#define) -- [onWatched](#onwatched) -- [onGenerated](#ongenerated) - -> Check out [Advanced > Architecture > Core Process and Hooks](../advanced/architecture.md#core-process-and-hooks) to understand the process better. - -## Basic Options - -### name - -- Type: `string` - -- Details: - - Name of the plugin. - - It will be used for identifying plugins to avoid using a same plugin multiple times, so make sure to use a unique plugin name. - - It should follow the naming convention: - - - Non-scoped: `vuepress-plugin-foo` - - Scoped: `@org/vuepress-plugin-foo` - -- Also see: - - [Plugin API > multiple](#multiple) - -### multiple - -- Type: `boolean` - -- Default: `false` - -- Details: - - Declare whether the plugin can be used multiple times. - - If set to `false`, when using plugins with the same name, the one used previously will be replaced by the one used later. - - If set to `true`, plugins with the same name could be used multiple times and won't be replaced. - -- Also see: - - [Plugin API > name](#name) - -## Development Hooks - -### alias - -- Type: `Record | ((app: App, isServer: boolean) => Record )` - -- Details: - - Path aliases definition. - - This hook accepts an object or a function that returns an object. - -- Example: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - alias: { - '@alias': path.resolve(__dirname, './path/to/alias'), - }, -} -``` - -### clientConfigFile - -- Type: `string | ((app: App) => string | Promise )` - -- Details: - - Path of client config file. - - This hook accepts an absolute file path, or a function that returns the path. - -- Example: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - clientConfigFile: path.resolve(__dirname, './path/to/clientConfig.js'), -} -``` - -- Also see: - - [Client API > defineClientConfig](./client-api.md#defineclientconfig) - - [Advanced > Cookbook > Usage of Client Config](../advanced/cookbook/usage-of-client-config.md) - -### define - -- Type: `Record | ((app: App, isServer: boolean) => Record )` - -- Details: - - Define global constants replacements. - - This hook accepts an object or a function that returns an object. - - This can be useful for passing variables to client files. Note that the values will be automatically processed by `JSON.stringify()`. - -- Example: - -```ts -export default { - define: { - __GLOBAL_BOOLEAN__: true, - __GLOBAL_STRING__: 'foobar', - __GLOBAL_OBJECT__: { foo: 'bar' }, - }, -} -``` - -### extendsBundlerOptions - -- Type: `(options: BundlerOptions, app: App) => void | Promise ` - -- Details: - - Bundler options extension. - - This hook accepts a function that will receive the bundler options. - - This hook can be used for modifying bundler options. - - You could determine which bundler the user is using by `app.options.bundler.name`. - -- Example: - -Adding default [app.compilerOptions.isCustomElement](https://vuejs.org/api/application.html#app-config-compileroptions) option: - -```ts -export default { - extendsBundlerOptions: (bundlerOptions, app) => { - // extends options of @vuepress/bundler-vite - if (app.options.bundler.name === '@vuepress/bundler-vite') { - bundlerOptions.vuePluginOptions ??= {} - bundlerOptions.vuePluginOptions.template ??= {} - bundlerOptions.vuePluginOptions.template.compilerOptions ??= {} - const isCustomElement = - bundlerOptions.vuePluginOptions.template.compilerOptions.isCustomElement - bundlerOptions.vuePluginOptions.template.compilerOptions.isCustomElement = - (tag) => { - if (isCustomElement?.(tag)) return true - if (tag === 'my-custom-element') return true - } - } - - // extends options of @vuepress/bundler-webpack - if (app.options.bundler.name === '@vuepress/bundler-webpack') { - bundlerOptions.vue ??= {} - bundlerOptions.vue.compilerOptions ??= {} - const isCustomElement = bundlerOptions.vue.compilerOptions.isCustomElement - bundlerOptions.vue.compilerOptions.isCustomElement = (tag) => { - if (isCustomElement?.(tag)) return true - if (tag === 'my-custom-element') return true - } - } - }, -} -``` - -- Also see: - - [Bundlers > Vite](./bundler/vite.md) - - [Bundlers > Webpack](./bundler/webpack.md) - -### extendsMarkdownOptions - -- Type: `(options: MarkdownOptions, app: App) => void | Promise ` - -- Details: - - Markdown options extension. - - This hook accepts a function that will receive the markdown options. - - This hook can be used for modifying markdown options. - -- Example: - -Modifying the default header levels that going to be extracted: - -```ts -export default { - extendsMarkdownOptions: (markdownOptions, app) => { - if (markdownOptions.headers === false) return - markdownOptions.headers ??= {} - if (markdownOptions.headers.level) return - markdownOptions.headers.level = [2, 3, 4, 5, 6] - }, -} -``` - -- Also see: - - [Config > markdown](./config.md#markdown) - -### extendsMarkdown - -- Type: `(md: Markdown, app: App) => void | Promise ` - -- Details: - - Markdown enhancement. - - This hook accepts a function that will receive an instance of `Markdown` powered by [markdown-it](https://github.com/markdown-it/markdown-it) in its arguments. - - This hook can be used for using extra markdown-it plugins and implementing customizations. - -- Example: - -```ts -export default { - extendsMarkdown: (md) => { - md.use(plugin1) - md.linkify.set({ fuzzyEmail: false }) - }, -} -``` - -### extendsPageOptions - -- Type: `(options: PageOptions, app: App) => void | Promise ` - -- Details: - - Page options extension. - - This hook accepts a function that will receive the options of `createPage`. - - This hook can be used for modifying page options - -- Example: - -Set permalink pattern for pages in `_posts` directory: - -```ts -export default { - extendsPageOptions: (pageOptions, app) => { - if (pageOptions.filePath?.startsWith(app.dir.source('_posts/'))) { - pageOptions.frontmatter = pageOptions.frontmatter ?? {} - pageOptions.frontmatter.permalinkPattern = '/:year/:month/:day/:slug.html' - } - }, -} -``` - -- Also see: - - [Node API > Page > createPage](./node-api.md#createpage) - -### extendsPage - -- Type: `(page: Page, app: App) => void | Promise ` - -- Details: - - Page extension. - - This hook accepts a function that will receive a `Page` instance. - - This hook can be used for adding extra properties or modifying current properties on `Page` object. - - Notice that changes to `page.data` and `page.routeMeta` can be used in client side code. - -- Example: - -```ts -export default { - extendsPage: (page) => { - page.foo = 'foo' - page.data.bar = 'bar' - }, -} -``` - -In client component: - -```ts -import { usePageData } from 'vuepress/client' - -export default { - setup() { - const page = usePageData() - console.log(page.value.bar) // bar - }, -} -``` - -- Also see: - - [Client API > usePageData](./client-api.md#usepagedata) - - [Node API > Page Properties > data](./node-api.md#data) - - [Node API > Page Properties > routeMeta](./node-api.md#routemeta) - -## Lifecycle Hooks - -### onInitialized - -- Type: `(app: App) => void | Promise ` - -- Details: - - This hook will be invoked once VuePress app has been initialized. - -### onPrepared - -- Type: `(app: App) => void | Promise ` - -- Details: - - This hook will be invoked once VuePress app has finished preparation. - -### onWatched - -- Type: `(app: App, watchers: Closable[], restart: () => Promise ) => void | Promise ` - -- Details: - - This hook will be invoked once VuePress app has started dev-server and watched files change. - - The `watchers` is an array of file watchers. When changing config file, the dev command will be restarted and those watchers will be closed. If you are adding new watchers in this hook, you should push your watchers to the `watchers` array, so that they can be closed correctly when restarting. - - The `restart` is a method to restart the dev command. When calling this method, the `watchers` array will be closed automatically. - -### onGenerated - -- Type: `(app: App) => void | Promise ` - -- Details: - - This hook will be invoked once VuePress app has generated static files. diff --git a/docs/reference/theme-api.md b/docs/reference/theme-api.md deleted file mode 100644 index 71d212a6..00000000 --- a/docs/reference/theme-api.md +++ /dev/null @@ -1,105 +0,0 @@ -# Theme API - -A VuePress theme also works as a plugin, so Theme API can accept all the options of [Plugin API](./plugin-api.md) with following differences. - -## Basic Options - -### name - -- Type: `string` - -- Details: - - Name of the theme. - - It should follow the naming convention, and ensure consistency with the package name when publishing to NPM: - - - Non-scoped: `vuepress-theme-foo` - - Scoped: `@org/vuepress-theme-foo` - -### multiple - -- Details: - - A theme should never be used multiple times, so this option is not supported in theme API. - -## Theme Specific Options - -### extends - -- Type: `Theme` - -- Details: - - The theme to inherit. - - All of the Theme API of the parent theme will be inherited, but the child theme will not override the parent theme directly. Theme specific options will override according to following rules: - - - [plugins](#plugins): When a same plugin is used in both child and parent theme, if the plugin does not support to be used multiple times, only the one used in the child theme will take effect. - - [templateBuild](#templatebuild) / [templateDev](#templatedev): Child theme templates will override parent theme templates. - - Multi-level inheritance is supported, i.e. theme B could be extended from theme A, and then theme C could be extended from theme B. In other words, a theme could have a parent theme, a grandparent theme and so on. - -- Example: - -```ts -import { defaultTheme } from '@vuepress/theme-default' -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - // inherit the default theme - extends: defaultTheme(), -} -``` - -### plugins - -- Type: `(Plugin | Plugin[])[]` - -- Details: - - Plugins to use in the theme. - -- Also see: - - [Config > plugins](./config.md#plugins) - -### templateBuild - -- Type: `string` - -- Details: - - Specify the path of the HTML template for build. - - It would override the default value of [templateBuild](./config.md#templatebuild), and could be overridden by user config. - -- Also see: - - [Config > templateBuild](./config.md#templatebuild) - -### templateBuildRenderer - -- Type: `TemplateRenderer` - -- Details: - - Specify the HTML template renderer to be used for build. - - It would override the default value of [templateBuildRenderer](./config.md#templatebuildrenderer), and could be overridden by user config. - -- Also see: - - [Config > templateBuildRenderer](./config.md#templatebuildrenderer) - -### templateDev - -- Type: `string` - -- Details: - - Specify the HTML template for dev. - - It would override the default value of [templateDev](./config.md#templatedev), but could be overridden by user config. - -- Also see: - - [Config > templateDev](./config.md#templatedev) diff --git a/docs/zh/README.md b/docs/zh/README.md deleted file mode 100644 index f54edcac..00000000 --- a/docs/zh/README.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -home: true -title: 首页 -heroImage: /images/hero.png -actions: - - text: 快速上手 - link: /zh/guide/getting-started.html - type: primary - - - text: 项目简介 - link: /zh/guide/introduction.html - type: secondary - -features: - - title: 简洁至上 - details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。 - - - title: Vue 驱动 - details: 享受 Vue 的开发体验,可以在 Markdown 中使用 Vue 组件,又可以使用 Vue 来开发自定义主题。 - - - title: 高性能 - details: VuePress 会为每个页面预渲染生成静态的 HTML,同时,每个页面被加载的时候,将作为 SPA 运行。 - - - title: 主题 - details: 提供了一个开箱即用的默认主题。你也可以挑选一个社区主题,或者创建一个你自己的主题。 - - - title: 插件 - details: 灵活的插件API,使得插件可以为你的站点提供许多即插即用的功能。 - - - title: 打包工具 - details: 推荐的打包工具是 Vite ,但也同样支持使用 Webpack 。选一个你喜欢的来使用吧! - -footer: MIT 协议 | 版权所有 © 2018-至今 VuePress 社区 ---- diff --git a/docs/zh/advanced/architecture.md b/docs/zh/advanced/architecture.md deleted file mode 100644 index a1debf6a..00000000 --- a/docs/zh/advanced/architecture.md +++ /dev/null @@ -1,36 +0,0 @@ -# 架构 - -## 概览 - - - -上图展示了 VuePress 的简要架构: - -- Node App 会生成临时文件,包括页面、路由等。 -- Bundler 会将 Client App 和临时文件一起进行打包,就像处理一个普通的 Vue App 一样。 - -作为开发者,你必须要意识到 VuePress 分为两个主要部分: **Node App** 和 **Client App** ,这一点对于开发插件和主题来说都十分重要。 - -- 插件或者主题的入口文件会在 Node App 中被加载。 -- 客户端文件会在 Client App 中被加载,也就是会被 Bundler 处理。比如组件、客户端配置文件等。 - -## 核心流程与 Hooks - - - -上图展示了 VuePress 的核心流程以及 [插件 API](../reference/plugin-api.md) 的 Hooks : - -- 在 **init** 阶段: - - 主题和插件会被加载。这意味着插件需要在初始化之前使用。 - - 由于我们要使用 markdown-it 来解析 Markdown 文件,因此需要在加载页面文件之前创建 markdown-it 实例: - - [extendsMarkdownOptions](../reference/plugin-api.md#extendsmarkdownoptions) Hook 会被调用,用以创建 markdown-it 实例。 - - [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) Hook 会被调用,用以扩展 markdown-it 实例。 - - 页面文件会被加载: - - [extendsPageOptions](../reference/plugin-api.md#extendspageoptions) Hook 会被调用,用以创建页面。 - - [extendsPage](../reference/plugin-api.md#extendspage) Hook 会被调用,用以扩展页面对象。 -- 在 **prepare** 阶段: - - 临时文件会被生成,因此所有和客户端文件相关的 Hooks 会在此处调用。 -- 在 **dev / build** 阶段: - - Bundler 会被加载: - - [extendsBundlerOptions](../reference/plugin-api.md#extendsbundleroptions) Hook 会被调用,用以生成 Bundler 的配置。 - - [alias](../reference/plugin-api.md#alias) Hook 和 [define](../reference/plugin-api.md#define) Hook 会被用在 Bundler 的配置中,所以它们会在此处调用。 diff --git a/docs/zh/advanced/cookbook/README.md b/docs/zh/advanced/cookbook/README.md deleted file mode 100644 index 8c108c03..00000000 --- a/docs/zh/advanced/cookbook/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# 介绍 - -## Cookbook 的目的是什么? - -- 我们在 **指南** 中介绍了基本概念,但你可能不知道怎么才能了解得更深入。 -- 我们在 **参考** 中列出了 API ,但你可能不知道如何充分利用它们。 - -于是就有了 Cookbook 。 - -每个案例都会针对某个特定的方面,通过提供更详细的示例来向你展示 VuePress 的用法和其他可能性。 diff --git a/docs/zh/advanced/cookbook/adding-extra-pages.md b/docs/zh/advanced/cookbook/adding-extra-pages.md deleted file mode 100644 index ec7129ad..00000000 --- a/docs/zh/advanced/cookbook/adding-extra-pages.md +++ /dev/null @@ -1,38 +0,0 @@ -# 添加额外页面 - -有时你可能希望在不创建 Markdown 文件的情况下添加一些额外的页面。 - -我们可以借助于 [插件 API](../../reference/plugin-api.md) 和 [Node API](../../reference/node-api.md) 来轻松实现。 - -## 添加默认的主页 - -作为一个主题作者,你可能不想要求用户必须创建一个 `/README.md` 文件来作为主页,但是你希望提供一个默认的主页: - -```ts -import { createPage } from 'vuepress/core' - -export default { - // 初始化之后,所有的页面已经加载完毕 - async onInitialized(app) { - // 如果主页不存在 - if (app.pages.every((page) => page.path !== '/')) { - // 创建一个主页 - const homepage = await createPage(app, { - path: '/', - // 设置 frontmatter - frontmatter: { - layout: 'Layout', - }, - // 设置 markdown 内容 - content: `\ -# 欢迎来到 ${app.options.title} - -这是默认主页 -`, - }) - // 把它添加到 `app.pages` - app.pages.push(homepage) - } - }, -} -``` diff --git a/docs/zh/advanced/cookbook/making-a-theme-extendable.md b/docs/zh/advanced/cookbook/making-a-theme-extendable.md deleted file mode 100644 index a3de57b3..00000000 --- a/docs/zh/advanced/cookbook/making-a-theme-extendable.md +++ /dev/null @@ -1,64 +0,0 @@ -# 开发一个可继承的主题 - -有时用户可能希望对一个主题进行一些小改动,但是又不想 Fork 并修改整个项目。 - -借助于 [主题 API](../../reference/theme-api.md) ,你可以让用户继承你的主题,允许用户对你的主题进行改动。 - -你肯定已经知道了如何 [继承默认主题](https://ecosystem.vuejs.press/zh/themes/default/extending.html) 。接下来我们将介绍如何让你的主题像默认主题一样被用户继承。 - -## 布局插槽 - -这种方式需要你来决定主题的哪些部分是可以被扩展的,它更适合用于一些常见的自定义需求,比如页眉或页脚。 - -你只需要在你的布局文件中提供 slots ,并告诉用户如何使用它们即可: - -```vue - - -- -``` - -## 组件别名 - -这种方式需要你考虑清楚你的主题的哪些组件可以被替换,并且你需要将组件拆分到合适的粒度。 - -首先,为你主题的可替换组件设置 `alias` 别名: - -```ts -import type { Theme } from 'vuepress/core' -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export const fooTheme = (options): Theme => ({ - name: 'vuepress-theme-foo', - alias: { - // 为可替换的组件设置别名 - '@theme/Navbar.vue': path.resolve(__dirname, 'components/Navbar.vue'), - '@theme/Sidebar.vue': path.resolve(__dirname, 'components/Sidebar.vue'), - }, -}) -``` - -然后,在你的主题中通过别名来使用这些组件: - -```vue - - - -- - - -- -``` - -这样,用户在继承或使用你的主题时,就可以通过覆盖 `alias` 来替换特定的组件了。 diff --git a/docs/zh/advanced/cookbook/markdown-and-vue-sfc.md b/docs/zh/advanced/cookbook/markdown-and-vue-sfc.md deleted file mode 100644 index 9d88fde1..00000000 --- a/docs/zh/advanced/cookbook/markdown-and-vue-sfc.md +++ /dev/null @@ -1,79 +0,0 @@ -# Markdown 与 Vue SFC - -每一个 Markdown 文件,首先都会编译为 HTML ,然后转换为一个 Vue 单文件组件 (SFC) 。换句话说,你可以像写 Vue SFC 一样来写 Markdown 文件: - -- ` - - -``` - -**输出** - -_你好, {{ msg }}_ - -- - - - -_当前计数为: {{ count }}_ - - - - - - - - diff --git a/docs/zh/advanced/cookbook/passing-data-to-client-code.md b/docs/zh/advanced/cookbook/passing-data-to-client-code.md deleted file mode 100644 index d22dfa47..00000000 --- a/docs/zh/advanced/cookbook/passing-data-to-client-code.md +++ /dev/null @@ -1,66 +0,0 @@ -# 向客户端代码传递数据 - -我们知道,VuePress 插件入口和主题入口是在 Node 端处理的,但有时候你可能需要向客户端动态传递数据。例如,你希望在用户传入不同的选项时生成不同的数据。 - -## 使用 `define` Hook - -插件 API 提供了一个 [define](../../reference/plugin-api.md#define) Hook 来定义客户端代码中的全局常量。你可以利用它来向客户端传递数据。 - -首先,通过 `define` Hook 定义一些常量: - -```ts -export default (options) => ({ - define: { - __FOO__: options.foo || 'str', - __OBJ__: { - bar: options.bar || 123, - }, - }, -}) -``` - -然后,在客户端代码中直接使用它们: - -```ts -const foo = __FOO__ -const obj = __OBJ__ -``` - -如果你在客户端代码中使用 TypeScript ,你可能需要手动声明这些全局常量的类型: - -```ts -declare const __FOO__: string -declare const __OBJ__: { bar: number } -``` - -## 写入并加载临时文件 - -如果你需要实现一些更复杂的功能,你可以写入临时文件,并在客户端代码中动态加载它们。 - -首先,写入一个名为 `foo.js` 的临时文件,它将会生成在 [temp](../../reference/config.md#temp) 目录中: - -```ts -export default (options) => ({ - async onPrepared(app) { - // 写入临时文件 - await app.writeTemp( - 'foo.js', - `export const foo = ${JSON.stringify(options.foo)}`, - ) - }, -}) -``` - -然后,在客户端代码中通过 `@temp` 别名来加载临时文件: - -```ts -import { foo } from '@temp/foo' -``` - -如果你在客户端代码中使用 TypeScript ,你可能需要手动声明这些临时模块的类型: - -```ts -declare module '@temp/foo' { - export const foo: string -} -``` diff --git a/docs/zh/advanced/cookbook/resolving-routes.md b/docs/zh/advanced/cookbook/resolving-routes.md deleted file mode 100644 index 7ec8e7ac..00000000 --- a/docs/zh/advanced/cookbook/resolving-routes.md +++ /dev/null @@ -1,50 +0,0 @@ -# 解析路由 - -## 获取全部路由 - -在开发主题和插件时,你可能希望获取所有页面的信息。通过 [useRoutes](../../reference/client-api.md#useroutes) 就可以获取所有页面的路由记录。 - -`useRoutes` 的返回值是一个包含了所有路由信息的 Ref 对象。其属性是每条路由的路由路径,对应的值是路径的路由信息。 - -```ts -import { useRoutes } from 'vuepress/client' - -const routes = useRoutes() -// { -// '/': { meta: { title: 'Home' }, loader: HomePageLoader }, -// '/404.html': { meta: { title: 'Not Found' }, loader: NotFoundPageLoader }, -// ... -// } - -const routePaths = computed(() => Object.keys(routes.value)) -// => [’/‘, '/404.html', '/foo/', '/bar/', ...] -``` - -## 解析路由地址 - -你可以使用 [resolveRoutePath](../../reference/client-api.md#resolveroutepath) 来解析给定的链接对应的路由路径。 - -`resolveRoutePath` 接收一个链接地址和一个可选的基础路径,返回一个解析后的路由地址: - -```ts -import { resolveRoutePath } from 'vuepress/client' - -const routePath = resolveRoutePath('/foo/') // => '/foo/' -const routePath = resolveRoutePath('baz.html', '/foo/bar.html') // => '/foo/baz.html' -``` - -## 解析路由信息 - -你可以使用 [resolveRoute](../../reference/client-api.md#resolveroute) 来解析给定的链接对应的路由信息。 - -`resolveRoute` 接收一个链接地址和一个可选的基础路径,返回一个解析后的路由信息: - -```ts -import { resolveRoute } from 'vuepress/client' - -const route = resolveRoute('/foo/') // => { notFound: false, path: '/foo/', meta: { title: 'Foo' }, loader: FooPageLoader } -const route = resolveRoute('baz.html', '/foo/bar.html') // => { notFound: false, path: '/foo/baz.html', meta: { title: 'Baz' }, loader: BazPageLoader } -const route = resolveRoute('/not-exist.html') // => { notFound: true, path: '/not-exist.html', meta: { title: 'Not Found' }, loader: NotFoundPageLoader } -``` - -路由信息中存在一个 `notFound` 字段,用于标识给定的路径是否存在对应的路由。当路由不存在时,返回值中的 `notFound` 字段为 `true`,其 `path` 字段为规范化后的路径,而 `meta` 和 `loader` 字段则会指向默认的 404 页面。 diff --git a/docs/zh/advanced/cookbook/usage-of-client-config.md b/docs/zh/advanced/cookbook/usage-of-client-config.md deleted file mode 100644 index 26dab64b..00000000 --- a/docs/zh/advanced/cookbook/usage-of-client-config.md +++ /dev/null @@ -1,174 +0,0 @@ -# 客户端配置的使用方法 - -你可以直接在你的项目中使用 [客户端配置文件](../../guide/configuration.md#客户端配置文件) 。或者,在你的插件或者主题中,使用 [clientConfigFile](../../reference/plugin-api.md#clientconfigfile) Hook 来指定客户端配置文件的路径: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -const pluginOrTheme = { - clientConfigFile: path.resolve(__dirname, './path/to/clientConfig.ts'), -} -``` - -在客户端配置文件中,`vuepress/client` 提供了一个 [defineClientConfig](../../reference/client-api.md#defineclientconfig) 函数来帮助你定义客户端配置: - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ app, router, siteData }) {}, - setup() {}, - layouts: {}, - rootComponents: [], -}) -``` - -## enhance - -`enhance` 函数既可以是同步的,也可以是异步的。它接收一个 Context 参数,包含以下属性: - -- `app` 是由 [createApp](https://staging-cn.vuejs.org/api/application.html#create-app) 创建的 Vue 应用实例。 -- `router` 是由 [createRouter](https://router.vuejs.org/zh/api/index.html#createrouter) 创建的路由实例。 -- `siteData` 是一个根据用户配置生成的 Ref 对象,包含 [base](../../reference/config.md#base), [lang](../../reference/config.md#lang), [title](../../reference/config.md#title), [description](../../reference/config.md#description), [head](../../reference/config.md#head) 和 [locales](../../reference/config.md#locales)。 - -`enhance` 函数会在客户端应用创建后被调用,你可以对 Vue 应用添加各种能力。 - -### 注册 Vue 组件 - -你可以通过 [app.component](https://staging-cn.vuejs.org/api/application.html#app-component) 方法来注册 Vue 全局组件: - -```ts -import { defineClientConfig } from 'vuepress/client' -import MyComponent from './MyComponent.vue' - -export default defineClientConfig({ - enhance({ app }) { - app.component('MyComponent', MyComponent) - }, -}) -``` - -### 使用不支持 SSR 的功能 - -VuePress 会在构建过程中生成一个 SSR 应用,用以对页面进行预渲染。一般而言,如果一段代码在客户端应用 Mount 之前就使用了浏览器或 DOM API ,我们就认为其对 SSR 不友好,即不支持 SSR 。 - -我们已经提供了一个 [ClientOnly](../../reference/components.md#clientonly) 组件来包裹不支持 SSR 的内容。 - -在 `enhance` 函数中,你可以使用 [`__VUEPRESS_SSR__`](../../reference/client-api.md#ssr) 标记来处理这种情况。 - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - async enhance() { - if (!__VUEPRESS_SSR__) { - const nonSsrFriendlyModule = await import('non-ssr-friendly-module') - // ... - } - }, -}) -``` - -### 使用 Router 方法 - -你可以使用 vue-router 提供的 [Router 方法](https://router.vuejs.org/zh/api/index.html#router-方法) 。例如,添加导航钩子: - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ router }) { - router.beforeEach((to) => { - console.log('before navigation') - }) - - router.afterEach((to) => { - console.log('after navigation') - }) - }, -}) -``` - -::: warning -我们不推荐使用 `addRoute` 方法来添加动态路由,因为这些路由记录 **不会** 在构建模式中被预渲染出来。 - -当然,如果你了解了这种用法的缺点,你还是可以这样使用。 -::: - -## setup - -`setup` 函数会在客户端 Vue 应用的 [setup](https://staging-cn.vuejs.org/api/composition-api-setup.html) Hook 中被调用。 - -### 使用组合式 API - -你可以把 `setup` 函数当作根组件的 [setup](https://staging-cn.vuejs.org/api/composition-api-setup.html) Hook 中的一部分。因此,所有的组合式 API 都可以在这里使用。 - -```ts -import { provide, ref } from 'vue' -import { useRoute, useRouter } from 'vue-router' -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - setup() { - // 获取当前的路由位置 - const route = useRoute() - // 或者 vue-router 实例 - const router = useRouter() - // 供给一个值,可以被布局、页面和其他组件注入 - const count = ref(0) - provide('count', count) - }, -}) -``` - -### 使用不支持 SSR 的功能 - -在 `setup` 函数中,[`__VUEPRESS_SSR__`](../../reference/client-api.md#ssr) 标记同样可用。 - -使用不支持 SSR 的功能的另一种方式就是将他们放在 [onMounted](https://staging-cn.vuejs.org/api/composition-api-lifecycle.html#onmounted) Hook 中: - -```ts -import { onMounted } from 'vue' -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - setup() { - onMounted(() => { - // 在 mounted 之后使用 DOM API - document.querySelector('#app') - }) - }, -}) -``` - -## layouts - -`layouts` 配置项用于设置布局组件。你在此处注册布局后,用户就可以通过 [layout](../../reference/frontmatter.md#layout) frontmatter 来使用它们。 - -```ts -import { defineClientConfig } from 'vuepress/client' -import MyLayout from './layouts/MyLayout.vue' - -export default defineClientConfig({ - layouts: { - MyLayout, - }, -}) -``` - -## rootComponents - -`rootComponents` 是一个组件数组,它们将会直接被放置在客户端 Vue 应用的根节点下。 - -该选项的典型使用方式就是放置一些全局的 UI 组件,比如全局弹窗等: - -```ts -import { defineClientConfig } from 'vuepress/client' -import GlobalPopup from './components/GlobalPopup.vue' - -export default defineClientConfig({ - rootComponents: [GlobalPopup], -}) -``` diff --git a/docs/zh/advanced/plugin.md b/docs/zh/advanced/plugin.md deleted file mode 100644 index 36a095bb..00000000 --- a/docs/zh/advanced/plugin.md +++ /dev/null @@ -1,53 +0,0 @@ -# 开发插件 - -::: tip -在阅读该指南之前,你最好先了解一下 VuePress 的 [架构](./architecture.md) 。 -::: - -## 创建一个插件 - -插件是一个符合 [插件 API](../reference/plugin-api.md) 的普通 JavaScript 对象,称之为 _插件对象_ : - -```ts -const fooPlugin = { - name: 'vuepress-plugin-foo', - // ... -} -``` - -插件还可以是一个接收 [App 实例](../reference/node-api.md#app) 作为参数,且返回值为 _插件对象_ 的函数,称之为 _插件函数_ : - -```ts -const barPlugin = (app) => ({ - name: 'vuepress-plugin-bar', - // ... -}) -``` - -插件通常需要允许用户传入配置,因此我们一般都会提供给用户一个函数来接收配置,然后将 _插件对象_ 或者 _插件函数_ 作为返回值。于是,你的插件应该转换成这样的形式: - -```ts -const fooPlugin = (options) => ({ - name: 'vuepress-plugin-foo', - // ... -}) - -const barPlugin = (options) => (app) => ({ - name: 'vuepress-plugin-bar', - // ... -}) -``` - -## 发布到 NPM - -在创建了插件之后,你需要在 [package.json](https://docs.npmjs.com/cli/v8/configuring-npm/package-json) 文件中遵循一定的约定,然后再将其发布到 NPM 上: - -```json -{ - "name": "vuepress-plugin-foo", - "keywords": ["vuepress-plugin"] -} -``` - -- 将 `name` 按照约定命名,即 `vuepress-plugin-xxx` 或 `@org/vuepress-plugin-xxx` ,它应该和 _插件对象_ 的 [name](../reference/plugin-api.md#name) 字段保持一致。 -- 在 `keywords` 中包含 `vuepress-plugin` ,这样用户可以在 NPM 上搜索到你的插件。 diff --git a/docs/zh/advanced/theme.md b/docs/zh/advanced/theme.md deleted file mode 100644 index 239b6f68..00000000 --- a/docs/zh/advanced/theme.md +++ /dev/null @@ -1,95 +0,0 @@ -# 开发主题 - -::: tip -在阅读该指南之前,你最好先了解一下 [开发插件](./plugin.md) 指南。 -::: - -## 创建一个主题 - -VuePress 主题是一个特殊的插件,它应该符合 [主题 API](../reference/theme-api.md) 。和插件一样,主题可以是一个 _主题对象_ 或一个 _主题函数_ ,并且通常通过一个函数来接收配置项: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -const fooTheme = (options) => - // 返回一个主题对象 - ({ - name: 'vuepress-theme-foo', - - // 主题的客户端配置文件的路径 - clientConfigFile: path.resolve(__dirname, 'client.js'), - - // 设置自定义 dev / build 模板 - // 如果没有指定模板,将会使用默认模板 - templateBuild: path.resolve(__dirname, 'templates/build.html'), - templateDev: path.resolve(__dirname, 'templates/dev.html'), - - // 使用插件 - plugins: [ - // ... - ], - - // 其他的插件 API 也都可用 - }) - -const barTheme = - (options) => - // 返回一个主题函数 - (app) => ({ - name: 'vuepress-theme-bar', - // ... - }) -``` - -然后,创建主题的客户端配置文件 `client.js` : - -```ts -import { defineClientConfig } from 'vuepress/client' -import Layout from './layouts/Layout.vue' -import NotFound from './layouts/NotFound.vue' - -export default defineClientConfig({ - layouts: { - Layout, - NotFound, - }, -}) -``` - -`layouts` 字段声明了你的主题提供的布局。一个主题必须提供至少两个布局:`Layout` 和 `NotFound` 。前者用于提供一般页面的默认布局,后者用于提供 404 页面的布局。 - -`Layout` 布局应该包含 [Content](../reference/components.md#content) 组件来展示 Markdown 内容: - -```vue - --- -``` - -`NotFound` 布局会被用于 `404.html` 页面: - -```vue - -- 404 Not Found- -``` - -你可以提供多个布局,用户可以通过 [layout](../reference/frontmatter.md#layout) Frontmatter 来修改布局。 - -## 发布到 NPM - -同样的,对于主题也有 [package.json](https://docs.npmjs.com/cli/v8/configuring-npm/package-json) 相关的约定: - -```json -{ - "name": "vuepress-theme-foo", - "keywords": ["vuepress-theme"] -} -``` - -- 将 `name` 按照约定命名: `vuepress-theme-xxx` 或 `@org/vuepress-theme-xxx` ,它应该和 _主题对象_ 的 [name](../reference/theme-api.md#name) 字段保持一致。 -- 在 `keywords` 中包含 `vuepress-theme` ,这样用户可以在 NPM 上搜索到你的主题。 diff --git a/docs/zh/guide/assets.md b/docs/zh/guide/assets.md deleted file mode 100644 index 611cda86..00000000 --- a/docs/zh/guide/assets.md +++ /dev/null @@ -1,126 +0,0 @@ -# 静态资源 - -## 相对路径 - -你可以在你的 Markdown 内容中使用相对路径来引用静态资源: - -```md - -``` - -或 - -```md - -``` - -一般情况下,我们推荐你使用这种方式来引用图片,因为人们通常会把图片放在引用它的 Markdown 文件附近。 - -## Public 文件 - -你可以把一些静态资源放在 Public 目录中,它们会被复制到最终生成的网站的根目录下。 - -默认的 Public 目录是 `.vuepress/public` ,可以通过 [public](../reference/config.md#public) 配置项来修改。 - -在下列这些情况中,你可能会用到它: - -- 你可能需要提供一些静态资源,但是它们并不直接被你的 Markdown 文件引用,比如 favicon 和 PWA 图标。 -- 你可能想要托管一些共享的静态资源,甚至可能需要在你的网站外部引用它,比如 Logo 图片。 -- 你可能想在你的 Markdown 内容中通过绝对路径来引入图片。 - -以我们文档的源文件为例,我们把 VuePress 的 Logo 放在了 Public 目录下: - -```bash -└─ docs - ├─ .vuepress - | └─ public - | └─ images - | └─ hero.png # <- Logo 文件 - └─ guide - └─ assets.md # <- 我们在这里 -``` - -我们可以这样在当前页面引用 Logo : - -**Input** - -```md - -``` - -**Output** - - - -### Base Helper - -如果你的网站部署在非根路径下,例如 `https://foo.github.io/bar/` ,那么你应该把 [base](../reference/config.md#base) 设置为 `'/bar/'`。显然,此时你的 Public 文件会被部署在 `https://foo.github.io/bar/images/hero.png` 这样的链接下。 - -在大多数情况下,你不需要担心这些 Public 文件的引用路径,因为 VuePress 会自动帮你处理 `base` 前缀: - -```md - - - -``` - -::: tip -在使用 [Webpack 打包工具](../reference/bundler/webpack.md) 时,你需要将 [markdown.assets.absolutePathPrependBase](../reference/config.md#markdown-assets) 设置为 `true` 来给 Markdown 图片自动添加 `base` 前缀。 -::: - -然而,有些情况下,你可能会有一些指向 Public 文件的动态路径,尤其是在你开发一个自定义主题的时候。在这种情况下, `base` 无法被自动处理。为了解决这个问题,VuePress 提供了 [withBase](../reference/client-api.md#withbase) 工具函数,它可以帮助你添加 `base` 前缀: - -```vue - - - -- -``` - -你也可以通过 `$withBase` 来直接使用这个工具函数: - -```md -
-``` - -## 依赖包和路径别名 - -尽管这不是常见用法,但是你可以从依赖包中引用图片: - -```bash -npm install -D package-name -``` - -由于 Markdown 会默认将图片链接视为相对链接,你需要使用 `
` 标签: - -```md -
-``` - -在配置文件中设置的路径别名也同样支持: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - alias: { - '@alias': path.resolve(__dirname, './path/to/some/dir'), - }, -} -``` - -```md -
-``` - -::: tip -配置参考: [alias](../reference/plugin-api.md#alias) -::: diff --git a/docs/zh/guide/bundler.md b/docs/zh/guide/bundler.md deleted file mode 100644 index 4291d8a3..00000000 --- a/docs/zh/guide/bundler.md +++ /dev/null @@ -1,59 +0,0 @@ -# 打包工具 - -VuePress 支持使用 [Vite](https://vite.dev/) 或 [Webpack](https://webpack.js.org/) 作为打包工具来进行网站的开发和构建。你可以根据自己的喜好来选择使用哪个打包工具,并且不需要进行额外的配置。 - -## 安装打包工具 - -在安装 [vuepress](https://www.npmjs.com/package/vuepress) 包时,并不会自动安装打包工具,你需要选择并安装一个打包工具。 - -::: code-tabs#shell - -@tab pnpm - -```bash -# 安装 vite 打包工具 -pnpm add -D vuepress@next @vuepress/bundler-vite@next -# 安装 webpack 打包工具 -pnpm add -D vuepress@next @vuepress/bundler-webpack@next -``` - -@tab yarn - -```bash -# 安装 vite 打包工具 -yarn add -D vuepress@next @vuepress/bundler-vite@next -# 安装 webpack 打包工具 -yarn add -D vuepress@next @vuepress/bundler-webpack@next -``` - -@tab npm - -```bash -# 安装 vite 打包工具 -npm install -D vuepress@next @vuepress/bundler-vite@next -# 安装 webpack 打包工具 -npm install -D vuepress@next @vuepress/bundler-webpack@next -``` - -::: - -## 使用打包工具 - -一般情况下,你不要任何额外配置就可以使用打包工具,因为我们已经帮你配置好了它们。 - -你只需要通过 [bundler](../reference/config.md#bundler) 配置项指定打包工具即可: - -```ts -import { viteBundler } from '@vuepress/bundler-vite' -// import { webpackBundler } from '@vuepress/bundler-webpack' - -export default { - bundler: viteBundler(), - // bundler: webpackBundler(), -} -``` - -当你需要对打包工具进行进阶配置时,只需要传入对应的配置项即可: - -- [打包工具 > Vite](../reference/bundler/vite.md) -- [打包工具 > Webpack](../reference/bundler/webpack.md) diff --git a/docs/zh/guide/configuration.md b/docs/zh/guide/configuration.md deleted file mode 100644 index 21214b21..00000000 --- a/docs/zh/guide/configuration.md +++ /dev/null @@ -1,86 +0,0 @@ -# 配置 - -## 配置文件 - -VuePress 站点的基本配置文件是 `.vuepress/config.js` ,但也同样支持 TypeScript 配置文件。你可以使用 `.vuepress/config.ts` 来得到更好的类型提示。 - -具体而言,我们对于配置文件的路径有着约定(按照优先顺序): - -- 当前工作目录 `cwd` 下: - - `vuepress.config.ts` - - `vuepress.config.js` - - `vuepress.config.mjs` -- 源文件目录 `sourceDir` 下: - - `.vuepress/config.ts` - - `.vuepress/config.js` - - `.vuepress/config.mjs` - -你也可以通过 [命令行接口](../reference/cli.md) 的 `--config` 选项来指定配置文件: - -```bash -vuepress dev docs --config my-config.ts -``` - -一个基础的配置文件是这样的: - -```ts -import { viteBundler } from '@vuepress/bundler-vite' -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler(), - theme: defaultTheme(), - - lang: 'zh-CN', - title: '你好, VuePress !', - description: '这是我的第一个 VuePress 站点', -}) -``` - -::: tip -前往 [配置参考](../reference/config.md) 查看所有 VuePress 配置。 -::: - -## 客户端配置文件 - -在大多数情况下,配置文件已经足够帮助你配置好你的 VuePress 站点。不过,有些时候用户们可能希望直接添加一些客户端代码。 VuePress 通过客户端配置文件来支持这种需求: - -``` -├─ docs -│ ├─ .vuepress -│ │ ├─ client.js <--- 客户端配置文件 -│ │ └─ config.js <--- 配置文件 -│ └─ README.md -├─ .gitignore -└─ package.json -``` - -同样的,我们也有关于客户端配置文件的路径约定(按照优先顺序): - -- 当前工作目录 `cwd` 下: - - `vuepress.client.ts` - - `vuepress.client.js` - - `vuepress.client.mjs` -- 源文件目录 `sourceDir` 下: - - `.vuepress/client.ts` - - `.vuepress/client.js` - - `.vuepress/client.mjs` - -一个基础的客户端配置文件是这样的: - -```ts -import { defineClientConfig } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ app, router, siteData }) {}, - setup() {}, - rootComponents: [], -}) -``` - -::: tip -和配置文件不同,客户端配置文件不能通过命令行接口的选项来指定。 - -可以前往 [深入 > Cookbook > 客户端配置的使用方法](../advanced/cookbook/usage-of-client-config.md) 来了解更多信息。 -::: diff --git a/docs/zh/guide/deployment.md b/docs/zh/guide/deployment.md deleted file mode 100644 index 347f3ea2..00000000 --- a/docs/zh/guide/deployment.md +++ /dev/null @@ -1,265 +0,0 @@ -# 部署 - -下述的指南基于以下条件: - -- Markdown 源文件放置在你项目的 `docs` 目录; -- 使用的是默认的构建输出目录 (`.vuepress/dist`) ; -- 使用 [pnpm](https://pnpm.io/zh/) 作为包管理器,当然也支持使用 npm 或 yarn 。 -- VuePress 作为项目依赖安装,并在 `package.json` 中配置了如下脚本: - -```json -{ - "scripts": { - "docs:build": "vuepress build docs" - } -} -``` - -## GitHub Pages - -1. 设置正确的 [base](../reference/config.md#base) 选项。 - - 如果你准备发布到 `https://
.github.io/` ,你可以省略这一步,因为 `base` 默认就是 `"/"` 。 - - 如果你准备发布到 `https:// .github.io/ /` ,也就是说你的仓库地址是 `https://github.com/ / ` ,则将 `base` 设置为 `"/ /"`。 - -2. 选择你想要使用的 CI 工具。这里我们以 [GitHub Actions](https://github.com/features/actions) 为例。 - - 创建 `.github/workflows/docs.yml` 文件来配置工作流。 - -::: details 点击展开配置样例 - -```yaml -name: docs - -on: - # 每当 push 到 main 分支时触发部署 - push: - branches: [main] - # 手动触发部署 - workflow_dispatch: - -jobs: - docs: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - # “最近更新时间” 等 git 日志相关信息,需要拉取全部提交记录 - fetch-depth: 0 - - - name: 设置 pnpm - uses: pnpm/action-setup@v4 - - - name: 设置 Node.js - uses: actions/setup-node@v4 - with: - # 选择要使用的 node 版本 - node-version: 22 - # 缓存 pnpm 依赖 - cache: pnpm - - - name: 安装依赖 - run: pnpm install --frozen-lockfile - - # 运行构建脚本 - - name: 构建 VuePress 站点 - run: pnpm docs:build - - # 查看 workflow 的文档来获取更多信息 - # @see https://github.com/crazy-max/ghaction-github-pages - - name: 部署到 GitHub Pages - uses: crazy-max/ghaction-github-pages@v4 - with: - # 部署到 gh-pages 分支 - target_branch: gh-pages - # 部署目录为 VuePress 的默认输出目录 - build_dir: docs/.vuepress/dist - env: - # @see https://docs.github.com/cn/actions/reference/authentication-in-a-workflow#about-the-github_token-secret - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -``` - -::: - -::: tip -请参考 [GitHub Pages 官方指南](https://pages.github.com/) 来获取更多信息。 -::: - -## GitLab Pages - -1. 设置正确的 [base](../reference/config.md#base) 选项。 - - 如果你准备发布到 `https:// .gitlab.io/` ,你可以省略这一步,因此 `base` 默认就是 `"/"` 。 - - 如果你准备发布到 `https:// .gitlab.io/ /` ,也就是说你的仓库地址是 `https://gitlab.com/ / ` ,则将 `base` 设置为 `"/ /"`。 - -2. 创建 `.gitlab-ci.yml` 文件来配置 [GitLab CI](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/) 工作流。 - -::: details 点击展开配置样例 - -```yaml -# 选择你要使用的 docker 镜像 -image: node:18-buster - -pages: - # 每当 push 到 main 分支时触发部署 - only: - - main - - # 缓存 node_modules - cache: - key: - files: - - pnpm-lock.yaml - paths: - - .pnpm-store - - # 安装 pnpm - before_script: - - curl -fsSL https://get.pnpm.io/install.sh | sh - - - pnpm config set store-dir .pnpm-store - - # 安装依赖并运行构建脚本 - script: - - pnpm install --frozen-lockfile - - pnpm docs:build --dest public - - artifacts: - paths: - - public -``` - -::: - -::: tip -请参考 [GitLab Pages 官方指南](https://docs.gitlab.com/ce/user/project/pages/#getting-started) 来获取更多信息。 -::: - -## Google Firebase - -1. 请确保你已经安装了 [firebase-tools](https://www.npmjs.com/package/firebase-tools)。 - -2. 在你项目的根目录下创建 `firebase.json` 和 `.firebaserc`,并包含以下内容: - -`firebase.json`: - -```json -{ - "hosting": { - "public": "./docs/.vuepress/dist", - "ignore": [] - } -} -``` - -`.firebaserc`: - -```json -{ - "projects": { - "default": " " - } -} -``` - -3. 在执行了 `pnpm docs:build` 后, 使用 `firebase deploy` 指令来部署。 - -::: tip -请参考 [Firebase CLI 官方指南](https://firebase.google.com/docs/cli) 来获取更多信息。 -::: - -## Heroku - -1. 首先安装 [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli); - -2. [在这里](https://signup.heroku.com) 注册一个 Heroku 账号; - -3. 运行 `heroku login` 并填写你的 Heroku 认证信息: - -```bash -heroku login -``` - -4. 在你的项目根目录中,创建一个名为 `static.json` 的文件,并包含下述内容: - -`static.json`: - -```json -{ - "root": "./docs/.vuepress/dist" -} -``` - -这里是你项目的配置,请参考 [heroku-buildpack-static](https://github.com/heroku/heroku-buildpack-static) 来获取更多信息。 - -## Kinsta - -请查看 [Set Up VuePress on Kinsta](https://kinsta.com/docs/vuepress-application/) 。 - -## Edgio - -请查看 [Edgio Documentation > Framework Guides > VuePress](https://docs.edg.io/guides/vuepress) 。 - -## Netlify - -1. 前往 [Netlify](https://netlify.com) ,从 GitHub 创建一个新项目,并进行如下配置: - - - **Build Command:** `pnpm docs:build` - - **Publish directory:** `docs/.vuepress/dist` - -2. 设置 [Environment variables](https://docs.netlify.com/configure-builds/environment-variables) 来选择 Node 版本: - - - `NODE_VERSION`: 20 - -3. 点击 deploy 按钮。 - -::: note - -你应该在 "Site Configuration" → "Build & Deploy" → "Post processing" 中禁用 Pretty URLs。 - -::: - -## Vercel - -1. 前往 [Vercel](https://vercel.com) ,从 GitHub 创建一个新项目,并进行如下配置: - - - **FRAMEWORK PRESET:** `Other` - - **BUILD COMMAND:** `pnpm docs:build` - - **OUTPUT DIRECTORY:** `docs/.vuepress/dist` - -2. 点击 deploy 按钮。 - - - -## 云开发 CloudBase - -[云开发 CloudBase](https://cloudbase.net/?site=vuepress) 是一个云原生一体化的 Serverless 云平台,支持静态网站、容器等多种托管能力,并提供简便的部署工具 [CloudBase Framework](https://cloudbase.net/framework.html?site=vuepress) 来一键部署应用。 - -1. 全局安装 CloudBase CLI : - -```bash -pnpm install -g @cloudbase/cli -``` - -2. 在项目根目录运行以下命令一键部署 VuePress 应用,在部署之前可以先 [开通环境](https://console.cloud.tencent.com/tcb/env/index?tdl_anchor=ad&tdl_site=vuejs): - -```bash -cloudbase init --without-template -cloudbase framework:deploy -``` - -CloudBase CLI 首先会跳转到控制台进行登录授权,然后将会交互式进行确认。 - -确认信息后会立即进行部署,部署完成后,可以获得一个自动 SSL,CDN 加速的网站应用,你也可以搭配使用 GitHub Action 来持续部署 GitHub 上的 VuePress 应用。 - -也可以使用 `cloudbase init --template vuepress` 快速创建和部署一个新的 VuePress 应用。 - -::: tip -更多详细信息请查看 CloudBase Framework 的[部署项目示例](https://github.com/TencentCloudBase/cloudbase-framework?site=vuepress#%E9%A1%B9%E7%9B%AE%E7%A4%BA%E4%BE%8B) -::: - -## 21 云盒子 - -请查看 [21 云盒子 - 部署一个 VuePress 静态网页](https://www.21yunbox.com/docs/#/deploy-vuepress)。 diff --git a/docs/zh/guide/getting-started.md b/docs/zh/guide/getting-started.md deleted file mode 100644 index d7708b37..00000000 --- a/docs/zh/guide/getting-started.md +++ /dev/null @@ -1,252 +0,0 @@ -# 快速上手 - -::: warning -VuePress v2 目前仍处于 RC (Release Candidate) 阶段。你已经可以用它来构建你的站点,但是它的配置和 API 还不够稳定,有可能会发生一些微小的 Breaking Changes 。因此,在每次更新 RC 版本之后,请一定要仔细阅读 [更新日志](https://github.com/vuepress/core/blob/main/CHANGELOG.md)。 -::: - -## 在线试一试 - -你可以通过 [StackBlitz](https://stackblitz.com/fork/vuepress) 在你的浏览器里直接使用 VuePress 。 - -## 安装 - -### 依赖环境 - -- [Node.js v20.6.0+](https://nodejs.org/) -- 包管理器,如 [pnpm](https://pnpm.io/zh/)、[yarn](https://classic.yarnpkg.com/en/)、[npm](https://www.npmjs.com/) 等。 - -::: tip - -- 使用 [pnpm](https://pnpm.io/zh/) 时,你需要安装 `vue` 作为 peer-dependencies 。 -- 使用 [yarn 2+](https://yarnpkg.com/) 时,你需要在 [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc#nodeLinker) 文件中设置 `nodeLinker: 'node-modules'` 。 - -::: - -### 创建项目 - -#### 通过命令行创建 - -你可以通过 [create-vuepress](https://www.npmjs.com/package/create-vuepress) 直接创建项目模板。 - -::: code-tabs#shell - -@tab pnpm - -```bash -pnpm create vuepress vuepress-starter -``` - -@tab yarn - -```bash -yarn create vuepress vuepress-starter -``` - -@tab npm - -```bash -npm init vuepress vuepress-starter -``` - -::: - -#### 手动创建 - -这一章节会帮助你从头搭建一个简单的 VuePress 文档网站。 - -- 创建并进入一个新目录 - -```bash -mkdir vuepress-starter -cd vuepress-starter -``` - -- 初始化项目 - -::: code-tabs#shell - -@tab pnpm - -```bash -git init -pnpm init -``` - -@tab yarn - -```bash -git init -yarn init -``` - -@tab npm - -```bash -git init -npm init -``` - -::: - -- 安装 VuePress - -::: code-tabs#shell - -@tab pnpm - -```bash -# 安装 vuepress 和 vue -pnpm add -D vuepress@next vue -# 安装打包工具和主题 -pnpm add -D @vuepress/bundler-vite@next @vuepress/theme-default@next -``` - -@tab yarn - -```bash -# 安装 vuepress -yarn add -D vuepress@next -# 安装打包工具和主题 -yarn add -D @vuepress/bundler-vite@next @vuepress/theme-default@next -``` - -@tab npm - -```bash -# 安装 vuepress -npm install -D vuepress@next -# 安装打包工具和主题 -npm install -D @vuepress/bundler-vite@next @vuepress/theme-default@next -``` - -::: - -- 创建 `docs` 目录和 `docs/.vuepress` 目录 - -```bash -mkdir docs -mkdir docs/.vuepress -``` - -- 创建 VuePress 配置文件 `docs/.vuepress/config.js` - -```ts -import { viteBundler } from '@vuepress/bundler-vite' -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler(), - theme: defaultTheme(), -}) -``` - -- 创建你的第一篇文档 - -```bash -echo '# Hello VuePress' > docs/README.md -``` - -## 目录结构 - -创建完成后,你项目的目录结构应该是这样的: - -``` -├─ docs -│ ├─ .vuepress -│ │ └─ config.js -│ └─ README.md -└─ package.json -``` - -`docs` 目录是你放置 Markdown 文件的地方,它同时也会作为 VuePress 的源文件目录。 - -`docs/.vuepress` 目录,即源文件目录下的 `.vuepress` 目录,是放置所有和 VuePress 相关的文件的地方。当前这里只有一个配置文件。默认还会在该目录下生成临时文件、缓存文件和构建输出文件。建议你把它们添加到 `.gitignore` 文件中。 - -::: details 示例 `.gitignore` 文件 - -``` -# VuePress 默认临时文件目录 -.vuepress/.temp -# VuePress 默认缓存目录 -.vuepress/.cache -# VuePress 默认构建生成的静态文件目录 -.vuepress/dist -``` - -::: - -## 开始使用 VuePress - -### 启动开发服务器 - -你可以在 `package.json` 中添加一些 [scripts](https://classic.yarnpkg.com/zh-Hans/docs/package-json#toc-scripts) : - -```json -{ - "scripts": { - "docs:dev": "vuepress dev docs", - "docs:build": "vuepress build docs" - } -} -``` - -运行 `docs:dev` 脚本可以启动开发服务器: - -::: code-tabs#shell - -@tab pnpm - -```bash -pnpm docs:dev -``` - -@tab yarn - -```bash -yarn docs:dev -``` - -@tab npm - -```bash -npm run docs:dev -``` - -::: - -VuePress 会在 [http://localhost:8080](http://localhost:8080) 启动一个热重载的开发服务器。当你修改你的 Markdown 文件时,浏览器中的内容也会自动更新。 - -### 构建你的网站 - -运行 `docs:build` 脚本可以构建你的网站: - -::: code-tabs#shell - -@tab pnpm - -```bash -pnpm docs:build -``` - -@tab yarn - -```bash -yarn docs:build -``` - -@tab npm - -```bash -npm run docs:build -``` - -::: - -在 `docs/.vuepress/dist` 目录中可以找到构建生成的静态文件。你可以查看 [部署](./deployment.md) 来了解如何部署你的网站。 - -## 进一步了解 VuePress - -现在,你应该已经有了一个简单可用的 VuePress 网站。但你可能仍需要阅读后续的指南来更加了解 VuePress 。 - -下一步,前往 [配置](./configuration.md) 了解更多配置文件相关的内容。 diff --git a/docs/zh/guide/i18n.md b/docs/zh/guide/i18n.md deleted file mode 100644 index c8ef6173..00000000 --- a/docs/zh/guide/i18n.md +++ /dev/null @@ -1,78 +0,0 @@ -# 多语言支持 - -## 站点多语言配置 - -要启用 VuePress 的多语言支持,首先需要使用如下的文件目录结构: - -``` -docs -├─ README.md -├─ foo.md -├─ nested -│ └─ README.md -└─ zh - ├─ README.md - ├─ foo.md - └─ nested - └─ README.md -``` - -然后,在你的 [配置文件](./configuration.md#配置文件) 中设置 `locales` 选项: - -```ts -export default { - locales: { - // 键名是该语言所属的子路径 - // 作为特例,默认语言可以使用 '/' 作为其路径。 - '/': { - lang: 'en-US', - title: 'VuePress', - description: 'Vue-powered Static Site Generator', - }, - '/zh/': { - lang: 'zh-CN', - title: 'VuePress', - description: 'Vue 驱动的静态网站生成器', - }, - }, -} -``` - -如果一个语言没有声明 `lang`, `title`, `description` 或者 `head` ,VuePress 将会尝试使用顶层配置的对应值。如果每个语言都声明了这些值,那么顶层配置中的对应值可以被省略。 - -::: tip -配置参考: [locales](../reference/config.md#locales) -::: - -## 主题多语言配置 - -VuePress 没有限制主题如何提供多语言支持,因此每个主题可能会有不同的多语言配置方式,而且部分主题可能不会提供多语言支持。建议你查看主题本身的文档来获取更详细的指引。 - -如果你使用的是默认主题,那么它提供多语言支持的方式和上述是一致的: - -```ts -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - theme: defaultTheme({ - locales: { - '/': { - selectLanguageName: 'English', - }, - '/zh/': { - selectLanguageName: '简体中文', - }, - }, - }), -}) -``` - -::: tip - -配置参考: - -- [默认主题 > 配置](https://ecosystem.vuejs.press/zh/themes/default/config.html) -- [默认主题 > 语言配置](https://ecosystem.vuejs.press/zh/themes/default/locale.html) - -::: diff --git a/docs/zh/guide/introduction.md b/docs/zh/guide/introduction.md deleted file mode 100644 index 1848728c..00000000 --- a/docs/zh/guide/introduction.md +++ /dev/null @@ -1,39 +0,0 @@ -# 介绍 - -VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 [Markdown](https://zh.wikipedia.org/wiki/Markdown) 来书写内容(如文档、博客等),然后 VuePress 会帮助你生成一个静态网站来展示它们。 - -VuePress 诞生的初衷是为了支持 Vue.js 及其子项目的文档需求,但是现在它已经在帮助大量用户构建他们的文档、博客和其他静态网站。 - -## 它是如何工作的? - -一个 VuePress 站点本质上是一个由 [Vue](https://vuejs.org/) 和 [Vue Router](https://router.vuejs.org) 驱动的单页面应用 (SPA)。 - -路由会根据你的 Markdown 文件的相对路径来自动生成。每个 Markdown 文件都通过 [markdown-it](https://github.com/markdown-it/markdown-it) 编译为 HTML ,然后将其作为 Vue 组件的模板。因此,你可以在 Markdown 文件中直接使用 Vue 语法,便于你嵌入一些动态内容。 - -在开发过程中,我们启动一个常规的开发服务器 (dev-server) ,并将 VuePress 站点作为一个常规的 SPA。如果你以前使用过 Vue 的话,你在使用时会感受到非常熟悉的开发体验。 - -在构建过程中,我们会为 VuePress 站点创建一个服务端渲染 (SSR) 的版本,然后通过虚拟访问每一条路径来渲染对应的 HTML 。这种做法的灵感来源于 [Nuxt](https://nuxtjs.org/) 的 `nuxt generate` 命令,以及其他的一些项目,比如 [Gatsby](https://www.gatsbyjs.org/)。 - -## 为什么不是 ...? - -### Nuxt - -Nuxt 是一套出色的 Vue SSR 框架, VuePress 能做的事情,Nuxt 实际上也同样能够胜任。但 Nuxt 是为构建应用程序而生的,而 VuePress 则更为轻量化并且专注在以内容为中心的静态网站上。 - -### VitePress - -VitePress 是 VuePress 的孪生兄弟,它同样由 Vue.js 团队创建和维护。 VitePress 甚至比 VuePress 要更轻更快,但它在灵活性和可配置性上作出了一些让步,比如它不支持插件系统。当然,如果你没有进阶的定制化需求, VitePress 已经足够支持你将你的内容部署到线上。 - -这个比喻可能不是很恰当,但是你可以把 VuePress 和 VitePress 的关系看作 Laravel 和 Lumen 。 - -### Docsify / Docute - -这两个项目同样都是基于 Vue,然而它们都是完全的运行时驱动,因此对 SEO 不够友好。如果你并不关注 SEO,同时也不想安装大量依赖,它们仍然是非常好的选择! - -### Hexo - -Hexo 一直驱动着 Vue 2.x 的文档。Hexo 最大的问题在于他的主题系统太过于静态以及过度地依赖纯字符串,而我们十分希望能够好好地利用 Vue 来处理我们的布局和交互。同时,Hexo 在配置 Markdown 渲染方面的灵活性也不是最佳的。 - -### GitBook - -过去我们的子项目文档一直都在使用 GitBook 。 GitBook 最大的问题在于当文件很多时,每次编辑后的重新加载时间长得令人无法忍受。它的默认主题导航结构也比较有限制性,并且,主题系统也不是 Vue 驱动的。GitBook 背后的团队如今也更专注于将其打造为一个商业产品而不是开源工具。 diff --git a/docs/zh/guide/markdown.md b/docs/zh/guide/markdown.md deleted file mode 100644 index 37c9c461..00000000 --- a/docs/zh/guide/markdown.md +++ /dev/null @@ -1,511 +0,0 @@ -# Markdown - -在阅读本章节之前,请确保你已经对 Markdown 有所了解。如果你还不了解 Markdown ,请先学习一些 [Markdown 教程](https://commonmark.org/help/)。 - -## 语法扩展 - -VuePress 会使用 [markdown-it](https://github.com/markdown-it/markdown-it) 来解析 Markdown 内容,因此可以借助于 markdown-it 插件来实现 [语法扩展](https://github.com/markdown-it/markdown-it#syntax-extensions) 。 - -本章节将会介绍 VuePress 内置支持的 Markdown 语法扩展。 - -你也可以通过 [markdown](../reference/config.md#markdown) 和 [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) 来配置这些内置扩展、加载更多 markdown-it 插件、实现你自己的扩展等。 - -### 内置 - -由 markdown-it 内置支持: - -- [表格](https://help.github.com/articles/organizing-information-with-tables/) (GFM) -- [删除线](https://help.github.com/articles/basic-writing-and-formatting-syntax/#styling-text) (GFM) - -### 标题锚点 - -你可能已经注意到,当你把鼠标放在各个章节的标题上时,会显示出一个 `#` 锚点。点击这个 `#` 锚点,可以直接跳转到对应章节。 - -::: tip -标题锚点扩展由 [markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor) 支持。 - -配置参考: [markdown.anchor](../reference/config.md#markdown-anchor) -::: - -### 链接 - -在你使用 Markdown 的 [链接语法](https://spec.commonmark.org/0.29/#link-reference-definitions) 时, VuePress 会为你进行一些转换。 - -以我们文档的源文件为例: - -```bash -└─ docs - └─ zh - ├─ guide - │ ├─ getting-started.md - │ ├─ introduction.md - │ └─ markdown.md # <- 我们在这里 - ├─ reference - │ └─ config.md - └─ README.md -``` - -**原始 Markdown** - -```md - - -[首页](../README.md) -[配置参考](../reference/config.md) -[快速上手](./getting-started.md) - - - -[指南 > 介绍](/zh/guide/introduction.md) -[配置参考 > markdown.links](/zh/reference/config.md#links) - - - -[GitHub](https://github.com) -``` - -**转换为** - -```vue - - 首页 -配置参考 -快速上手 -指南 > 介绍 -- 配置参考 > markdown.links - - - GitHub - - -``` - -**渲染为** - -[首页](../README.md) -[配置参考](../reference/config.md) -[快速上手](./getting-started.md) -[指南 > 介绍](/zh/guide/introduction.md) -[配置参考 > markdown.links](/zh/reference/config.md#links) -[GitHub](https://github.com) - -**解释** - -- 内部链接会被转换为 [RouteLink](../reference/components.md#routelink) 以便进行 SPA 导航。 -- 指向 `.md` 文件的内部链接会被转换为目标页面的 [路由路径](./page.md#路由),并且支持绝对路径和相对路径。 -- 外部链接会被添加 `target="_blank" rel="noopener noreferrer"` 属性。 - -**建议** - -对于指向内部 Markdown 文件的链接,尽可能使用相对路径而不是绝对路径。 - -- 相对路径是指向目标文件的有效链接,在你的编辑器或者代码仓库中浏览源文件时也可以正确跳转。 -- 相对路径在不同 locales 下都是一致的,这样在翻译你的内容时就不需要修改 locale 路径了。 - -::: tip -链接扩展是由我们的内置插件支持的。 - -配置参考: [markdown.links](../reference/config.md#markdown-links) -::: - -### Emoji :tada: - -你可以在你的 Markdown 内容中输入 `:EMOJICODE:` 来添加 Emoji 表情。 - -前往 [emoji-cheat-sheet](https://github.com/ikatyang/emoji-cheat-sheet) 来查看所有可用的 Emoji 表情和对应代码。 - -**输入** - -```md -VuePress 2 已经发布 :tada: ! -``` - -**输出** - -VuePress 2 已经发布 :tada: ! - -::: tip -Emoji 扩展由 [markdown-it-emoji](https://github.com/markdown-it/markdown-it-emoji) 支持。 - -配置参考: [markdown.emoji](../reference/config.md#markdown-emoji) -::: - -### 目录 - -如果你想要把当前页面的目录添加到 Markdown 内容中,你可以使用 `[[toc]]` 语法。 - -**输入** - -```md -[[toc]] -``` - -**输出** - -[[toc]] - -目录中的标题将会链接到对应的 [标题锚点](#标题锚点),因此如果你禁用了标题锚点,可能会影响目录的功能。 - -::: tip -目录扩展由 [@mdit-vue/plugin-toc](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc) 支持。 - -配置参考: [markdown.toc](../reference/config.md#markdown-toc) -::: - -### 代码块 - -下列代码块扩展都是在 Node 端进行 Markdown 解析时实现的,也就是代码块并不会在客户端被处理。 - -通过 [@vuepress/plugin-prismjs][prismjs] 和 [@vuepress/plugin-shiki][shiki],你可以通过 [Prism](https://prismjs.com/) 或 [Shiki](https://shiki.tmrs.site/) 来高亮代码块。 - -#### 代码标题 - -你可以在代码块添加一个 `title` 键值对来为代码块设置标题。 - -**输入** - -````md -```ts title=".vuepress/config.ts" -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: '你好, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` -```` - -**输出** - -```ts title=".vuepress/config.ts" -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: '你好, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` - -::: tip - -代码标题是通过高亮器插件默认支持的。它可以和下列的其他标记一起使用。请在它们之间使用空格分隔。 - -::: - -#### 行高亮 - -你可以在代码块添加行数范围标记,来为对应代码行进行高亮。 - -**输入** - -````md -```ts{1,7-9} -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: '你好, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` -```` - -**输出** - -```ts{1,7-9} -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - title: '你好, VuePress', - - theme: defaultTheme({ - logo: 'https://vuejs.org/images/logo.png', - }), -}) -``` - -行数范围标记的例子: - -- 行数范围: `{5-8}` -- 多个单行: `{4,7,9}` -- 组合: `{4,7-13,16,23-27,40}` - -::: tip - -行高亮扩展是通过高亮器插件默认支持的。 - -配置参考:[prism 行高亮](https://ecosystem.vuejs.press/zh/plugins/markdown/prismjs.html#highlightlines) 和 [shiki 行高亮](https://ecosystem.vuejs.press/zh/plugins/markdown/shiki.html#highlightlines) - -::: - -#### 行号 - -你肯定已经注意到在代码块的最左侧会展示行号。这个功能是默认启用的,你可以通过配置来禁用它。 - -你可以在代码块添加 `:line-numbers` / `:no-line-numbers` 标记来覆盖配置项中的设置。 - -**输入** - -````md -```ts -// 行号默认是启用的 -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` - -```ts:no-line-numbers -// 行号被禁用 -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` -```` - -**输出** - -```ts -// 行号默认是启用的 -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` - -```ts:no-line-numbers -// 行号被禁用 -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` - -::: tip - -行号扩展是通过高亮器插件默认支持的。 - -配置参考:[prism 行号](https://ecosystem.vuejs.press/zh/plugins/markdown/prismjs.html#linenumbers) 和 [shiki 行号](https://ecosystem.vuejs.press/zh/plugins/markdown/shiki.html#linenumbers) - -::: - -#### 添加 v-pre - -由于 [模板语法可以在 Markdown 中使用](#模板语法),它也同样可以在代码块中生效。 - -为了避免你的代码块被 Vue 编译, VuePress 默认会在你的代码块添加 [v-pre](https://v3.vuejs.org/api/directives.html#v-pre) 指令。这一默认行为可以在配置中关闭。 - -你可以在代码块添加 `:v-pre` / `:no-v-pre` 标记来覆盖配置项中的设置。 - -::: warning - -模板语法的字符有可能会被语法高亮器解析,比如 "Mustache" 语法(即双花括号)。因此,就像下面的例子一样,在某些语言中 `:no-v-pre` 可能并不能生效。 - -如果你无论如何都想在这种语言中使用 Vue 语法,你可以尝试禁用默认的语法高亮,然后在客户端实现你的自定义代码高亮。 - -::: - -**输入** - -````md -```md - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - -```md:no-v-pre - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - -```js:no-v-pre -// 由于 JS 代码高亮,这里不会被正确编译 -const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} -``` -```` - -**输出** - -```md - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - -```md:no-v-pre - - -1 + 2 + 3 = {{ 1 + 2 + 3 }} -``` - - - -```js -// 由于 JS 代码高亮,这里不会被正确编译 -const onePlusTwoPlusThree = {{ 1 + 2 + 3 }} -``` - -::: tip - -v-pre 扩展是由我们的内置插件支持的。 - -配置参考: [markdown.vPre.block](../reference/config.md#markdown-vpre-block) - -::: - -### 导入代码块 - -你可以使用下面的语法,从文件中导入代码块: - -```md - - -@[code](../foo.js) -``` - -如果你只想导入这个文件的一部分: - -```md - - -@[code{1-10}](../foo.js) -``` - -代码语言会根据文件扩展名进行推断,但我们建议你显式指定: - -```md - - -@[code js](../foo.js) -``` - -实际上,`[]` 内的第二部分会被作为代码块标记来处理,因此在上面 [代码块](#代码块) 章节中提到的语法在这里都可以支持: - -```md - - -@[code js{2,4-5}](../foo.js) -``` - -下面是一个复杂的例子: - -- 导入 `'../foo.js'` 文件的第 3 行至第 10 行 -- 指定语言为 `'js'` -- 对导入代码的第 3 行进行高亮,即 `'../foo.js'` 文件的第 5 行 -- 禁用行号 - -```md -@[code{3-10} js{3}:no-line-numbers](../foo.js) -``` - -需要注意的是,路径别名在导入代码语法中不会生效。你可以通过下面的配置来自行处理路径别名: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - markdown: { - importCode: { - handleImportPath: (str) => - str.replace(/^@src/, path.resolve(__dirname, 'path/to/src')), - }, - }, -} -``` - -```md - - -@[code](@src/foo.js) -``` - -::: tip -导入代码扩展是由我们的内置插件支持的。 - -配置参考: [markdown.importCode](../reference/config.md#markdown-importcode) -::: - -## 在 Markdown 中使用 Vue - -这一章节会介绍 Vue 在 Markdown 中一些基本用法。 - -可以前往 [Cookbook > Markdown 和 Vue SFC](../advanced/cookbook/markdown-and-vue-sfc.md) 来了解更多内容。 - -### 模板语法 - -我们知道: - -- Markdown 中允许使用 HTML。 -- Vue 模板语法是和 HTML 兼容的。 - -这意味着, Markdown 中允许直接使用 [Vue 模板语法](https://v3.vuejs.org/guide/template-syntax.html)。 - -**输入** - -```md -一加一等于: {{ 1 + 1 }} - - span: {{ i }} -``` - -**输出** - -一加一等于: {{ 1 + 1 }} - - span: {{ i }} - -### 组件 - -你可以在 Markdown 中直接使用 Vue 组件。 - -**输入** - -```md -这是默认主题内置的 `` 组件 -``` - -**输出** - -这是默认主题内置的 ` ` 组件 - -::: tip -前往 [内置组件](../reference/components.md) 查看所有内置组件。 - -前往 [默认主题 > 内置组件](https://ecosystem.vuejs.press/zh/themes/default/components.html) 查看默认主题中的所有内置组件。 -::: - -## Markdown 插件 - -你可以在 [VuePress 市场](https://marketplace.vuejs.press/zh/plugins/markdown.html) 上探索更多的 Markdown 插件。 - -## 注意事项 - -### 非标准的 HTML 标签 - -非标准的 HTML 标签不会被 Vue 模板编译器识别成原生 HTML 标签。相反,Vue 会尝试将这些标签解析为 Vue 组件,而显然这些组件通常是不存在的。 例如: - -- 已废弃的 HTML 标签,比如 [\ ](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/center) 和 [\](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font) 等。 -- [MathML 标签](https://developer.mozilla.org/zh-CN/docs/Web/MathML),它们可能会被一些 markdown-it 的 LaTeX 插件用到。 - -如果你无论如何都要使用这些标签的话,可以尝试下面两种方法之一: - -- 添加一个 [v-pre](https://v3.cn.vuejs.org/api/directives.html#v-pre) 指令来跳过这个元素和它的子元素的编译过程。注意所有的模板语法也都会失效。 -- 设置 [compilerOptions.isCustomElement](https://v3.vuejs.org/api/application-config.html#compileroptions) 来告诉 Vue 模板编译器不要尝试作为组件来解析它们。 - - 对于 `@vuepress/bundler-webpack` ,设置 [vue.compilerOptions](../reference/bundler/webpack.md#vue) - - 对于 `@vuepress/bundler-vite` ,设置 [vuePluginOptions.template.compilerOptions](../reference/bundler/vite.md#vuepluginoptions) - -[prismjs]: https://ecosystem.vuejs.press/zh/plugins/markdown/prismjs.html -[shiki]: https://ecosystem.vuejs.press/zh/plugins/markdown/shiki.html diff --git a/docs/zh/guide/migration.md b/docs/zh/guide/migration.md deleted file mode 100644 index af1647c1..00000000 --- a/docs/zh/guide/migration.md +++ /dev/null @@ -1,445 +0,0 @@ -# 从 v1 迁移 - -::: warning -VuePress v1 的插件和主题与 VuePress v2 不兼容。你需要将它们升级到与 v2 对应的版本。 -::: - -VuePress v2 的一些主要改动和优化: - -- VuePress v2 现在使用 Vue 3 ,因此你要保证你的组件和其他客户端文件是适用于 Vue 3 的。 -- VuePress v2 是使用 TypeScript 开发的,因此它现在提供了更好的类型支持。我们强烈推荐你使用 TypeScript 来开发插件和主题。 VuePress 配置文件也同样支持 TypeScript ,你可以直接使用 `.vuepress/config.ts` 。 -- VuePress v2 支持使用 Webpack 和 Vite 作为打包工具。你可以在配置文件中选择你喜欢的打包工具来使用。 -- VuePress v2 现在是纯 ESM 包, CommonJS 格式的配置文件不再被支持。 - -VuePress v2 的核心思想和流程是和 v1 一致的,但 v2 API 经过了重新设计,更加标准化。因此在将现有的 v1 项目迁移至 v2 时,你很可能会遇到一些 Breaking Changes 。本指南将帮助你将 v1 的站点 / 插件 / 主题迁移至 v2 。 - -- 如果你是一个普通用户,你需要阅读 [给用户](#给用户) 的指南。 -- 如果你是一个插件作者,你需要阅读 [给插件作者](#给插件作者) 的指南。 -- 如果你是一个主题作者,你需要阅读 [给主题作者](#给主题作者) 的指南。 - -## 给用户 - -### 用户配置变更 - -配置文件应该使用 ESM 格式, CommonJS 格式的配置文件已不再支持。 - -```diff title=".vuepress/config.ts" -- module.exports = { -- // 用户配置 -- } - -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ // 用户配置 -+ }) -``` - -#### bundler - -现在我们支持使用不同的打包工具。 - -你需要安装并在配置文件中使用 Vite 打包工具: - -```bash -npm i -D @vuepress/bundler-vite@next -``` - -```ts title=".vuepress/config.ts" -import { viteBundler } from '@vuepress/bundler-vite' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler(), -}) -``` - -或者使用 Webpack 打包工具: - -```bash -npm i -D @vuepress/bundler-webpack@next -``` - -```ts title=".vuepress/config.ts" -import { webpackBundler } from '@vuepress/bundler-webpack' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: webpackBundler(), -}) -``` - -#### theme - -不再支持通过字符串使用主题,默认主题也不再集成到 vuepress 包中。 - -你需要安装并在配置文件中使用默认主题: - -```bash -npm i -D @vuepress/theme-default@next -``` - -```diff title=".vuepress/config.ts" -- module.exports = { -- theme: '@vuepress/theme-default', -- themeConfig: { -- // 默认主题配置 -- }, -- } - -+ import { defaultTheme } from '@vuepress/theme-default' -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ theme: defaultTheme({ -+ // 默认主题配置 -+ }) -+ }) -``` - -#### themeConfig - -移除。直接向主题传入配置。 - -#### plugins - -不再支持通过字符串使用插件。需要直接引入插件。 - -```diff title=".vuepress/config.ts" -- module.exports = { -- plugins: [ -- [ -- '@vuepress/plugin-google-analytics', -- { -- id: 'G-XXXXXXXXXX', -- }, -- ], -- ], -- } - -+ import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ plugins: [ -+ googleAnalyticsPlugin({ -+ id: 'G-XXXXXXXXXX', -+ }), -+ ], -+ }) -``` - -#### shouldPrefetch - -默认值从 `() => true` 更改为 `true` 。 - -#### extraWatchFiles - -移除。 - -你可以手动在 [onWatched](../reference/plugin-api.md#onwatched) Hook 中监听文件变化。 - -#### patterns - -重命名为 `pagePatterns` 。 - -#### markdown.lineNumbers - -移除。 - -相同的功能改在 [@vuepress/plugin-prismjs][prismjs] 和 [@vuepress/plugin-shiki][shiki] 提供。 - -#### markdown.pageSuffix - -移除。 - -#### markdown.externalLinks - -移动至 [markdown.links.externalAttrs](../reference/config.md#markdown-links) 。 - -#### markdown.toc - -有改动。 - -参考 [配置 > markdown.toc](../reference/config.md#markdown-toc) - -#### markdown.plugins - -移除。 - -在 [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) Hook 中使用 markdown-it 插件。 - -#### markdown.extendMarkdown - -移除。 - -使用 [extendsMarkdown](../reference/plugin-api.md#extendsmarkdown) Hook 。 - -#### markdown.extractHeaders - -移动至 [markdown.headers](../reference/config.md#markdown-headers) 。 - -#### Webpack 相关配置 - -所有 Webpack 相关的配置都移动至 `@vuepress/bundler-webpack` 的配置项中,包括: - -- `postcss` -- `stylus` -- `scss` -- `sass` -- `less` -- `chainWebpack` -- `configureWebpack` -- `evergreen`:默认值从 `false` 更改为 `true` - -```diff title=".vuepress/config.ts" -- module.exports = { -- sass: { /* ... */ }, -- } - -+ import { webpackBundler } from '@vuepress/bundler-webpack' -+ import { defineUserConfig } from 'vuepress' -+ -+ export default defineUserConfig({ -+ bundler: webpackBundler({ -+ sass: { /* ... */ }, -+ }), -+ }) -``` - -请参考 [指南 > Bundler](./bundler.md) 。 - -### Frontmatter 变更 - -#### meta - -移除。 - -改为使用 [head](../reference/frontmatter.md#head) 。例如: - -```yaml -head: - - - meta - - name: foo - content: bar - - - link - - rel: canonical - href: foobar - - - script - - {} - - console.log('hello from frontmatter'); -``` - -和以下结构相同: - -```ts title=".vuepress/config.ts" -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - // ... - head: [ - ['meta', { name: 'foo', content: 'bar' }], - ['link', { rel: 'canonical', href: 'foobar' }], - ['script', {}, `console.log('hello from frontmatter');`], - ], - // ... -}) -``` - -### 永久链接 Patterns 变更 - -- `:i_month`:移除 -- `:i_day`:移除 -- `:minutes`:移除(v1 文档中未列出) -- `:seconds`:移除(v1 文档中未列出) -- `:regular`:重命名为 `:raw` - -参考 [Frontmatter > permalinkPattern](../reference/frontmatter.md#permalinkpattern) 。 - -### 调色板系统变更 - -VuePress v1 的 Stylus 调色板系统 (即 `styles/palette.styl` 和 `styles/index.styl`) 不再由 VuePress Core 默认提供支持。 - -调色板系统提取到了 [@vuepress/plugin-palette](https://ecosystem.vuejs.press/zh/plugins/palette.html) 当中。 - -主题作者可以使用自己的方式来为用户提供自定义样式的能力,而不必被限制在 Stylus 当中。 - -如果你使用的是默认主题,那么调色板系统仍然存在,但改为使用 SASS ,并且大部分变量都迁移为 CSS 变量。参考 [默认主题 > 样式](https://ecosystem.vuejs.press/zh/themes/default/styles.html) 。 - -### 约定文件变更 - -#### .vuepress/enhanceApp.js - -重命名为 `.vuepress/client.{js,ts}` ,使用方法也有改动。 - -参考 [深入 > Cookbook > 客户端配置的使用方法](../advanced/cookbook/usage-of-client-config.md) 。 - -#### .vuepress/components/ - -在该目录下的文件不会被自动注册为 Vue 组件。 - -你需要使用 [@vuepress/plugin-register-components](https://ecosystem.vuejs.press/zh/plugins/register-components.html) ,或者在 `.vuepress/client.{js,ts}` 中手动注册你的组件。 - -#### .vuepress/theme/ - -即使该目录存在,也不会被隐式默认当作本地主题目录。 - -你需要在 [theme](../reference/config.md#theme) 配置项中显式引入并使用本地主题。 - -### Markdown 变更 - -- Markdown 插槽不再被支持。 -- Markdown 图片语法不再支持 Webpack 别名。不以 `./` 开头的链接也会被识别为相对路径,这与原生 Markdown 图片语法的行为一致。如果你想要使用 Webpack 别名,或者使用来自外部包的图片,你应该使用 ` ` 标签。 - -```diff --  --  - -+
-+
-``` - -### CLI 变更 - -#### eject 命令 - -移除。 - -#### cache 选项 - -- `-c, --cache [cache]`:修改为 `--cache
` ,意味着 `-c` 不再是 `cache` 选项的缩写,并且 `cache` 选项的值不再是可选的。 -- `--no-cache`:重命名为 `--clean-cache` 。 - -### 默认主题变更 - -#### 内置组件 - -- ` ` 和 ` ` 被 [代码选项卡](https://ecosystem.vuejs.press/zh/themes/default/markdown.html#code-tabs) 替代 -- ` ` - - `$badgeErrorColor` 调色板变量重命名为 `$badgeDangerColor` - - `type` Prop 现在只接受 `tip` 、 `warning` 和 `danger` - -#### 调色板系统 - -默认主题的调色板系统迁移为 SASS 和 CSS 变量。 - -参考 [默认主题 > 样式](https://ecosystem.vuejs.press/zh/themes/default/styles.html) 。 - -#### 主题配置 - -默认主题的配置有大量变更,建议你阅读 v2 的默认主题配置参考文档来进行迁移。 - -参考 [默认主题 > 配置](https://ecosystem.vuejs.press/zh/themes/default/config.html) 。 - -这里仅列出部分要注意的变更: - -##### 侧边栏配置 - -```diff -- sidebar: { -- title: 'Foo Bar', -- path: '/foo/bar.html', -- collapsable: true, -- children: [ -- ['/baz', 'Baz'], -- ], -- } - -+ sidebar: { -+ text: 'Foo Bar', -+ link: '/foo/bar.html', -+ collapsible: true, -+ children: [ -+ { -+ text: 'Baz', -+ link: '/baz', -+ } -+ ], -+ } -``` - -### 官方插件变更 - -查看 v2 版本的官方插件文档。 - -### 社区主题和插件 - -v1 的主题和插件和 v2 并不兼容。 - -请确保你在使用的主题和插件已经支持 v2 ,并前往它们各自的文档查看迁移指南。 - -## 给插件作者 - -一些主要的 Breaking Changes : - -- 你不能再在你的插件中使用其他插件了,这避免了很多由于插件嵌套引发的问题。如果你的插件依赖于别的插件,你可以在文档中列出他们,并让用户手动引入。或者,你也可以向用户提供一个插件数组以方便使用。 -- 大部分 v1 Hook 都在 v2 中存在等效的 Hook 或实现方式。唯一的例外是 `extendsCli` ,它被移除了。 -- Webpack 相关的 Hook 都被移除了,因为 VuePress Core 已经和 Webpack 解耦了。你可以尝试使用 [extendsBundlerOptions](../reference/plugin-api.md#extendsbundleroptions) Hook 来进行相似的操作,但要注意应适配所有不同的打包工具。 - -你可以参考 [深入 > 开发插件](../advanced/plugin.md) 来了解如何开发一个 v2 插件。 - -### 插件 API 变更 - -- `plugins`:移除 -- `ready`:重命名为 `onPrepared` -- `updated`:重命名为 `onWatched` -- `generated`:重命名为 `onGenerated` -- `additionalPages`:移除,改为在 `onInitialized` Hook 中使用 `app.pages.push(createPage())` -- `clientDynamicModules`:移除,改为在 `onPrepared` Hook 中使用 `app.writeTemp()` -- `enhanceAppFiles`:移除,使用 `clientConfigFile` Hook -- `globalUIComponents`:移除,使用 `clientConfigFile` Hook -- `clientRootMixin`:移除,使用 `clientConfigFile` Hook -- `extendMarkdown`:重命名为 `extendsMarkdown` -- `chainMarkdown`:移除 -- `extendPageData`:重命名为 `extendsPage` -- `extendsCli`:移除 -- `configureWebpack`:移除 -- `chainWebpack`:移除 -- `beforeDevServer`:移除 -- `afterDevServer`:移除 - -参考 [插件 API](../reference/plugin-api.md) 。 - -## 给主题作者 - -请先浏览 [插件 API 变更](#插件-api-变更) 和 [主题 API 变更](#主题-api-变更)。 - -虽然我们不允许在插件中使用其他插件了,但是你仍然可以在你的主题中使用插件。 - -一些主要的 Breaking Changes : - -- 所谓的 **主题目录结构约定** 不再存在。 - - `theme/enhanceApp.js` 文件不会被隐式作为 Client App Enhance 文件。你需要在 `clientConfigFile` Hook 中显式指定它。 - - `theme/global-components/` 目录下的文件不会被自动注册为 Vue 组件。你需要使用 [@vuepress/plugin-register-components](https://ecosystem.vuejs.press/zh/plugins/register-components.html) ,或者在 `clientConfigFile` 中手动注册组件。 - - `theme/layouts/` 目录下的文件不会被自动注册为布局组件。你需要在 `clientConfigFile` 中通过 `layouts` 来显式指定。 - - `theme/templates/` 目录下的文件不会被自动用作 dev / ssr 的模板。你需要通过 `templateBuild` 和 `templateDev` 配置项来显式指定。 - - 你始终需要提供一个合法的 JS 入口文件,不要再使用 `"main": "layouts/Layout.vue"` 作为主题入口。 -- `themeConfig` 已经从用户配置和站点数据中移除。如果你想要像 v1 一样通过 `this.$site.themeConfig` 来访问 `themeConfig` ,我们现在建议使用 [@vuepress/plugin-theme-data](https://ecosystem.vuejs.press/zh/plugins/theme-data.html) 插件和它提供的 Composition API `useThemeData` 。 -- Stylus 不再是默认的 CSS 预处理器,并且 Stylus 调色板系统不再被默认支持。如果你仍然想要使用和 v1 类似的调色板系统,可以使用 [@vuepress/plugin-palette](https://ecosystem.vuejs.press/zh/plugins/palette.html) 。 -- 由 Prism.js 提供的 Markdown 代码块的语法高亮不再被默认支持。你可以选择使用 [@vuepress/plugin-prismjs][prismjs] 或 [@vuepress/plugin-shiki][shiki] ,或者用你自己的方式实现语法高亮。 -- 考虑到可扩展性, `this.$site.pages` 不再可用。查看 [深入 > Cookbook > 解析路由](../advanced/cookbook/resolving-routes.md) 了解如何在 v2 中获取页面的数据。 - -你可以参考 [深入 > 开发主题](../advanced/theme.md) 来了解如何开发一个 v2 主题。 - -### 主题 API 变更 - -#### layouts - -移除。 - -现在你需要在客户端配置文件中设置布局组件。 - -参考 [深入 > 开发主题](../advanced/theme.md) 。 - -#### extend - -重命名为 `extends` 。 - -你仍然可以通过 `extends: parentTheme()` 来继承一个父主题,这将会继承其插件和布局等。 - -你可以参考 [默认主题 > 继承](https://ecosystem.vuejs.press/zh/themes/default/extending.html) 来了解如何继承默认主题。 - -`@theme` 和 `@parent-theme` 别名默认被移除了,但你仍然可以使用类似的方式来开发一个可继承的主题,参考 [深入 > Cookbook > 开发一个可继承的主题](../advanced/cookbook/making-a-theme-extendable.md) 。 - -[prismjs]: https://ecosystem.vuejs.press/zh/plugins/prismjs.html -[shiki]: https://ecosystem.vuejs.press/zh/plugins/shiki.html diff --git a/docs/zh/guide/page.md b/docs/zh/guide/page.md deleted file mode 100644 index 4bd2faf6..00000000 --- a/docs/zh/guide/page.md +++ /dev/null @@ -1,64 +0,0 @@ -# 页面 - -VuePress 是以 Markdown 为中心的。你项目中的每一个 Markdown 文件都是一个单独的页面。 - -## 路由 - -默认情况下,页面的路由路径是根据你的 Markdown 文件的相对路径决定的。 - -假设这是你的 Markdown 文件所处的目录结构: - -``` -└─ docs - ├─ guide - │ ├─ getting-started.md - │ └─ README.md - ├─ contributing.md - └─ README.md -``` - -将 `docs` 目录作为你的 [sourceDir](../reference/cli.md) ,例如你在运行 `vuepress dev docs` 命令。此时,你的 Markdown 文件对应的路由路径为: - -| 相对路径 | 路由路径 | -| --------------------------- | ----------------------------- | -| `/README.md` | `/` | -| `/index.md` | `/` | -| `/contributing.md` | `/contributing.html` | -| `/guide/README.md` | `/guide/` | -| `/guide/getting-started.md` | `/guide/getting-started.html` | - -::: tip -默认配置下, `README.md` 和 `index.md` 都会被转换成 `index.html` ,并且其对应的路由路径都是由斜杠结尾的。然而,如果你想同时保留这两个文件,就可能会造成冲突。 - -在这种情况下,你可以设置 [pagePatterns](../reference/config.md#pagepatterns) 来避免某个文件被 VuePress 处理,例如使用 `['**/*.md', '!**/README.md', '!.vuepress', '!node_modules']` 来排除所有的 `README.md` 文件。 - -此外,一些符号如 `:` 和 `+` 可能对 vue-router 有特殊含义,因此你应该避免使用它们,请参阅 [vue-router 文档](https://router.vuejs.org/zh/guide/essentials/route-matching-syntax.html) 了解更多详情。 -::: - -## Frontmatter - -Markdown 文件可以包含一个 [YAML](https://yaml.org/) Frontmatter 。Frontmatter 必须在 Markdown 文件的顶部,并且被包裹在一对三短划线中间。下面是一个基本的示例: - -```md ---- -lang: zh-CN -title: 页面的标题 -description: 页面的描述 ---- -``` - -你肯定注意到 Frontmatter 中的字段和[配置文件](./configuration.md#config-file)中的[站点配置](./configuration.md#站点配置)十分类似。你可以通过 Frontmatter 来覆盖当前页面的 `lang`, `title`, `description` 等属性。因此,你可以把 Frontmatter 当作页面级作用域的配置。 - -同样的,VuePress 有一些内置支持的 Frontmatter 字段,而你使用的主题也可能有它自己的特殊 Frontmatter 。 - -::: tip -前往 [Frontmatter 参考](../reference/frontmatter.md) 查看 VuePress 支持的 Frontmatter 配置。 - -前往 [默认主题 > Frontmatter 参考](https://ecosystem.vuejs.press/zh/themes/default/frontmatter.html) 查看默认主题的 Frontmatter 配置。 -::: - -## 内容 - -页面的主要内容是使用 Markdown 书写的。VuePress 首先会将 Markdown 转换为 HTML ,然后将 HTML 作为 Vue 单文件组件的 `` 。 - -借助 [markdown-it](https://github.com/markdown-it/markdown-it) 和 Vue 模板语法的能力,基础的 Markdown 可以得到很多的扩展功能。接下来,前往 [Markdown](./markdown.md) 章节来了解 VuePress 中 Markdown 的扩展功能。 diff --git a/docs/zh/guide/plugin.md b/docs/zh/guide/plugin.md deleted file mode 100644 index c5d1f31a..00000000 --- a/docs/zh/guide/plugin.md +++ /dev/null @@ -1,51 +0,0 @@ -# 插件 - -借助于 [插件 API](../reference/plugin-api.md) , VuePress 插件可以为你提供各种不同的功能。 - -## 官方插件 - -VuePress 团队提供了一些官方插件。 - -你需要在你的配置文件中通过 [plugins](../reference/config.md#plugins) 配置项来使用它们。举例来说,你可以使用 [@vuepress/plugin-google-analytics](https://ecosystem.vuejs.press/zh/plugins/analytics/google-analytics.html) 来使用 Google Analytics : - -```ts -import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics' - -export default { - plugins: [ - googleAnalyticsPlugin({ - id: 'G-XXXXXXXXXX', - }), - ], -} -``` - -::: tip -大部分插件只能使用一次,如果同一个插件被多次使用,那么只有最后一次会生效。 - -然而,部分插件是可以被多次使用的(例如 [@vuepress/plugin-container](https://ecosystem.vuejs.press/zh/plugins/container.html)),你应该查看插件本身的文档来获取详细指引。 -::: - -## 社区插件 - -社区用户创建了很多插件,并将它们发布到了 [NPM](https://www.npmjs.com/search?q=keywords:vuepress-plugin) 上。 查看插件本身的文档可以获取更详细的指引。 - -你可以在 [VuePress 市场](https://marketplace.vuejs.press/zh/plugins/) 中探索更多插件。 - -## 本地插件 - -如果你想要使用自己的插件,但是又不想发布它,你可以创建一个本地插件。 - -我们推荐你直接将 [配置文件](./configuration.md#配置文件) 作为插件使用,因为 [几乎所有的插件 API 都可以在配置文件中使用](../reference/config.md#插件-api),这在绝大多数场景下都更为方便。 - -但是如果你在配置文件中要做的事情太多了,你可以考虑将它们提取到单独的插件中,然后在你的配置文件中使用它们: - -```ts -import myPlugin from './path/to/my-plugin.js' - -export default { - plugins: [myPlugin()], -} -``` - -前往 [深入 > 开发插件](../advanced/plugin.md) 学习如何开发你自己的插件。 diff --git a/docs/zh/guide/theme.md b/docs/zh/guide/theme.md deleted file mode 100644 index 39f88154..00000000 --- a/docs/zh/guide/theme.md +++ /dev/null @@ -1,40 +0,0 @@ -# 主题 - -VuePress 主题为你提供了布局、样式和其他功能,帮助你专注于 Markdown 内容的写作。 - -## 默认主题 - -VuePress 提供了一个默认主题,你当前正在浏览的文档网站就是使用的这个默认主题。 - -你需要在你的配置文件中通过 [theme](../reference/config.md#theme) 配置项来使用它: - -```ts -import { defaultTheme } from '@vuepress/theme-default' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - theme: defaultTheme({ - // 默认主题配置 - navbar: [ - { - text: '首页', - link: '/', - }, - ], - }), -}) -``` - -默认主题为文档网站提供了基础且实用的功能,你可以前往 [默认主题配置参考](https://ecosystem.vuejs.press/zh/themes/default/config.html) 获取全部的配置列表。 - -然而,你可能觉得默认主题不够出色,又或者你不想搭建一个文档网站,而是一个其他类型的网站,比如博客。此时,你可以尝试使用社区主题或者创建本地主题。 - -## 社区主题 - -社区用户创建了很多主题,并将它们发布到了 [NPM](https://www.npmjs.com/search?q=keywords:vuepress-theme) 上。查看主题本身的文档可以获取更详细的指引。 - -你可以在 [VuePress 市场](https://marketplace.vuejs.press/zh/themes/) 中探索更多主题。 - -## 本地主题 - -如果你想要使用自己的自定义主题,但是又不想发布它,你可以创建一个本地主题。前往 [深入 > 开发主题](../advanced/theme.md) 学习如何开发你自己的主题。 diff --git a/docs/zh/guide/troubleshooting.md b/docs/zh/guide/troubleshooting.md deleted file mode 100644 index 739fb30e..00000000 --- a/docs/zh/guide/troubleshooting.md +++ /dev/null @@ -1,14 +0,0 @@ -# 常见问题 - -## 缺少 bundler / theme 配置? - -你需要在配置文件中明确指定要使用的打包工具 (bundler) 和主题 (theme) 。 - -查看打包工具的配置参考,了解如何正确配置打包工具: - -- [打包工具 > Vite](../reference/bundler/vite.md) -- [打包工具 > Webpack](../reference/bundler/webpack.md) - -请参阅默认主题参考,了解如何正确配置默认主题: - -- [默认主题 > 配置](https://ecosystem.vuejs.press/zh/themes/default/) diff --git a/docs/zh/reference/bundler/vite.md b/docs/zh/reference/bundler/vite.md deleted file mode 100644 index b2afc84d..00000000 --- a/docs/zh/reference/bundler/vite.md +++ /dev/null @@ -1,47 +0,0 @@ -# Vite - - - -Vite 打包工具是由 [@vuepress/bundler-vite](https://www.npmjs.com/package/@vuepress/bundler-vite) 包提供的。 - -## 使用方法 - -安装打包工具: - -```bash -npm i -D @vuepress/bundler-vite@next -``` - -在配置文件中指定打包工具: - -```ts title=".vuepress/config.ts" -import { viteBundler } from '@vuepress/bundler-vite' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: viteBundler({ - viteOptions: {}, - vuePluginOptions: {}, - }), -}) -``` - -## 配置项 - -### viteOptions - -- 详情: - - 接收 Vite 的所有配置项。 - -- 参考: - - [Vite > Config](https://cn.vite.dev/config/) - -### vuePluginOptions - -- 详情: - - 接收 [@vitejs/plugin-vue](https://www.npmjs.com/package/@vitejs/plugin-vue) 的所有配置项。 - -- 参考: - - [Vite > 插件 > 官方插件](https://cn.vite.dev/plugins/#vitejsplugin-vue) diff --git a/docs/zh/reference/bundler/webpack.md b/docs/zh/reference/bundler/webpack.md deleted file mode 100644 index 500d3a7f..00000000 --- a/docs/zh/reference/bundler/webpack.md +++ /dev/null @@ -1,148 +0,0 @@ -# Webpack - - - -Webpack 打包工具是由 [@vuepress/bundler-webpack](https://www.npmjs.com/package/@vuepress/bundler-webpack) 包提供的。 - -## 使用方法 - -安装打包工具: - -```bash -npm i -D @vuepress/bundler-webpack@next -``` - -在配置文件中指定打包工具: - -```ts title=".vuepress/config.ts" -import { webpackBundler } from '@vuepress/bundler-webpack' -import { defineUserConfig } from 'vuepress' - -export default defineUserConfig({ - bundler: webpackBundler({ - postcss: {}, - vue: {}, - }), -}) -``` - -## 配置项 - -### configureWebpack - -- 类型: `(config: WebpackConfiguration, isServer: boolean, isBuild: boolean) => WebpackConfiguration | void` - -- 详情: - - 用于修改内部的 Webpack 配置。 - - 该配置项接收一个函数,该函数的第一个参数是 Webpack 配置对象,第二个参数是 `isServer` 标志位,第三个参数是 `isBuild` 标志位。 - -### chainWebpack - -- 类型: `(config: WebpackChainConfig, isServer: boolean, isBuild: boolean) => void` - -- 详情: - - 通过 [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain) 来修改内部的 Webpack 配置。 - - 该配置项接收一个函数,该函数的第一个参数是由 `webpack-chain` 提供的 `Config` 实例,第二个参数是 `isServer` 标志位,第三个参数是 `isBuild` 标志位。 - -### devServerSetupMiddlewares - -- 类型: `(middlewares: Middleware[], devServer: Server) => Middleware[]` - -- 详情: - - 在 Webpack 的 `devServer.setupMiddlewares` 中调用的 Hook 。 - - 函数的参数即是 `devServer.setupMiddlewares` 的参数。 - -- 参考: - - [Webpack > Configuration > DevServer > devServer.setupMiddlewares](https://webpack.js.org/configuration/dev-server/#devserversetupmiddlewares) - -### vue - -- 类型: `VueLoaderOptions` - -- 详情: - - `vue-loader` 的配置项。 - -- 参考: - - [vue-loader > 选项参考](https://vue-loader.vuejs.org/zh/options.html) - -### postcss - -- 类型: `PostcssLoaderOptions` - -- 详情: - - `postcss-loader` 的配置项。 - -- 参考: - - [postcss-loader > Options](https://github.com/webpack-contrib/postcss-loader#options) - -### stylus - -- 类型: `StylusLoaderOptions` - -- 详情: - - `stylus-loader` 的配置项。 - -- 参考: - - [stylus-loader > Options](https://github.com/webpack-contrib/stylus-loader#options) - -### scss - -- 类型: `SassLoaderOptions` - -- 详情: - - 针对 `.scss` 文件的 `sass-loader` 的配置项。 - -- 参考: - - [sass-loader > Options](https://github.com/webpack-contrib/sass-loader#options) - -### sass - -- 类型: `SassLoaderOptions` - -- 详情: - - 针对 `.sass` 文件的 `sass-loader` 的配置项。 - -- 参考: - - [sass-loader > Options](https://github.com/webpack-contrib/sass-loader#options) - -### less - -- 类型: `LessLoaderOptions` - -- 详情: - - `less-loader` 的配置项。 - -- 参考: - - [less-loader > Options](https://github.com/webpack-contrib/less-loader#options) - -### evergreen - -- 类型: `boolean` - -- 默认值: `true` - -- 详情: - - 如果你的对象只有那些 “常青树” 浏览器,你可以将其设置成 `true` 。这将会禁用一些转译过程和 Polyfills ,带来更快的构建速度和更小的文件体积。 - -## 常见问题 - -### 在修改 `base` 后引用 Public 文件 - -与 Vite 不同, Webpack 不会为 Public 文件自动处理 `base`。因此如果你修改了网站的 `base`,建议你在引用 Public 图片文件时使用 [Base Helper](../../guide/assets.md#base-helper)。 - -### 使用默认主题 - -默认主题使用 [SASS](https://sass-lang.com/) 作为 CSS 预处理器,因此你在使用 Webpack 时(特别是在使用 [pnpm](https://pnpm.io/) 时)可能需要手动安装 [sass-loader](https://www.npmjs.com/package/sass-loader) 来确保其正常工作。 diff --git a/docs/zh/reference/cli.md b/docs/zh/reference/cli.md deleted file mode 100644 index 6acf89aa..00000000 --- a/docs/zh/reference/cli.md +++ /dev/null @@ -1,85 +0,0 @@ -# 命令行接口 - -执行 `vuepress --help` 来获取下列帮助信息: - -``` -Usage: - $ vuepress [options] - -Commands: - dev [sourceDir] Start development server - build [sourceDir] Build to static site - info Display environment information - -For more info, run any command with the `--help` flag: - $ vuepress dev --help - $ vuepress build --help - $ vuepress info --help - -Options: - -v, --version Display version number - -h, --help Display this message -``` - -::: tip -VuePress 使用了 [debug](https://www.npmjs.com/package/debug) 模块。 - -设置环境变量 `DEBUG=vuepress*` 可以启用调试日志。 -::: - -## dev - -启动一个开发服务器,在本地开发你的 VuePress 站点。 - -``` -Usage: - $ vuepress dev [sourceDir] - -Options: - -c, --config Set path to config file - -p, --port Use specified port (default: 8080) - -t, --temp Set the directory of the temporary files - --host Use specified host (default: 0.0.0.0) - --cache Set the directory of the cache files - --clean-temp Clean the temporary files before dev - --clean-cache Clean the cache files before dev - --open Open browser when ready - --debug Enable debug mode - --no-watch Disable watching page and config files (default: true) - -v, --version Display version number - -h, --help Display this message -``` - -::: tip -通过命令行设置的配置项,会覆盖你配置文件中的同名配置项。 -::: - -## build - -将你的 VuePress 站点构建成静态文件,以便你进行后续[部署](../guide/deployment.md)。 - -``` -Usage: - $ vuepress build [sourceDir] - -Options: - -c, --config Set path to config file - -d, --dest Set the directory build output (default: .vuepress/dist) - -t, --temp Set the directory of the temporary files - --cache Set the directory of the cache files - --clean-temp Clean the temporary files before build - --clean-cache Clean the cache files before build - --debug Enable debug mode - -v, --version Display version number - -h, --help Display this message -``` - -::: tip -通过命令行设置的配置项,会覆盖你配置文件中的同名配置项。 -::: - -## info - -输出当前系统和依赖相关的信息。 - -在你想要检查你的环境,或者提交 Issue 时候,可以使用该命令。 diff --git a/docs/zh/reference/client-api.md b/docs/zh/reference/client-api.md deleted file mode 100644 index f2ae67d6..00000000 --- a/docs/zh/reference/client-api.md +++ /dev/null @@ -1,238 +0,0 @@ -# 客户端 API - -客户端 API 可以通过 `vuepress/client` 来引入。 - -## 组合式 API - -### useClientData - -- 详情: - - 返回所有客户端数据的 Ref 对象。 - - 每个属性也可以通过下列的组合式 API 来访问。 - -- 示例: - -```vue - -``` - -### usePageData - -- 详情: - - 返回当前页面数据的 Ref 对象。 - -- 参考: - - [Node API > Page 属性 > data](./node-api.md#data) - - [插件 API > extendsPage](./plugin-api.md#extendspage) - -### usePageFrontmatter - -- 详情: - - 返回当前页面 Frontmatter 的 Ref 对象。 - - 它的值是页面数据的 `frontmatter` 属性。 - -### usePageHead - -- 详情: - - 返回当前页面 Head 配置的 Ref 对象。 - - 它的值是合并 [head](./frontmatter.md#head) Frontmatter 和 [head](./config.md#head) 配置,并进行去重后得到的。 - -### usePageHeadTitle - -- 详情: - - 返回当前页面 Head 中的标题的 Ref 对象。 - - 它的值是连接页面标题和站点标题后得到的。 - -### usePageLang - -- 详情: - - 返回当前页面语言的 Ref 对象。 - - 它的值是页面数据的 `lang` 属性。 - -### useRoutes - -- 详情: - - 返回所有路由的 Ref 对象。 - - 它的值是站点数据的路由信息。 - -- 参考: - - [深入 > Cookbook > 解析路由](../advanced/cookbook/resolving-routes.md) - -### useRouteLocale - -- 详情: - - 返回当前路由对应的 locale path 的 Ref 对象。 - - 它的值是 [locales](./config.md#locales) 配置的键之一。 - -### useSiteData - -- 详情: - - 返回站点数据的 Ref 对象。 - -### useSiteLocaleData - -- 详情: - - 返回当前 locale 的站点数据的 Ref 对象。 - - 当前 locale 中的配置已经合并到顶层配置中。 - -### onContentUpdated - -- 详情: - - 当 markdown 文件内容发生变化时,触发回调。 - - 该函数仅能在组件的 `setup` 阶段被调用。 - - ```vue - - ``` - -## 工具函数 - -### defineClientConfig - -- 详情: - - 帮助你创建 [clientConfigFile](./plugin-api.md#clientconfigfile) 的工具函数。 - -- 参考: - - [深入 > Cookbook > 客户端配置的使用方法](../advanced/cookbook/usage-of-client-config.md) - -### resolveRoute - -- 详情: - - 解析给定链接对应的路由 - -- 参考: - - [深入 > Cookbook > 解析路由](../advanced/cookbook/resolving-routes.md) - -### resolveRoutePath - -- 详情: - - 解析给定链接对应的路由路径 - -- 参考: - - [深入 > Cookbook > 解析路由](../advanced/cookbook/resolving-routes.md) - -### withBase - -- 详情: - - 在 URL 前添加站点 [base](./config.md#base) 前缀。 - -- 参考: - - [指南 > 静态资源 > Base Helper](../guide/assets.md#base-helper) - -## 常量 - -在客户端代码中有一些常量可以使用。 - -如果想要把这些常量的类型定义补充到你的代码环境中,请将 `vuepress/client-types` 添加到你的 `tsconfig.json` 里: - -```json -{ - "compilerOptions": { - "types": ["vuepress/client-types"] - } -} -``` - -### `__VUEPRESS_VERSION__` - -- 类型: `string` - -- 详情: - - VuePress Core 的版本号。 - -### `__VUEPRESS_BASE__` - -- 类型: `string` - -- 详情: - - 配置中的 [base](./config.md#base) 字段。 - -### `__VUEPRESS_DEV__` - -- 类型: `boolean` - -- 详情: - - 一个环境标记,用于标识当前是否运行在 `dev` 模式下。 - -### `__VUEPRESS_SSR__` - -- 类型: `boolean` - -- 详情: - - 一个环境标记,用于标识当前是否运行在服务端渲染 (SSR) 环境下。 - -## 进阶能力 - -### resolvers - -- 类型: `Record ` - -- 详情: - - 一个响应式对象,其中的方法决定了如何获取全局计算属性。 - -- 示例: - -在客户端配置文件中自定义 ` ` 的格式: - -```ts -import { defineClientConfig, resolvers } from 'vuepress/client' - -export default defineClientConfig({ - enhance({ app, router, siteData }) { - resolvers.resolvePageHeadTitle = (page, siteLocale) => - `${siteLocale.title} > ${page.title}` - }, -}) -``` - -::: danger -`resolvers` 会直接影响 VuePress 的基础功能,在修改前请确保你已充分了解其用途。 -::: diff --git a/docs/zh/reference/components.md b/docs/zh/reference/components.md deleted file mode 100644 index 59f2c1c6..00000000 --- a/docs/zh/reference/components.md +++ /dev/null @@ -1,158 +0,0 @@ -# 内置组件 - -## AutoLink - -- Props: - - - config - - 类型:`AutoLinkConfig` - - 是否必须:`true` - -```ts -interface AutoLinkConfig { - /** - * 判断该链接是否被激活的模式,优先级高于 `exact` - */ - activeMatch?: RegExp | string - - /** - * `aria-label` 属性 - */ - ariaLabel?: string - - /** - * 该链接是否只有在 URL 完全匹配时才激活 - */ - exact?: boolean - - /** - * 自动链接的 URL - */ - link: string - - /** - * `rel` 属性 - */ - rel?: string - - /** - * `target` 属性 - */ - target?: string - - /** - * 自动链接的文本 - */ - text: string -} -``` - -- 使用: - -```md - - - - default 插槽 - - -- before 插槽 - after 插槽 - - -- {{ config.text }} - - -- {{ config.text }} - -``` - -- 详情: - - 该组件将会自动将内部链接渲染为 `` ,将外部链接渲染为 `` ,并添加必要的属性。 - - 你可以通过 `before` 和 `after` 插槽,在文本之前和之后渲染内容。也可以通过 `default` 插槽,直接渲染文本(默认文本是 `config.text`)。 - - 该组件主要是为了开发主题时使用,普通用户在绝大多数情况下并不会用到它。对于主题作者来说,我们建议你在不确定链接是内部链接还是外部链接时,尽量使用这个组件。 - -## ClientOnly - -- 使用: - -```md - - -``` - -- 详情: - - 该组件和它的子元素只会在客户端被渲染。也就是说,它不会在构建 (SSR) 过程中被渲染到 HTML 内。 - - 如果一个组件在 `setup()` 中直接使用 浏览器 / DOM API ,它会导致构建过程报错,因为这些 API 在 Node.js 的环境中是无法使用的。在这种情况下,你可以选择一种方式: - - - 修改这个组件,只在 `onBeforeMount()` 或 `onMounted()` Hook 中使用 浏览器 / DOM API 。 - - 使用 `- ` 包裹这个组件。 - -:::tip -从 Vue 3.5 开始,如果你只是想避免 Hydration Mismatch ,可以尝试使用新的 [data-allow-mismatch](https://blog.vuejs.org/posts/vue-3-5#data-allow-mismatch) 属性来代替 ` ` 组件。 -::: - -## Content - -- Props: - - - path - - 类型: `string` - - 是否必须: `false` - -- 使用: - -```md - -``` - -- 详情: - - 该组件会渲染页面的 Markdown 内容。 - - 如果没有传入 `path` Prop ,它会渲染当前路由下的页面内容。 - - 该组件主要是为了开发主题时使用。在绝大多数情况下你不会用到它。 - -- 参考: - - [Node API > Page 属性 > path](./node-api.md#path) - -## RouteLink - -- Props: - - - to - - 类型: `string` - - 是否必须: `true` - - active - - 类型: `boolean` - - 是否必须: `false` - - 默认值: `false` - - activeClass - - 类型: `string` - - 是否必须: `false` - - 默认值: `'route-link-active'` - -- 使用: - -```md - 目标页面 -当前页面 -``` - -- 详情: - - 该组件会渲染一个链接,用于跳转到指定页面。 - - 如果 `active` Prop 被设置为 `true` ,那么这个链接会被额外添加一个 `activeClass` 类名。需要注意的是,这里的 active 状态并不会根据当前路由自动更新。 - - 该组件主要是为了开发主题时使用,普通用户在绝大多数情况下并不会用到它。对于主题作者来说,我们建议你在渲染内部链接时尽量使用这个组件,而不是使用 `vue-router` 的 `` 组件。 diff --git a/docs/zh/reference/config.md b/docs/zh/reference/config.md deleted file mode 100644 index 058ba119..00000000 --- a/docs/zh/reference/config.md +++ /dev/null @@ -1,634 +0,0 @@ -# 配置 - -## 站点配置 - -### base - -- 类型: `string` - -- 默认值: `/` - -- 详情: - - 部署站点的基础路径。 - - 如果你想让你的网站部署到一个子路径下,你将需要设置它。它的值应当总是以斜杠开始,并以斜杠结束。举例来说,如果你想将你的网站部署到 `https://foo.github.io/bar/`,那么 `base` 应该被设置成 `"/bar/"`。 - - `base` 将会作为前缀自动地插入到以 `/` 开始的其他选项的链接中,所以你只需要指定一次。([head](#head) 中的属性除外) - - 需要注意的是, `base` 应该是一个以 `/` 开始和结束的绝对路径名。 - -- 参考: - - [指南 > 静态资源 > Base Helper](../guide/assets.md#base-helper) - - [指南 > 部署](../guide/deployment.md) - -### lang - -- 类型: `string` - -- 默认值: `en-US` - -- 详情: - - 站点的语言。 - - 它将会在最终渲染出的 HTML 中作为 `` 标签的 `lang` 属性。 - - 它可以设置在不同语言的 locales 中。 - -- 参考: - - [配置 > locales](#locales) - -### title - -- 类型: `string` - -- 默认值: `''` - -- 详情: - - 站点的标题。 - - 它将会作为所有页面标题的后缀,并且在默认主题的导航栏中显示。 - - 它可以设置在不同语言的 locales 中。 - -- 参考: - - [配置 > locales](#locales) - -### description - -- 类型: `string` - -- 默认值: `''` - -- 详情: - - 站点的描述。 - - 它将会在最终渲染出的 HTML 中作为 `` 标签的 `content` 属性。它会被每个页面的 Frontmatter 中的 `description` 字段覆盖。 - - 它可以设置在不同语言的 locales 中。 - -- 参考: - - [配置 > locales](#locales) - - [Frontmatter > description](./frontmatter.md#description) - -### head - -- 类型: `HeadConfig[]` - -- 默认值: `[]` - -- 详情: - - 在最终渲染出的 HTML 的 `` 标签内加入的额外标签。 - - 你可以通过 `[tagName, { attrName: attrValue }, innerHTML?]` 的格式来添加标签。 - - 它可以设置在不同语言的 locales 中。 - - 需要注意的是,如果 `attrValue` 是一个 pathname ,它不会被自动添加 [base](#base) 前缀,所以如果需要的话请记得手动添加前缀。 - -- 示例: - - 增加一个自定义的 favicon : - -```ts -export default { - head: [['link', { rel: 'icon', href: '/images/logo.png' }]], -} -``` - -渲染为: - -```html - - - -``` - -- 参考: - - [配置 > locales](#locales) - - [Frontmatter > head](./frontmatter.md#head) - -### locales - -- 类型: `{ [path: string]: Partial }` - -- 默认值: `{}` - -- 详情: - - 多语言支持的各个语言 locales 。 - - 可以使用的字段有: - - - [lang](#lang) - - [title](#title) - - [description](#description) - - [head](#head) - -- 参考: - - [指南 > I18n](../guide/i18n.md) - -## 主题配置 - -### theme - -- 类型: `Theme` - -- 详情: - - 设置站点要使用的主题。 - - 如果不设置该选项,将会使用默认主题。 - -- 参考: - - [指南 > 主题](../guide/theme.md) - - [默认主题 > 配置](https://ecosystem.vuejs.press/zh/themes/default/config.html) - -## 打包工具配置 - -### bundler - -- 类型: `Bundler` - -- 详情: - - 设置站点要使用的打包工具。 - - 如果不设置该选项,将会使用默认的打包工具: - - - 使用 `vuepress` 或 `vuepress-vite` 时,默认的打包工具是 Vite 。 - - 使用 `vuepress-webpack` 时,默认的打包工具是 Webpack 。 - -- 参考: - - [指南 > 打包工具](../guide/bundler.md) - - [打包工具 > Vite](./bundler/vite.md) - - [打包工具 > Webpack](./bundler/webpack.md) - -## 通用配置项 - -### dest - -- 类型: `string` - -- 默认值: `` `${sourceDir}/.vuepress/dist` `` - -- 详情: - - 指定 `vuepress build` 命令的输出目录。 - -### temp - -- 类型: `string` - -- 默认值: `` `${sourceDir}/.vuepress/.temp` `` - -- 详情: - - 指定临时文件目录。 - -::: warning -VuePress 在开发和构建时会加载临时文件,因此临时文件目录应位于项目根目录内部,以便可以正确地解析到依赖。 -::: - -### cache - -- 类型: `string` - -- 默认值: `` `${sourceDir}/.vuepress/.cache` `` - -- 详情: - - 指定缓存文件目录。 - -### public - -- 类型: `string` - -- 默认值: `` `${sourceDir}/.vuepress/public` `` - -- 详情: - - 指定 Public 文件目录。 - -- 参考: - - [指南 > 静态资源 > Public 文件](../guide/assets.md#public-文件) - -### debug - -- 类型: `boolean` - -- 默认值: `false` - -- 详情: - - 是否启用 Debug 模式。 - - 该配置项主要提供给开发者使用。同时,我们使用了 [debug](https://github.com/visionmedia/debug) 模块打印 Debug 日志,可以通过 `DEBUG=vuepress*` 环境变量来启用。 - -### pagePatterns - -- 类型: `string[]` - -- 默认值: `['**/*.md', '!.vuepress', '!node_modules']` - -- 详情: - - 指定页面文件的 Patterns 。这些 Patterns 是相对于 Source 目录的。 - -### permalinkPattern - -- 类型: `string | null` - -- 默认值: `null` - -- 详情: - - 指定为页面生成永久链接的 Pattern 。 - - 它会被每个页面的 Frontmatter 中的 `permalinkPattern` 字段覆盖。 - -- 参考: - - [Frontmatter > permalinkPattern](./frontmatter.md#permalinkpattern) - -## Dev 配置项 - -### host - -- 类型: `string` - -- 默认值: `'0.0.0.0'` - -- 详情: - - 指定开发服务器的主机名。 - -### port - -- 类型: `number` - -- 默认值: `8080` - -- 详情: - - 指定开发服务器的端口号。 - -### open - -- 类型: `boolean` - -- 默认值: `false` - -- 详情: - - 是否在开发服务器启动后打开浏览器。 - -### templateDev - -- 类型: `string` - -- 默认值: `'@vuepress/client/templates/dev.html'` - -- 详情: - - 指定开发时使用的 HTML 模板。 - -## Build 配置项 - -### shouldPreload - -- 类型: `((file: string, type: string) => boolean)) | boolean` - -- 默认值: `true` - -- 详情: - - 一个函数,用来控制哪些文件是需要生成对应的 `` 标签的。设置为 `true` 或者 `false` 来完全启用或禁用它。 - - 默认情况下,只有当前页面所需的文件会被预加载。所以在绝大部分情况下,你只需要使用 `true` 就可以了。 - -### shouldPrefetch - -- 类型: `((file: string, type: string) => boolean)) | boolean` - -- 默认值: `true` - -- 详情: - - 一个函数,用来控制哪些文件是需要生成对应的 `` 标签的。设置为 `true` 或者 `false` 来完全启用或禁用它。 - - 如果你将它设置为 `true` ,所有其它页面所需的文件都会被预拉取。这对于小型站点来说是十分有帮助的,因为它会大大提升页面切换的速度。但是在你的网站有很多页面时不建议你这么做。 - -### templateBuild - -- 类型: `string` - -- 默认值: `'@vuepress/client/templates/build.html'` - -- 详情: - - 指定构建时使用的 HTML 模板路径。 - -### templateBuildRenderer - -- 类型: `TemplateRenderer` - -- 默认值: `templateRenderer` - -- 详情: - - 指定构建时使用的 HTML 模板渲染函数。 - -## Markdown 配置 - -### markdown - -- 类型: `MarkdownOptions` - -- 默认值: `{}` - -- 详情: - - 对 VuePress 内置的 Markdown 语法扩展进行配置。 - - 它可以接收 [markdown-it](https://github.com/markdown-it/markdown-it) 的所有配置项,以及下列额外的配置项。 - -- 参考: - - [markdown-it > Init with presets and options](https://github.com/markdown-it/markdown-it#init-with-presets-and-options) - - [指南 > Markdown > 语法扩展](../guide/markdown.md#语法扩展) - -### markdown.anchor - -- 类型: `AnchorPluginOptions | false` - -- 默认值: - -```ts -const defaultOptions = { - level: [1, 2, 3, 4, 5, 6], - permalink: anchorPlugin.permalink.headerLink({ - class: 'header-anchor', - safariReaderFix: true, - }), -} -``` - -- 详情: - - [markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor) 的配置项。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [指南 > Markdown > 语法扩展 > 标题锚点](../guide/markdown.md#标题锚点) - -### markdown.assets - -- 类型: `AssetsPluginOptions | false` - -- 详情: - - VuePress 内置的 markdown-it assets 插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -::: danger -除非你了解它的用途,否则你不应该设置该配置项。 -::: - -### markdown.component - -- 类型: `undefined | false` - -- 详情: - - [@mdit-vue/plugin-component](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-component) 插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -::: danger -除非你了解它的用途,否则你不应该设置该配置项。 -::: - -### markdown.emoji - -- 类型: `EmojiPluginOptions | false` - -- 详情: - - [markdown-it-emoji](https://github.com/markdown-it/markdown-it-emoji) 的配置项。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [指南 > Markdown > 语法扩展 > Emoji](../guide/markdown.md#emoji) - -### markdown.frontmatter - -- 类型: `FrontmatterPluginOptions | false` - -- 详情: - - [@mdit-vue/plugin-frontmatter](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-frontmatter) 插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [指南 > 页面 > Frontmatter](../guide/page.md#frontmatter) - - [Node API > Page 属性 > frontmatter](./node-api.md#frontmatter) - -::: danger -除非你了解它的用途,否则你不应该设置该配置项。 -::: - -### markdown.headers - -- 类型: `HeadersPluginOptions | false` - -- 默认值: - -```ts -const defaultOptions = { - level: [2, 3], -} -``` - -- 详情: - - [@mdit-vue/plugin-headers](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers) 插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [Node API > Page 属性 > headers](./node-api.md#headers) - -### markdown.importCode - -- 类型: `ImportCodePluginOptions | false` - -- 详情: - - VuePress 内置的 markdown-it 导入代码插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [指南 > Markdown > 语法扩展 > 导入代码块](../guide/markdown.md#导入代码块) - -#### markdown.importCode.handleImportPath - -- 类型: `(str: string) => string` - -- 默认值: `(str) => str` - -- 详情: - - 一个函数,用于处理导入代码语法中的文件导入路径。 - -### markdown.links - -- 类型: `LinkPluginOptions | false` - -- 详情: - - VuePress 内置的 markdown-it 链接插件的配置项。 - - 它可以把站内链接的 tag 转换为 [internalTag](#markdownlinksinternaltag) ,并且可以在站外链接上添加额外的属性和图标。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [指南 > Markdown > 语法扩展 > 链接](../guide/markdown.md#链接) - -#### markdown.links.internalTag - -- 类型: `string` - -- 默认值: `'RouteLink'` - -- 详情: - - 内部链接所使用的标签。 - - 默认情况下,该插件会把内部链接转换为 [RouteLink](./components.md#routelink) 。 - -#### markdown.links.externalAttrs - -- 类型: `Record ` - -- 默认值: `{ target: '_blank', rel: 'noopener noreferrer' }` - -- 详情: - - 为外部链接添加额外的属性。 - -### markdown.sfc - -- 类型: `SfcPluginOptions | false` - -- 详情: - - [@mdit-vue/plugin-sfc](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc) 插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [Cookbook > Markdown 与 Vue SFC](../advanced/cookbook/markdown-and-vue-sfc.md) - - [Node API > Page 属性 > sfcBlocks](./node-api.md#sfcblocks) - -::: danger -除非你了解它的用途,否则你不应该设置该配置项。 -::: - -### markdown.slugify - -- 类型: `(str: string) => string` - -- 详情: - - 默认使用的 slugify 函数。 - -### markdown.title - -- 类型: `undefined | false` - -- 详情: - - [@mdit-vue/plugin-title](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-title) 插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -::: danger -除非你了解它的用途,否则你不应该设置该配置项。 -::: - -### markdown.toc - -- 类型: `TocPluginOptions | false` - -- 默认值: - -```ts -const defaultOptions = { - level: [2, 3], -} -``` - -- 详情: - - [@mdit-vue/plugin-toc](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc) 插件的配置项。 - - 设置为 `false` 可以禁用该插件。 - -- 参考: - - [指南 > Markdown > 语法扩展 > 目录](../guide/markdown.md#目录) - -#### markdown.vPre.block - -- 类型: `boolean` - -- 默认值: `true` - -- 详情: - - 是否在代码块的 ` ` 标签上添加 `v-pre` 指令。 - -- 参考: - - [指南 > Markdown > 语法扩展 > 代码块 > 添加 v-pre](../guide/markdown.md#添加-v-pre) - -#### markdown.vPre.inline - -- 类型: `boolean` - -- 默认值: `true` - -- 详情: - - 是否在行内代码的 `` 标签上添加 `v-pre` 指令。 - -- 参考: - - [指南 > Markdown > 语法扩展 > 代码块 > 添加 v-pre](../guide/markdown.md#添加-v-pre) - -## 插件配置 - -### plugins - -- 类型: `PluginConfig[]` - -- 详情: - - 要使用的插件。 - - 该配置项接收一个数组,其中的每一个数组项是一个或一组插件。 - -- 参考: - - [指南 > 插件](../guide/plugin.md) - -## 插件 API - -用户配置文件同样可以作为一个 VuePress 插件,所以除了 `name` 和 `multiple` 配置项以外的所有插件 API 都可以在配置文件中使用。 - -前往 [插件 API 参考](./plugin-api.md) 查看所有插件 API 。 diff --git a/docs/zh/reference/frontmatter.md b/docs/zh/reference/frontmatter.md deleted file mode 100644 index 09fed9e9..00000000 --- a/docs/zh/reference/frontmatter.md +++ /dev/null @@ -1,213 +0,0 @@ -# Frontmatter - -## date - -- 类型: `string` - -- 详情: - - 页面的创建日期。 - - 应按照 `yyyy-MM-dd` 的格式来指定日期,或者遵循 [YAML Timestamp Type](https://yaml.org/type/timestamp.html) 。 - -- 参考: - - [Node API > Page 属性 > date](./node-api.md#date) - -## description - -- 类型: `string` - -- 详情: - - 页面的描述。 - - 它将会覆盖站点配置中的 `description` 配置项。 - -- 参考: - - [配置 > description](./config.md#description) - -## head - -- 类型: `HeadConfig[]` - -- 详情: - - 页面 `` 标签内添加的额外标签。 - -- 示例: - -```md ---- -head: - - - meta - - name: foo - content: yaml 数组语法 - - [meta, { name: bar, content: 方括号语法 }] ---- -``` - -渲染为: - -```html - - - - -``` - -- 参考: - - [配置 > head](./config.md#head) - -## lang - -- 类型: `string` - -- 详情: - - 页面的语言。 - - 它将会覆盖站点配置中的 `lang` 配置项 - -- 参考: - - [配置 > lang](./config.md#lang) - - [Node API > Page 属性 > lang](./node-api.md#lang) - -## layout - -- 类型: `string` - -- 详情: - - 页面的布局。 - - 布局是由主题提供的。如果你不指定该 Frontmatter ,则会使用默认布局。你应该参考主题自身的文档来了解其提供了哪些布局。 - - 如果主题布局无法满足你的需求,你可以使用自定义布局组件。 - -- 示例: - -在 `.vuepress/client.ts` 文件中注册一个布局组件: - -```ts -import { defineClientConfig } from 'vuepress/client' -import CustomLayout from './CustomLayout.vue' - -export default defineClientConfig({ - layouts: { - CustomLayout, - }, -}) -``` - -在 Frontmatter 中设置自定义布局: - -```md ---- -layout: CustomLayout ---- -``` - -## permalink - -- 类型: `string | null` - -- 详情: - - 页面的永久链接。 - - 它将会覆盖根据文件路径来决定的默认路由路径。 - - 当被设置为 `null` 时,将会禁用页面的永久链接。 - -- 参考: - - [Frontmatter > permalinkPattern](#permalinkpattern) - - [指南 > 页面 > 路由](../guide/page.md#路由) - - [Node API > Page 属性 > permalink](./node-api.md#permalink) - -## permalinkPattern - -- 类型: `string | null` - -- 详情: - - 为页面生成永久链接的 Pattern 。 - - 它将会覆盖站点配置中的 `permalinkPattern` 配置项。 - - 如果 Frontmatter 中设置了 `permalink` ,那么这个字段则不会生效。 - -- 使用: - - | Pattern | 描述 | - | -------- | ------------------ | - | `:year` | 创建日期的 年 部分 | - | `:month` | 创建日期的 月 部分 | - | `:day` | 创建日期的 日 部分 | - | `:slug` | 页面文件名的 Slug | - | `:raw` | 原始路由路径 | - - `:year`, `:month` 和 `:day` Pattern 根据如下优先级进行解析: - - - Frontmatter 中的 `date` 字段。 - - 符合 `yyyy-MM-dd-foobar.md` 或 `yyyy-MM-foobar.md` 日期格式的文件名。 - - 符合 `yyyy/MM/dd/foobar.md` 或 `yyyy/MM/foobar.md` 日期格式的目录名。 - - 默认值 `0000-00-00` 。 - -- 示例 1 : - - 页面文件名是 `foo-bar.md` 。 - - 页面 Frontmatter 是: - -```md ---- -date: 2021-01-03 -permalinkPattern: :year/:month/:day/:slug.html ---- -``` - -那么页面的永久链接将会是 `2021/01/03/foo-bar.html` 。 - -- 示例 2 : - - 页面文件名是 `2021-01-03-bar-baz.md`。 - - 页面 Frontmatter 是: - -```md ---- -permalinkPattern: :year/:month/:day/:slug.html ---- -``` - -那么页面的永久链接将会是 `2021/01/03/bar-baz.html` 。 - -- 参考: - - [配置 > permalinkPattern](./config.md#permalinkpattern) - - [Frontmatter > date](#date) - - [Frontmatter > permalink](#permalink) - - [Node API > Page 属性 > permalink](./node-api.md#permalink) - -## routeMeta - -- 类型: `Record
` - -- 详情: - - 附加到页面路由的自定义数据。 - -- 参考: - - [Node API > Page 属性 > routeMeta](./node-api.md#routeMeta) - -## title - -- 类型: `string` - -- 详情: - - 页面的标题。 - - 如果你不在 Frontmatter 中设置 `title` ,那么页面中第一个一级标题(即 `# title`)的内容会被当作标题使用。 - -- 参考: - - [Node API > Page 属性 > title](./node-api.md#title) diff --git a/docs/zh/reference/node-api.md b/docs/zh/reference/node-api.md deleted file mode 100644 index 02bbc4ff..00000000 --- a/docs/zh/reference/node-api.md +++ /dev/null @@ -1,641 +0,0 @@ -# Node API - -Node API 可以通过 `vuepress/core` 来引入。 - -## App - -[插件 API](./plugin-api.md) 的所有 Hooks 中都可以获取到 App 实例。 - -`BuildApp` 和 `DevApp` 除了 [build](#build) 和 [dev](#dev) 方法外,拥有一样的属性和方法。 - -### createBuildApp - -- 函数签名: - -```ts -const createBuildApp: (config: AppConfig) => BuildApp -``` - -- 参数: - -| 参数 | 类型 | 描述 | -| ------ | ----------- | -------------------------- | -| config | `AppConfig` | 创建 VuePress App 的选项。 | - -- 详情: - - 创建一个 Build 模式的 App 实例,用于构建静态文件。 - -- 示例: - -```ts -const build = async () => { - const app = createBuildApp({ - // ...配置项 - }) - - // 初始化和准备 - await app.init() - await app.prepare() - - // 构建 - await app.build() - - // 处理 onGenerated hook - await app.pluginApi.hooks.onGenerated.process(app) -} -``` - -- 参考: - - [Node API > App 方法 > build](#build) - -### createDevApp - -- 函数签名: - -```ts -const createDevApp: (config: AppConfig) => DevApp -``` - -- 参数: - -| 参数 | 类型 | 描述 | -| ------ | ----------- | -------------------------- | -| config | `AppConfig` | 创建 VuePress App 的选项。 | - -- 详情: - - 创建一个 Dev 模式的 App 实例,用于启动开发服务器。 - -- 示例: - -```ts -const dev = async () => { - const app = createDevApp({ - // ...配置项 - }) - - // 初始化和准备 - await app.init() - await app.prepare() - - // 启动开发服务器 - const closeDevServer = await app.dev() - - // 准备文件监听器 - const watchers = [] - - // 重启开发服务器 - const restart = async () => { - await Promise.all([ - // 关闭所有监听器 - ...watchers.map((item) => item.close()), - // 关闭当前的开发服务器 - closeDevServer(), - ]) - await dev() - } - - // 处理 onWatched hook - await app.pluginApi.hooks.onWatched.process(app, watchers, restart) -} -``` - -- 参考: - - [Node API > App 方法 > dev](#dev) - -## App 属性 - -### options - -- 类型: `AppOptions` - -- 详情: - - VuePress App 的配置项。 - - 这些配置项来自于 [createBuildApp](#createbuildapp) / [createDevApp](#createdevapp) 的 `config` 参数,但所有可选的字段都填充上了默认值。 - -### siteData - -- 类型: `SiteData` - -- 详情: - - 由用户设置的站点数据,包含所有的 [站点配置](./config.md#站点配置) ,可以在客户端代码中使用。 - -### version - -- 类型: `string` - -- 详情: - - VuePress App 的版本,即 `@vuepress/core` 包的版本。 - -### env.isBuild - -- 类型: `boolean` - -- 详情: - - 用于判断 App 是否运行在 Build 模式的环境标记,即当前 App 是否是 [BuildApp](#createbuildapp) 实例。 - -### env.isDev - -- 类型: `boolean` - -- 详情: - - 用于判断 App 是否运行在 Dev 模式的环境标记,即当前 App 是否是 [DevApp](#createdevapp) 实例。 - -### env.isDebug - -- 类型: `boolean` - -- 详情: - - 用于判断 App 是否开启 Debug 模式的环境标记。 - -### markdown - -- 类型: `MarkdownIt` - -- 详情: - - 用于解析 Markdown 内容的 [markdown-it](https://github.com/markdown-it/markdown-it) 实例。 - - 它仅在 [onInitialized](./plugin-api.md#oninitialized) 以及之后的 Hooks 中才可用。 - -### pages - -- 类型: `Page[]` - -- 详情: - - [Page](#page) 对象数组。 - - 它仅在 [onInitialized](./plugin-api.md#oninitialized) 以及之后的 Hooks 中才可用。 - -## App 方法 - -### dir - -- 工具函数: - - - `dir.cache()`: 解析至缓存目录 - - `dir.temp()`: 解析至临时文件目录 - - `dir.source()`: 解析至源文件目录 - - `dir.dest()`: 解析至输出目录 - - `dir.client()`: 解析至 `@vuepress/client` 目录 - - `dir.public()`: 解析至 Public 文件目录 - -- 函数签名: - -```ts -type AppDirFunction = (...args: string[]) => string -``` - -- 详情: - - 用于解析对应目录下的文件绝对路径的一些工具函数。 - - 如果你不传入任何参数,就会返回对应目录的绝对路径。 - -- 示例: - -```ts -// 解析 `${sourceDir}/README.md` 文件的绝对路径 -const homeSourceFile = app.dir.source('README.md') -``` - -### writeTemp - -- 函数签名: - -```ts -declare const writeTemp = (file: string, content: string) => Promise -``` - -- 参数: - -| 参数 | 类型 | 描述 | -| ------- | -------- | -------------------------------------------- | -| file | `string` | 要写入的临时文件的路径,相对于临时文件目录。 | -| content | `string` | 要写入的临时文件路径的内容。 | - -- 详情: - - 用于写入临时文件的方法。 - - 写入的文件可以在客户端文件中通过 `@temp` 别名来引入。 - -- 示例: - -```ts -export default { - // 在 onPrepared hook 中写入临时文件 - async onPrepared() { - await app.writeTemp('foo.js', "export const foo = 'bar'") - }, -} -``` - -```ts -// 在客户端文件中引入临时文件 -import { foo } from '@temp/foo' -``` - -### init - -- 函数签名: - -```ts -declare const init = () => Promise -``` - -- 详情: - - 初始化 VuePress App 。 - -- 参考: - - [深入 > 架构 > 核心流程与 Hooks](../advanced/architecture.md#核心流程与-hooks) - -### prepare - -- 函数签名: - -```ts -declare const prepare = () => Promise -``` - -- 详情: - - 准备客户端临时文件。 - -- 参考: - - [深入 > 架构 > 核心流程与 Hooks](../advanced/architecture.md#核心流程与-hooks) - -### build - -- 函数签名: - -```ts -declare const build = () => Promise -``` - -- 详情: - - 生成静态站点文件。 - - 该方法仅在 [BuildApp](#createbuildapp) 中可用。 - -- 参考: - - [深入 > 架构 > 核心流程与 Hooks](../advanced/architecture.md#核心流程与-hooks) - -### dev - -- 函数签名: - -```ts -declare const dev = () => Promise<() => Promise > -``` - -- 详情: - - 启动开发服务器。 - - 该方法仅在 [DevApp](#createdevapp) 中可用。 - -- 参考: - - [深入 > 架构 > 核心流程与 Hooks](../advanced/architecture.md#核心流程与-hooks) - -## Page - -### createPage - -- 函数签名: - -```ts -const createPage: (app: App, options: PageOptions) => Promise -``` - -- 参数: - -| 参数 | 类型 | 描述 | -| ------- | ------------- | --------------------------- | -| app | `App` | VuePress App 实例。 | -| options | `PageOptions` | 创建 VuePress Page 的选项。 | - -- 详情: - - 创建一个 VuePress Page 对象。 - -- 示例: - -```ts -import { createPage } from 'vuepress/core' - -export default { - // 在 onInitialized hook 中创建一个额外页面 - async onInitialized(app) { - app.pages.push( - await createPage(app, { - path: '/foo.html', - frontmatter: { - layout: 'Layout', - }, - content: `\ -# 某个 Page - -你好,世界。 -`, - }), - ) - }, -} -``` - -- 参考: - - [Node API > App 属性 > pages](#pages) - - [Cookbook > 添加额外页面](../advanced/cookbook/adding-extra-pages.md) - -## Page 属性 - -### path - -- 类型: `string` - -- 详情: - - 该 Page 的路由路径。 - -- 参考: - - [指南 > 页面 > 路由](../guide/page.md#路由) - - [Node API > Page 属性 > pathInferred](#pathinferred) - -### title - -- 类型: `string` - -- 详情: - - 该 Page 的标题。 - -- 参考: - - [Frontmatter > title](./frontmatter.md#title) - -### lang - -- 类型: `string` - -- 详情: - - 该 Page 的语言。 - -- 示例: - - - `'en-US'` - - `'zh-CN'` - -- 参考: - - [Frontmatter > lang](./frontmatter.md#title) - -### frontmatter - -- 类型: `PageFrontmatter` - -- 详情: - - 该 Page 的 Frontmatter 。 - -- 参考: - - [Frontmatter](./frontmatter.md) - -### headers - -- 类型: `PageHeader[]` - -```ts -interface PageHeader { - level: number - title: string - slug: string - children: PageHeader[] -} -``` - -- 详情: - - 该 Page 的小标题。 - -- 参考: - - [配置 > markdown.headers](./config.md#markdown-headers) - -### data - -- 类型: `PageData` - -```ts -interface PageData { - path: string - title: string - lang: string - frontmatter: PageFrontmatter -} -``` - -- 详情: - - 该 Page 的数据。 - - Page 数据可以在客户端代码中使用。 - -- 参考: - - [客户端 API > usePageData](./client-api.md#usepagedata) - - [插件 API > extendsPage](./plugin-api.md#extendspage) - -### content - -- 类型: `string` - -- 详情: - - 该 Page 的未经渲染的原始内容。 - -### contentRendered - -- 类型: `string` - -- 详情: - - 该 Page 的渲染后的内容。 - -### date - -- 类型: `string` - -- 详情: - - 该 Page 的日期,遵从 'yyyy-MM-dd' 格式。 - -- 示例: - - - `'0000-00-00'` - - `'2021-08-16`' - -- 参考: - - [Frontmatter > date](./frontmatter.md#date) - -### deps - -- 类型: `string[]` - -- 详情: - - 该 Page 的依赖。 - - 举例来说,如果在页面中导入了代码片段,那么被导入文件的绝对路径就会被添加到 `deps` 中。 - -- 参考: - - [配置 > markdown.importCode](./config.md#markdown-importcode) - -### links - -- 类型: `MarkdownLink[]` - -```ts -interface MarkdownLink { - raw: string - relative: string - absolute: string -} -``` - -- 详情: - - 该 Page 内容中包含的链接。 - -### markdownEnv - -- 类型: `Record ` - -- 详情: - - 在使用 markdown-it 解析 Markdown 内容时的 `env` 对象。 - - 一些 markdown-it 插件可能会在这个对象中存储一些额外的信息,你可以使用它们来进行高级定制化。 - - 需要注意的是,其他的一些 Page 属性其实也是从 `env` 对象中获取到的,但是我们已经把这些属性从 `page.markdownEnv` 中移除掉了。 - -- 参考: - - [markdown-it > API Documentation > MarkdownIt > parse](https://markdown-it.github.io/markdown-it/#MarkdownIt.parse) - -### pathInferred - -- 类型: `string | null` - -- 详情: - - 该 Page 根据文件路径推断出的路由路径。 - - 默认情况下,路由路径是根据 Markdown 源文件的相对文件路径推断出来的。然而,用户可能会显式指定页面路由,比如通过 [permalink](#permalink) 来指定该页面最终使用的路由路径。因此我们在 Page 属性中保留推断出来的路径,以便于你在某些情况下可能会用到它。 - - 如果该 Page 不是来自于 Markdown 源文件,那么该属性会为 `null` 。 - -- 示例: - - - `'/'` - - `'/foo.html'` - -- 参考: - - [指南 > 页面 > 路由](../guide/page.md#路由) - - [Node API > Page 属性 > path](#path) - -### pathLocale - -- 类型: `string` - -- 详情: - - 该 Page 路由路径的 Locale 前缀。 - - 它是根据页面的 Markdown 源文件相对路径、以及用户配置的 `locales` 的键推断得到的。 - -- 示例: - - - `'/'` - - `'/en/'` - - `'/zh/'` - -- 参考: - - [配置 > locales](./config.md#locales) - -### permalink - -- 类型: `string | null` - -- 详情: - - 该 Page 的永久链接。 - -- 参考: - - [Frontmatter > permalink](./frontmatter.md#permalink) - - [Frontmatter > permalinkPattern](./frontmatter.md#permalinkpattern) - -### routeMeta - -- 类型: `Record ` - -- 详情: - - 附加到页面路由记录上的额外数据。 - -- 参考: - - [Frontmatter > routeMeta](./frontmatter.md#routemeta) - -::: tip Route Meta 和 Page Data 的区别是什么? -[Route Meta](#routemeta) 和 [Page Data](#data) 都可以在客户端代码中使用。然而, Route Meta 是附加在页面路由记录上的,因此当用户进入你的站点时,所有页面的 Route Meta 都会立即被加载。相比之下, Page Data 是存储在单独的文件中的,只有在用户进入对应页面时才会被加载。 - -因此,不建议在 Route Meta 中存储大量的信息,否则在站点有很多页面时,将会影响站点的初始加载速度。 -::: - -### sfcBlocks - -- 类型: `MarkdownSfcBlocks` - -- 详情: - - 该 Page 中提取出的 Vue SFC Blocks 。 - -- 参考: - - [配置 > markdown.sfc](./config.md#markdown-sfc) - -### slug - -- 类型: `string` - -- 详情: - - 该 Page 的 Slug 。 - - 它是根据页面的 Markdown 源文件的文件名推断得到的。 - -### filePath - -- 类型: `string | null` - -- 详情: - - 该 Page 的 Markdown 源文件的绝对路径。 - - 如果该 Page 不是来自于 Markdown 源文件,那么该属性会为 `null` 。 - -### filePathRelative - -- 类型: `string | null` - -- 详情: - - 该 Page 的 Markdown 源文件的相对路径。 - - 如果该 Page 不是来自于 Markdown 源文件,那么该属性会为 `null` 。 diff --git a/docs/zh/reference/plugin-api.md b/docs/zh/reference/plugin-api.md deleted file mode 100644 index 8248ed38..00000000 --- a/docs/zh/reference/plugin-api.md +++ /dev/null @@ -1,363 +0,0 @@ -# 插件 API - -你可以查看 [Node API](./node-api.md) 来了解如何使用插件 Hooks 中的 VuePress App 实例。 - -## 概览 - -插件需要在初始化之前使用。基础配置项会在使用插件时立即被处理: - -- [name](#name) -- [multiple](#multiple) - -下列 Hooks 会在初始化 App 时处理: - -- [extendsMarkdownOptions](#extendsmarkdownoptions) -- [extendsMarkdown](#extendsmarkdown) -- [extendsPageOptions](#extendspageoptions) -- [extendsPage](#extendspage) -- [onInitialized](#oninitialized) - -下列 Hooks 会在准备文件时处理: - -- [clientConfigFile](#clientconfigfile) -- [onPrepared](#onprepared) - -下列 Hooks 会在 dev / build 时处理: - -- [extendsBundlerOptions](#extendsbundleroptions) -- [alias](#alias) -- [define](#define) -- [onWatched](#onwatched) -- [onGenerated](#ongenerated) - -> 查看 [深入 > 架构 > 核心流程与 Hooks](../advanced/architecture.md#核心流程与-hooks) 来更好地理解该流程。 - -## 基础配置项 - -### name - -- 类型: `string` - -- 详情: - - 插件的名称。 - - 它会被用来识别插件,以避免多次使用同一个插件,因此应确保你的插件名称是独一无二的。 - - 它应遵从如下命名约定: - - - 非 Scoped: `vuepress-plugin-foo` - - Scoped: `@org/vuepress-plugin-foo` - -- 参考: - - [插件 API > multiple](#multiple) - -### multiple - -- 类型: `boolean` - -- 默认值: `false` - -- 详情: - - 插件是否能够被多次使用。 - - 如果设置为 `false` ,当有相同名称的插件被使用时,先使用的会被后使用的替换掉。 - - 如果设置为 `true` ,相同名称的插件可以被多次使用且不会被替换。 - -- 参考: - - [插件 API > name](#name) - -## 开发 Hooks - -### alias - -- 类型: `Record | ((app: App, isServer: boolean) => Record )` - -- 详情: - - 定义路径别名。 - - 该 Hook 接收一个对象,或者一个返回对象的函数。 - -- 示例: - -```ts -import { getDirname, path } from 'vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export default { - alias: { - '@alias': path.resolve(__dirname, './path/to/alias'), - }, -} -``` - -### clientConfigFile - -- 类型: `string | ((app: App) => string | Promise