diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..5d126348 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# 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/.eslintignore b/.eslintignore new file mode 100644 index 00000000..ac5bc285 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +!.vuepress/ +!.*.js +.cache/ +.temp/ +node_modules/ +dist/ diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 00000000..b3ffd39f --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,13 @@ +module.exports = { + root: true, + extends: 'vuepress', + overrides: [ + { + files: ['*.ts', '*.vue'], + extends: 'vuepress-typescript', + parserOptions: { + project: ['tsconfig.json'], + }, + }, + ], +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d022441a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +* text eol=lf +*.txt text eol=crlf + +*.png binary +*.jpg binary +*.jpeg binary +*.ico binary +*.tff binary +*.woff binary +*.woff2 binary diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..400fc670 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,16 @@ +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 new file mode 100644 index 00000000..3aee83f9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +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 new file mode 100644 index 00000000..4e8e9506 --- /dev/null +++ b/.github/workflows/check-docs.yml @@ -0,0 +1,53 @@ +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: ['18', '20'] + bundler: ['vite', 'webpack'] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + + - 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: Build source code + run: pnpm build + + - 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 new file mode 100644 index 00000000..9f6ae92a --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,44 @@ +name: docs + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + docs: + runs-on: ubuntu-latest + + env: + DOCS_GA_ID: G-CTB8FQ7VMW + NODE_VERSION: '18' + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + + - 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 new file mode 100644 index 00000000..d25cc571 --- /dev/null +++ b/.github/workflows/issue-commented.yml @@ -0,0 +1,17 @@ +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 new file mode 100644 index 00000000..4b51b033 --- /dev/null +++ b/.github/workflows/issue-daily.yml @@ -0,0 +1,42 @@ +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 new file mode 100644 index 00000000..e38c9047 --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,30 @@ +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 [v2.vuepress.vuejs.org/new](https://v2.vuepress.vuejs.org/new). Issues marked with `need reproduction` will be closed if they have no activity within 7 days. diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e3fdda76 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# 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 new file mode 100755 index 00000000..d69ab0a7 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +pnpm commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..fab6428a --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +pnpm lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..94c9f11d --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +pnpm-lock.yaml +*.html +*.md diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..adc12201 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "vue.volar" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..9b673398 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,43 @@ +{ + "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": [ + "composables", + "devtool", + "docsearch", + "envinfo", + "esbuild", + "frontmatter", + "globby", + "gtag", + "mdit", + "nprogress", + "prefetch", + "preload", + "prismjs", + "shiki", + "slugify", + "unmount", + "vuejs", + "vuepress", + "vueuse", + "zoomable" + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..9ef07511 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,15 @@ +# VuePress Documentation Contributing Guide + +## Overview + +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: + +- English (en-US) in `/` path +- Chinese (zh-CN) in `/zh/` path + +We have two different deployments: + +- Release deployment powered by [Netlify](https://www.netlify.com). This deployment is built from the latest released version, so users will not see unreleased changes. The domain name is [https://v2.vuepress.vuejs.org](https://v2.vuepress.vuejs.org). +- Developer deployment powered by [GitHub Pages](https://pages.github.com). This deployment is built from the latest commit, so developers could preview the latest changes. The domain name is [https://vuepress.github.io](https://vuepress.github.io). diff --git a/CONTRIBUTING_zh.md b/CONTRIBUTING_zh.md new file mode 100644 index 00000000..d0208725 --- /dev/null +++ b/CONTRIBUTING_zh.md @@ -0,0 +1,15 @@ +# VuePress 文档贡献指南 + +## 概览 + +VuePress 的文档是由 VuePress 自己驱动的,是由该仓库中的源码构建而来。 + +所有的 Markdown 源文件都放置在 `docs` 目录下。我们维护了两种翻译: + +- 英语 (en-US) 在 `/` 路径下 +- 中文 (zh-CN) 在 `/zh/` 路径下 + +我们部署了两套站点: + +- 在 [Netlify](https://www.netlify.com) 部署的 Release 版本。该站点是从最新发布的版本中构建而来,因此用户不会看到未发布的改动。域名为 [https://v2.vuepress.vuejs.org](https://v2.vuepress.vuejs.org)。 +- 在 [GitHub Pages](https://pages.github.com) 部署的 Developer 版本。该站点是从最新的提交中构建而来,因此开发者可以预览最新的改动。域名为 [https://vuepress.github.io](https://vuepress.github.io)。 diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..44387d62 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-present, VuePress Community + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..2b646bca --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# VuePress Documentation + +VuePress documentation repository. + +## Deployments + +- Release deployment: https://v2.vuepress.vuejs.org +- Developer deployment: https://vuepress.github.io + +## License + +[MIT](https://github.com/vuepress/docs/blob/main/LICENSE) diff --git a/docs/.vuepress/components/NpmBadge.vue b/docs/.vuepress/components/NpmBadge.vue new file mode 100644 index 00000000..c9ff7be2 --- /dev/null +++ b/docs/.vuepress/components/NpmBadge.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts new file mode 100644 index 00000000..5cf08ede --- /dev/null +++ b/docs/.vuepress/config.ts @@ -0,0 +1,197 @@ +import { createRequire } from 'node:module' +import process from 'node:process' +import { viteBundler } from '@vuepress/bundler-vite' +import { webpackBundler } from '@vuepress/bundler-webpack' +import { defineUserConfig } from '@vuepress/cli' +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 { 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({ + logo: '/images/hero.png', + repo: 'vuepress/vuepress-next', + 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({ theme: 'dark-plus' }) : [], + ], +}) diff --git a/docs/.vuepress/configs/head.ts b/docs/.vuepress/configs/head.ts new file mode 100644 index 00000000..8d20be52 --- /dev/null +++ b/docs/.vuepress/configs/head.ts @@ -0,0 +1,40 @@ +import type { HeadConfig } from '@vuepress/core' + +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 new file mode 100644 index 00000000..b23dc923 --- /dev/null +++ b/docs/.vuepress/configs/index.ts @@ -0,0 +1,3 @@ +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 new file mode 100644 index 00000000..64f53d0c --- /dev/null +++ b/docs/.vuepress/configs/meta.ts @@ -0,0 +1,8 @@ +import { createRequire } from 'node:module' +import { fs } from '@vuepress/utils' + +const require = createRequire(import.meta.url) + +export const version = fs.readJsonSync( + require.resolve('@vuepress/core/package.json'), +).version diff --git a/docs/.vuepress/configs/navbar/en.ts b/docs/.vuepress/configs/navbar/en.ts new file mode 100644 index 00000000..73874ecc --- /dev/null +++ b/docs/.vuepress/configs/navbar/en.ts @@ -0,0 +1,143 @@ +import type { NavbarConfig } from '@vuepress/theme-default' +import { version } from '../meta.js' + +export const navbarEn: NavbarConfig = [ + { + text: 'Guide', + link: '/guide/', + }, + { + text: 'Reference', + children: [ + { + text: 'VuePress', + 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: 'Default Theme', + children: [ + '/reference/default-theme/config.md', + '/reference/default-theme/frontmatter.md', + '/reference/default-theme/components.md', + '/reference/default-theme/markdown.md', + '/reference/default-theme/styles.md', + '/reference/default-theme/extending.md', + ], + }, + ], + }, + { + text: 'Plugins', + children: [ + { + text: 'Common Features', + children: [ + '/reference/plugin/back-to-top.md', + '/reference/plugin/container.md', + '/reference/plugin/external-link-icon.md', + '/reference/plugin/google-analytics.md', + '/reference/plugin/medium-zoom.md', + '/reference/plugin/nprogress.md', + '/reference/plugin/register-components.md', + ], + }, + { + text: 'Content Search', + children: [ + '/reference/plugin/docsearch.md', + '/reference/plugin/search.md', + ], + }, + { + text: 'PWA', + children: [ + '/reference/plugin/pwa.md', + '/reference/plugin/pwa-popup.md', + ], + }, + { + text: 'Syntax Highlighting', + children: [ + '/reference/plugin/prismjs.md', + '/reference/plugin/shiki.md', + ], + }, + { + text: 'Theme Development', + children: [ + '/reference/plugin/active-header-links.md', + '/reference/plugin/git.md', + '/reference/plugin/palette.md', + '/reference/plugin/theme-data.md', + '/reference/plugin/toc.md', + ], + }, + ], + }, + { + 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: 'Contributing Guide', + link: 'https://github.com/vuepress/vuepress-next/blob/main/CONTRIBUTING.md', + }, + { + text: 'Awesome VuePress', + link: 'https://github.com/vuepress/awesome-vuepress', + }, + ], + }, + ], + }, + { + text: `v${version}`, + children: [ + { + text: 'Changelog', + link: 'https://github.com/vuepress/vuepress-next/blob/main/CHANGELOG.md', + }, + { + text: 'v1.x', + link: 'https://v1.vuepress.vuejs.org', + }, + { + text: 'v0.x', + link: 'https://v0.vuepress.vuejs.org', + }, + ], + }, +] diff --git a/docs/.vuepress/configs/navbar/index.ts b/docs/.vuepress/configs/navbar/index.ts new file mode 100644 index 00000000..7183393c --- /dev/null +++ b/docs/.vuepress/configs/navbar/index.ts @@ -0,0 +1,2 @@ +export * from './en.js' +export * from './zh.js' diff --git a/docs/.vuepress/configs/navbar/zh.ts b/docs/.vuepress/configs/navbar/zh.ts new file mode 100644 index 00000000..17f77fd3 --- /dev/null +++ b/docs/.vuepress/configs/navbar/zh.ts @@ -0,0 +1,140 @@ +import type { NavbarConfig } from '@vuepress/theme-default' +import { version } from '../meta.js' + +export const navbarZh: NavbarConfig = [ + { + text: '指南', + link: '/zh/guide/', + }, + { + text: '参考', + children: [ + { + text: 'VuePress', + 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: [ + '/zh/reference/default-theme/config.md', + '/zh/reference/default-theme/frontmatter.md', + '/zh/reference/default-theme/components.md', + '/zh/reference/default-theme/markdown.md', + '/zh/reference/default-theme/styles.md', + '/zh/reference/default-theme/extending.md', + ], + }, + ], + }, + { + text: '插件', + children: [ + { + text: '常用功能', + children: [ + '/zh/reference/plugin/back-to-top.md', + '/zh/reference/plugin/container.md', + '/zh/reference/plugin/external-link-icon.md', + '/zh/reference/plugin/google-analytics.md', + '/zh/reference/plugin/medium-zoom.md', + '/zh/reference/plugin/nprogress.md', + '/zh/reference/plugin/register-components.md', + ], + }, + { + text: '内容搜索', + children: [ + '/zh/reference/plugin/docsearch.md', + '/zh/reference/plugin/search.md', + ], + }, + { + text: 'PWA', + children: [ + '/zh/reference/plugin/pwa.md', + '/zh/reference/plugin/pwa-popup.md', + ], + }, + { + text: '语法高亮', + children: [ + '/zh/reference/plugin/prismjs.md', + '/zh/reference/plugin/shiki.md', + ], + }, + { + text: '主题开发', + children: [ + '/zh/reference/plugin/active-header-links.md', + '/zh/reference/plugin/git.md', + '/zh/reference/plugin/palette.md', + '/zh/reference/plugin/theme-data.md', + '/zh/reference/plugin/toc.md', + ], + }, + ], + }, + { + 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://github.com/vuepress/vuepress-next/blob/main/CONTRIBUTING_zh.md', + }, + { + text: 'Awesome VuePress', + link: 'https://github.com/vuepress/awesome-vuepress', + }, + ], + }, + ], + }, + { + text: `v${version}`, + children: [ + { + text: '更新日志', + link: 'https://github.com/vuepress/vuepress-next/blob/main/CHANGELOG.md', + }, + { + text: 'v1.x', + link: 'https://v1.vuepress.vuejs.org/zh/', + }, + { + text: 'v0.x', + link: 'https://v0.vuepress.vuejs.org/zh/', + }, + ], + }, +] diff --git a/docs/.vuepress/configs/sidebar/en.ts b/docs/.vuepress/configs/sidebar/en.ts new file mode 100644 index 00000000..b358ab59 --- /dev/null +++ b/docs/.vuepress/configs/sidebar/en.ts @@ -0,0 +1,126 @@ +import type { SidebarConfig } from '@vuepress/theme-default' + +export const sidebarEn: SidebarConfig = { + '/guide/': [ + { + text: 'Guide', + children: [ + '/guide/README.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', + ], + }, + ], + '/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', + ], + }, + ], + '/reference/': [ + { + text: 'VuePress Reference', + 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 Reference', + collapsible: true, + children: ['/reference/bundler/vite.md', '/reference/bundler/webpack.md'], + }, + { + text: 'Default Theme Reference', + collapsible: true, + children: [ + '/reference/default-theme/config.md', + '/reference/default-theme/frontmatter.md', + '/reference/default-theme/components.md', + '/reference/default-theme/markdown.md', + '/reference/default-theme/styles.md', + '/reference/default-theme/extending.md', + ], + }, + { + text: 'Official Plugins Reference', + collapsible: true, + children: [ + { + text: 'Common Features', + children: [ + '/reference/plugin/back-to-top.md', + '/reference/plugin/container.md', + '/reference/plugin/external-link-icon.md', + '/reference/plugin/google-analytics.md', + '/reference/plugin/medium-zoom.md', + '/reference/plugin/nprogress.md', + '/reference/plugin/register-components.md', + ], + }, + { + text: 'Content Search', + children: [ + '/reference/plugin/docsearch.md', + '/reference/plugin/search.md', + ], + }, + { + text: 'PWA', + children: [ + '/reference/plugin/pwa.md', + '/reference/plugin/pwa-popup.md', + ], + }, + { + text: 'Syntax Highlighting', + children: [ + '/reference/plugin/prismjs.md', + '/reference/plugin/shiki.md', + ], + }, + { + text: 'Theme Development', + children: [ + '/reference/plugin/active-header-links.md', + '/reference/plugin/git.md', + '/reference/plugin/palette.md', + '/reference/plugin/theme-data.md', + '/reference/plugin/toc.md', + ], + }, + ], + }, + ], +} diff --git a/docs/.vuepress/configs/sidebar/index.ts b/docs/.vuepress/configs/sidebar/index.ts new file mode 100644 index 00000000..7183393c --- /dev/null +++ b/docs/.vuepress/configs/sidebar/index.ts @@ -0,0 +1,2 @@ +export * from './en.js' +export * from './zh.js' diff --git a/docs/.vuepress/configs/sidebar/zh.ts b/docs/.vuepress/configs/sidebar/zh.ts new file mode 100644 index 00000000..fc75e512 --- /dev/null +++ b/docs/.vuepress/configs/sidebar/zh.ts @@ -0,0 +1,129 @@ +import type { SidebarConfig } from '@vuepress/theme-default' + +export const sidebarZh: SidebarConfig = { + '/zh/guide/': [ + { + text: '指南', + children: [ + '/zh/guide/README.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/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/reference/': [ + { + text: 'VuePress 参考', + 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: '打包工具参考', + collapsible: true, + children: [ + '/zh/reference/bundler/vite.md', + '/zh/reference/bundler/webpack.md', + ], + }, + { + text: '默认主题参考', + collapsible: true, + children: [ + '/zh/reference/default-theme/config.md', + '/zh/reference/default-theme/frontmatter.md', + '/zh/reference/default-theme/components.md', + '/zh/reference/default-theme/markdown.md', + '/zh/reference/default-theme/styles.md', + '/zh/reference/default-theme/extending.md', + ], + }, + { + text: '官方插件参考', + collapsible: true, + children: [ + { + text: '常用功能', + children: [ + '/zh/reference/plugin/back-to-top.md', + '/zh/reference/plugin/container.md', + '/zh/reference/plugin/external-link-icon.md', + '/zh/reference/plugin/google-analytics.md', + '/zh/reference/plugin/medium-zoom.md', + '/zh/reference/plugin/nprogress.md', + '/zh/reference/plugin/register-components.md', + ], + }, + { + text: '内容搜索', + children: [ + '/zh/reference/plugin/docsearch.md', + '/zh/reference/plugin/search.md', + ], + }, + { + text: 'PWA', + children: [ + '/zh/reference/plugin/pwa.md', + '/zh/reference/plugin/pwa-popup.md', + ], + }, + { + text: '语法高亮', + children: [ + '/zh/reference/plugin/prismjs.md', + '/zh/reference/plugin/shiki.md', + ], + }, + { + text: '主题开发', + children: [ + '/zh/reference/plugin/active-header-links.md', + '/zh/reference/plugin/git.md', + '/zh/reference/plugin/palette.md', + '/zh/reference/plugin/theme-data.md', + '/zh/reference/plugin/toc.md', + ], + }, + ], + }, + ], +} diff --git a/docs/.vuepress/public/browserconfig.xml b/docs/.vuepress/public/browserconfig.xml new file mode 100644 index 00000000..5bdd109f --- /dev/null +++ b/docs/.vuepress/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #ffffff + + + diff --git a/docs/.vuepress/public/favicon.ico b/docs/.vuepress/public/favicon.ico new file mode 100644 index 00000000..e481e5dd Binary files /dev/null and b/docs/.vuepress/public/favicon.ico differ diff --git a/docs/.vuepress/public/images/cookbook/extending-a-theme-01.png b/docs/.vuepress/public/images/cookbook/extending-a-theme-01.png new file mode 100644 index 00000000..9ba6d7e8 Binary files /dev/null and b/docs/.vuepress/public/images/cookbook/extending-a-theme-01.png differ diff --git a/docs/.vuepress/public/images/guide/vuepress-architecture-overview.png b/docs/.vuepress/public/images/guide/vuepress-architecture-overview.png new file mode 100644 index 00000000..4e64bee9 Binary files /dev/null and b/docs/.vuepress/public/images/guide/vuepress-architecture-overview.png differ diff --git a/docs/.vuepress/public/images/guide/vuepress-core-process.png b/docs/.vuepress/public/images/guide/vuepress-core-process.png new file mode 100644 index 00000000..acf17029 Binary files /dev/null and b/docs/.vuepress/public/images/guide/vuepress-core-process.png differ diff --git a/docs/.vuepress/public/images/hero.png b/docs/.vuepress/public/images/hero.png new file mode 100644 index 00000000..ac6beaff Binary files /dev/null and b/docs/.vuepress/public/images/hero.png differ diff --git a/docs/.vuepress/public/images/icons/android-chrome-192x192.png b/docs/.vuepress/public/images/icons/android-chrome-192x192.png new file mode 100644 index 00000000..ddd04391 Binary files /dev/null and b/docs/.vuepress/public/images/icons/android-chrome-192x192.png differ diff --git a/docs/.vuepress/public/images/icons/android-chrome-384x384.png b/docs/.vuepress/public/images/icons/android-chrome-384x384.png new file mode 100644 index 00000000..86e1fd58 Binary files /dev/null and b/docs/.vuepress/public/images/icons/android-chrome-384x384.png differ diff --git a/docs/.vuepress/public/images/icons/apple-touch-icon.png b/docs/.vuepress/public/images/icons/apple-touch-icon.png new file mode 100644 index 00000000..208915f1 Binary files /dev/null and b/docs/.vuepress/public/images/icons/apple-touch-icon.png differ diff --git a/docs/.vuepress/public/images/icons/favicon-16x16.png b/docs/.vuepress/public/images/icons/favicon-16x16.png new file mode 100644 index 00000000..ca5047e7 Binary files /dev/null and b/docs/.vuepress/public/images/icons/favicon-16x16.png differ diff --git a/docs/.vuepress/public/images/icons/favicon-32x32.png b/docs/.vuepress/public/images/icons/favicon-32x32.png new file mode 100644 index 00000000..e275ce9b Binary files /dev/null and b/docs/.vuepress/public/images/icons/favicon-32x32.png differ diff --git a/docs/.vuepress/public/images/icons/mstile-150x150.png b/docs/.vuepress/public/images/icons/mstile-150x150.png new file mode 100644 index 00000000..d0b14394 Binary files /dev/null and b/docs/.vuepress/public/images/icons/mstile-150x150.png differ diff --git a/docs/.vuepress/public/images/icons/safari-pinned-tab.svg b/docs/.vuepress/public/images/icons/safari-pinned-tab.svg new file mode 100644 index 00000000..dc0b992c --- /dev/null +++ b/docs/.vuepress/public/images/icons/safari-pinned-tab.svg @@ -0,0 +1,23 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/docs/.vuepress/public/images/logo.png b/docs/.vuepress/public/images/logo.png new file mode 100644 index 00000000..60e17006 Binary files /dev/null and b/docs/.vuepress/public/images/logo.png differ diff --git a/docs/.vuepress/public/manifest.webmanifest b/docs/.vuepress/public/manifest.webmanifest new file mode 100644 index 00000000..d2e935f1 --- /dev/null +++ b/docs/.vuepress/public/manifest.webmanifest @@ -0,0 +1,21 @@ +{ + "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" + } + ] +} diff --git a/docs/.vuepress/public/new.html b/docs/.vuepress/public/new.html new file mode 100644 index 00000000..911989fe --- /dev/null +++ b/docs/.vuepress/public/new.html @@ -0,0 +1 @@ + diff --git a/docs/.vuepress/styles/index.scss b/docs/.vuepress/styles/index.scss new file mode 100644 index 00000000..90dc235e --- /dev/null +++ b/docs/.vuepress/styles/index.scss @@ -0,0 +1,9 @@ +:root { + scroll-behavior: smooth; +} + +@media (min-width: 751px) { + #docsearch-container:lang(zh-CN) { + min-width: 184.66px; + } +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..b0378e61 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,26 @@ +--- +home: true +title: Home +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 + 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: Default 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 new file mode 100644 index 00000000..b80f495a --- /dev/null +++ b/docs/advanced/architecture.md @@ -0,0 +1,36 @@ +# Architecture + +## Overview + +![vuepress-architecture-overview](/images/guide/vuepress-architecture-overview.png) + +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 SPA. + +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 + +![vuepress-core-process](/images/guide/vuepress-core-process.png) + +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. \ No newline at end of file diff --git a/docs/advanced/cookbook/README.md b/docs/advanced/cookbook/README.md new file mode 100644 index 00000000..da53257d --- /dev/null +++ b/docs/advanced/cookbook/README.md @@ -0,0 +1,10 @@ +# 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 new file mode 100644 index 00000000..4725368d --- /dev/null +++ b/docs/advanced/cookbook/adding-extra-pages.md @@ -0,0 +1,38 @@ +# 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 new file mode 100644 index 00000000..8214310f --- /dev/null +++ b/docs/advanced/cookbook/making-a-theme-extendable.md @@ -0,0 +1,66 @@ +# 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](../../reference/default-theme/extending.md). 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 + +``` + +## 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 => { + 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: + +```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 new file mode 100644 index 00000000..cdbc1771 --- /dev/null +++ b/docs/advanced/cookbook/markdown-and-vue-sfc.md @@ -0,0 +1,78 @@ +# 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 new file mode 100644 index 00000000..28407066 --- /dev/null +++ b/docs/advanced/cookbook/passing-data-to-client-code.md @@ -0,0 +1,63 @@ +# 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/usage-of-client-config.md b/docs/advanced/cookbook/usage-of-client-config.md new file mode 100644 index 00000000..8dd27dce --- /dev/null +++ b/docs/advanced/cookbook/usage-of-client-config.md @@ -0,0 +1,174 @@ +# 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` package 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 { 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 + +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 { defineClientConfig } from '@vuepress/client' +import { onMounted } from 'vue' + +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 new file mode 100644 index 00000000..e0be81ba --- /dev/null +++ b/docs/advanced/plugin.md @@ -0,0 +1,63 @@ +# 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) => { + 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: + +```ts +const fooPlugin = (options) => { + return { + name: 'vuepress-plugin-foo', + // ... + } +} + +const barPlugin = (options) => { + return (app) => { + return { + 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 new file mode 100644 index 00000000..bb83bf16 --- /dev/null +++ b/docs/advanced/theme.md @@ -0,0 +1,100 @@ +# 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 + 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` : + +```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 + +``` + +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/README.md b/docs/guide/README.md new file mode 100644 index 00000000..d04f0854 --- /dev/null +++ b/docs/guide/README.md @@ -0,0 +1,39 @@ +# 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/assets.md b/docs/guide/assets.md new file mode 100644 index 00000000..7d3abb7f --- /dev/null +++ b/docs/guide/assets.md @@ -0,0 +1,121 @@ +# Assets + +## Relative URLs + +You can reference any assets using relative URLs in your Markdown content: + +```md +![An image](./image.png) +``` + +or + +```md +![An image](image.png) +``` + +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 +![VuePress Logo](/images/hero.png) +``` + +**Output** + +![VuePress Logo](/images/hero.png) + +### 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 + +![VuePress Logo](/images/hero.png) +``` + +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 +VuePress Logo +``` + +## 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 +Image from dependency +``` + +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 +Image from path alias +``` + +::: tip +Config reference: [alias](../reference/plugin-api.md#alias) +::: diff --git a/docs/guide/bundler.md b/docs/guide/bundler.md new file mode 100644 index 00000000..1a8640dc --- /dev/null +++ b/docs/guide/bundler.md @@ -0,0 +1,67 @@ +# Bundler + +VuePress has been using [Webpack](https://webpack.js.org/) as the bundler to dev and build sites. Since VuePress v2, other bundlers are also supported, and now we are using [Vite](https://vitejs.dev/) as the default bundler. Of course, you can still choose to use Webpack. + +## Choose a Bundler + +When using the [vuepress](https://www.npmjs.com/package/vuepress) package, Vite bundler is installed and used automatically. + +If you want to use Webpack bundler instead, you can remove it and install the [vuepress-webpack](https://www.npmjs.com/package/vuepress-webpack) package instead: + + + + +```bash +pnpm remove vuepress +pnpm add -D vuepress-webpack@next +``` + + + + + +```bash +yarn remove vuepress +yarn add -D vuepress-webpack@next +``` + + + + + +```bash +npm uninstall vuepress +npm install -D vuepress-webpack@next +``` + + + + +::: tip +In fact, the [vuepress](https://www.npmjs.com/package/vuepress) package is just a wrapper of the [vuepress-vite](https://www.npmjs.com/package/vuepress-vite) package. +::: + +## Configure Bundler + +Generally, you could use a bundler without extra configuration, because we have already configured them properly to work with VuePress. + +You can configure bundler for advanced usage via the [bundler](../reference/config.md#bundler) option: + +```ts +import { viteBundler } from 'vuepress' +// import { webpackBundler } from 'vuepress-webpack' + +export default { + bundler: viteBundler({ + vuePluginOptions: { + template: { + compilerOptions: { + isCustomElement: (tag) => tag === 'center', + }, + }, + }, + }), +} +``` + +You can refer to [Bundlers > Vite](../reference/bundler/vite.md) and [Bundlers > Webpack](../reference/bundler/webpack.md) to check out all options of the corresponding bundler. diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md new file mode 100644 index 00000000..f07eed61 --- /dev/null +++ b/docs/guide/configuration.md @@ -0,0 +1,92 @@ +# Configuration + +## Config File + +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): + +- 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): + +```sh +vuepress dev docs --config my-config.js +``` + +A basic config file looks like this: + +```ts +import { defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + 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 new file mode 100644 index 00000000..7f132b68 --- /dev/null +++ b/docs/guide/deployment.md @@ -0,0 +1,224 @@ +# 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@v2 + with: + # choose pnpm version to use + version: 8 + # install deps with pnpm + run_install: true + + - name: Setup Node.js + uses: actions/setup-node@v4 + 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@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`: 18 + +3. Hit the deploy button. + +## 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 new file mode 100644 index 00000000..944de1e5 --- /dev/null +++ b/docs/guide/getting-started.md @@ -0,0 +1,145 @@ +# 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/vuepress-next/blob/main/CHANGELOG.md) carefully each time you upgrade a RC version. +::: + +## Prerequisites + +- [Node.js v18.16.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` and `@vuepress/client` 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. + +::: + +## 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 + +```bash +mkdir vuepress-starter +cd vuepress-starter +``` + +- **Step 2**: Initialize your project + + + + +```bash +git init +pnpm init +``` + + + + + +```bash +git init +yarn init +``` + + + + + +```bash +git init +npm init +``` + + + + +- **Step 3**: Install VuePress locally + + + + +```bash +pnpm add -D vuepress@next @vuepress/client@next vue +``` + + + + + +```bash +yarn add -D vuepress@next +``` + + + + + +```bash +npm install -D vuepress@next +``` + + + + +- **Step 4**: 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" + } +} +``` + +- **Step 5**: Add the default temp and cache directory to `.gitignore` file + +```bash +echo 'node_modules' >> .gitignore +echo '.temp' >> .gitignore +echo '.cache' >> .gitignore +``` + +- **Step 6**: Create your first document + +```bash +mkdir docs +echo '# Hello VuePress' > docs/README.md +``` + +- **Step 7**: Serve the documentation site in the local server + + + + +```bash +pnpm docs:dev +``` + + + + + +```bash +yarn docs:dev +``` + + + + + +```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. + +By now, you should have a basic but functional VuePress documentation site. Next, learn about the basics of [configuration](./configuration.md) in VuePress. diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md new file mode 100644 index 00000000..0ec8175b --- /dev/null +++ b/docs/guide/i18n.md @@ -0,0 +1,72 @@ +# 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' + +export default { + theme: defaultTheme({ + locales: { + '/': { + selectLanguageName: 'English', + }, + '/zh/': { + selectLanguageName: '简体中文', + }, + }, + }), +} +``` + +::: tip +Config reference: [Default Theme > locales](../reference/default-theme/config.md#locales) +::: diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md new file mode 100644 index 00000000..bb594785 --- /dev/null +++ b/docs/guide/markdown.md @@ -0,0 +1,435 @@ +# Markdown + +Make sure you already know Markdown well before reading this section. If not, please learn some [Markdown tutorials](https://commonmark.org/help/) first. + +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. + +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. + +## Syntax Extensions + +This section will introduce built-in Markdown syntax extensions of VuePress. + +### 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 + │ ├─ markdown.md # <- Here we are + │ └─ README.md + ├─ reference + │ └─ config.md + └─ README.md +``` + +**Raw Markdown** + +```md + +[Home](../README.md) +[Config Reference](../reference/config.md) +[Getting Started](./getting-started.md) + +[Guide](/guide/README.md) +[Config Reference > markdown.links](/reference/config.md#links) + +[GitHub](https://github.com) +``` + +**Converted to** + +```vue + +``` + +**Rendered as** + +[Home](../README.md) +[Config Reference](../reference/config.md) +[Getting Started](./getting-started.md) +[Guide](/guide/README.md) +[Config Reference > markdown.links](/reference/config.md#links) +[GitHub](https://github.com) + +**Explanation** + +- Internal links will be converted to `` 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. + +#### 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,6-8} +import { defaultTheme, defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + title: 'Hello, VuePress', + + theme: defaultTheme({ + logo: 'https://vuejs.org/images/logo.png', + }), +}) +``` +```` + +**Output** + +```ts{1,6-8} +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: + +- Line ranges: `{5-8}` +- Multiple single lines: `{4,7,9}` +- Combined: `{4,7-13,16,23-27,40}` + +::: tip +This line highlighting extension is supported by our built-in plugin, which is forked and modified from [markdown-it-highlight-lines](https://github.com/egoist/markdown-it-highlight-lines). + +Config reference: [markdown.code.highlightLines](../reference/config.md#markdown-code-highlightlines) +::: + +#### 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** + +````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 +This line numbers extension is supported by our built-in plugin. + +Config reference: [markdown.code.lineNumbers](../reference/config.md#markdown-code-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.code.vPre.block](../reference/config.md#markdown-code-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](../reference/default-theme/components.md) for a full list of default theme built-in components. +::: + +## Custom Markdown Plugins + +Sometimes #940 + +## 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 `@bundler-webpack`, set [vue.compilerOptions](../reference/bundler/webpack.md#vue) + - For `@bundler-vite`, set [vuePluginOptions.template.compilerOptions](../reference/bundler/vite.md#vuepluginoptions) diff --git a/docs/guide/migration.md b/docs/guide/migration.md new file mode 100644 index 00000000..f0c15860 --- /dev/null +++ b/docs/guide/migration.md @@ -0,0 +1,393 @@ +# 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. 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](#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 +// .vuepress/config.js + +- module.exports = { +- // user config +- } + ++ export default { ++ // user config ++ } +``` + +#### theme + +Using a theme via string is not supported. Import the theme directly. + +```diff +- 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. + +```diff +- 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` to `true`. + +#### extraWatchFiles + +Removed. + +You can watch files manually in [onWatched](../reference/plugin-api.md#onwatched) hook. + +#### patterns + +Renamed to `pagePatterns` + +#### markdown.lineNumbers + +Moved to [markdown.code.lineNumbers](../reference/config.md#markdown-code-linenumbers). + +Default value is changed from `false` to `true`. + +#### 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 +- module.exports = { +- sass: { /* ... */ }, +- } + ++ import { webpackBundler } from '@vuepress/bundler-webpack' ++ export default { ++ 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 +// .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 + +- `: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](../reference/plugin/palette.md). + +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](../reference/default-theme/styles.md). + +### 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](../reference/plugin/register-components.md), 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 +- ![](@alias/foo.png) +- ![](package-name/bar.png) + ++ ++ +``` + +### 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 `` renamed to `` and `` +- `` + - `$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](../reference/default-theme/styles.md). + +#### 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](../reference/default-theme/config.md). + +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](../reference/plugin/register-components.md), 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](../reference/plugin/theme-data.md) 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](../reference/plugin/palette.md) may help. +- Markdown code blocks syntax highlighting by Prism.js is not embedded by default. You can use either [@vuepress/plugin-prismjs](../reference/plugin/prismjs.md) or [@vuepress/plugin-shiki](../reference/plugin/shiki.md), or implement syntax highlighting in your own way. +- For scalability concerns, `this.$site.pages` is not available any more. + +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](../reference/default-theme/extending.md) 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). diff --git a/docs/guide/page.md b/docs/guide/page.md new file mode 100644 index 00000000..2c627c8a --- /dev/null +++ b/docs/guide/page.md @@ -0,0 +1,64 @@ +# 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](../reference/default-theme/frontmatter.md) 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 `