vue进阶04-vue文档生成工具vuepress2

介绍

VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 Markdown 来书写内容(如文档、博客等),然后 VuePress 会帮助你生成一个静态网站来展示它们。

VuePress 诞生的初衷是为了支持 Vue.js 及其子项目的文档需求,但是现在它已经在帮助大量用户构建他们的文档、博客和其他静态网站

它是如何工作的?

一个 VuePress 站点本质上是一个由 Vue 和 Vue Router 驱动的单页面应用 (SPA)。

路由会根据你的 Markdown 文件的相对路径来自动生成。每个 Markdown 文件都通过 markdown-it 编译为 HTML ,然后将其作为 Vue 组件的模板。因此,你可以在 Markdown 文件中直接使用 Vue 语法,便于你嵌入一些动态内容。

在开发过程中,我们启动一个常规的开发服务器 (dev-server) ,并将 VuePress 站点作为一个常规的 SPA。如果你以前使用过 Vue 的话,你在使用时会感受到非常熟悉的开发体验。

在构建过程中,我们会为 VuePress 站点创建一个服务端渲染 (SSR) 的版本,然后通过虚拟访问每一条路径来渲染对应的 HTML 。这种做法的灵感来源于 Nuxt 的 nuxt generate 命令,以及其他的一些项目,比如 Gatsby。

为什么不是 …?

Nuxt

Nuxt 是一套出色的 Vue SSR 框架, VuePress 能做的事情,Nuxt 实际上也同样能够胜任。但 Nuxt 是为构建应用程序而生的,而 VuePress 则更为轻量化并且专注在以内容为中心的静态网站上。

VitePress

VitePress 是 VuePress 的孪生兄弟,它同样由 Vue.js 团队创建和维护。 VitePress 甚至比 VuePress 要更轻更快,但它在灵活性和可配置性上作出了一些让步,比如它不支持插件系统。当然,如果你没有进阶的定制化需求, VitePress 已经足够支持你将你的内容部署到线上。

这个比喻可能不是很恰当,但是你可以把 VuePress 和 VitePress 的关系看作 Laravel 和 Lumen 。

Docsify / Docute

这两个项目同样都是基于 Vue,然而它们都是完全的运行时驱动,因此对 SEO 不够友好。如果你并不关注 SEO,同时也不想安装大量依赖,它们仍然是非常好的选择!

Hexo

Hexo 一直驱动着 Vue 2.x 的文档。Hexo 最大的问题在于他的主题系统太过于静态以及过度地依赖纯字符串,而我们十分希望能够好好地利用 Vue 来处理我们的布局和交互。同时,Hexo 在配置 Markdown 渲染方面的灵活性也不是最佳的。

GitBook

过去我们的子项目文档一直都在使用 GitBook 。 GitBook 最大的问题在于当文件很多时,每次编辑后的重新加载时间长得令人无法忍受。它的默认主题导航结构也比较有限制性,并且,主题系统也不是 Vue 驱动的。GitBook 背后的团队如今也更专注于将其打造为一个商业产品而不是开源工具。

快速上手

环境要求

Node.js v14.18.0+
Yarn v1 classic (尽量用yarn安装依赖,npm尝试n多次各种兼容问题)

hellworld

步骤1: 创建并进入一个新目录

mkdir vuepress-starter
cd vuepress-starter

步骤2: 初始化项目

yarn init

步骤3: 将 VuePress 安装为本地依赖

yarn add -D vuepress@next

步骤4: 在 package.json 中添加一些 scripts

{
  "scripts": {
    "docs:dev": "vuepress dev docs",
    "docs:build": "vuepress build docs"
  }
}

安装本地vuepress后可使用命令行运行

.\node_modules\.bin\vuepress dev docs
# 分析vuepress.cmd后发现执行的js文件是
node .\node_modules\vuepress\bin\vuepress.js dev docs
# vuepress1.x md文件过多,存内存溢出的增加内存执行方式
node --max_old_space_size=7096 ./node_modules/vuepress/cli.js build
# vuepress2.x md文件过多,内存溢出的增加内存执行方式 vuepress.1.x
node --max_old_space_size=7096 ./node_modules/vuepress\bin\vuepress.js build

步骤5: 将默认的临时目录和缓存目录添加到 .gitignore 文件中

echo 'node_modules' >> .gitignore
echo '.temp' >> .gitignore
echo '.cache' >> .gitignore

步骤6: 创建你的第一篇文档

mkdir docs
echo '# Hello VuePress' > docs/README.md

步骤7: 在本地启动服务器来开发你的文档网站

yarn docs:dev

VuePress 会在 http://localhost:8080 启动一个热重载的开发服务器。当你修改你的 Markdown 文件时,浏览器中的内容也会自动更新。

增强指南

config.js 配置

通用配置

以下是一份大而全的配置,包括国际化,导航栏,侧边栏,插件

import { defineUserConfig } from 'vuepress'
import { defaultTheme } from '@vuepress/theme-default'
import { searchPlugin } from '@vuepress/plugin-search'
//自定义插件
import sideBarPlugin  from './plugins/sidebar'
export default {
    base: '/jiedoc/',
    cmd: 'node ./node_modules/vuepress/bin/vuepress.js build',
    plugins:[
        sideBarPlugin, //自定义的插件
        searchPlugin({
            // 搜索插件
          }),
        'vuepress-plugin-mermaidjs',  //支持各种图形(流程图)等的插件
        '@maginapp/vuepress-plugin-flowchart', //支持各种图形(mermaid流程图)等的插件
        {
            openMarker:'```mermaid',
            closeMarker:'```',
            scondMarker:'flowchat',
            ignoreSecondLine:false
        }
    ],
    markdown:{
        anchor:{ permalink:false },
        toc:{ includeLevel:[1, 2] },
        extendMarkdown:md => {
            md.use(require('markdown-it-katex'))
                .use(require('markdown-it-footnote'))
                .use(require('markdown-it-ins'))
                .use(require('markdown-it-mark'))
                .use(require('markdown-it-sub'))
                .use(require('markdown-it-sup'))
                .use(require('markdown-it-abbr'))
        },
        lineNumbers: true, // 显示代码行号
    },
    head: [
        //引用一些静态的资源
        ['link', { rel: 'shortcut icon', type: "image/x-icon", href: "/assets/img/favicon.ico" }],
        ['link', { rel: 'apple-touch-icon', type: "image/x-icon", href: "/assets/img/apple-touch-icon.png" }],
        ['link', { rel: 'icon', type: "image/png", sizes: "32x32", href: "/assets/img/favicon-32x32.png" }],
        ['link', { rel: 'icon', type: "image/png", sizes: "16x16", href: "/assets/img/favicon-16x16.png" }],
        ['link', { rel: 'manifest', href: "/assets/img/site.webmanifest" }],
        ['script', { src: '/assets/js/jquery/3.3.1/jquery.slim.min.js' }],
        ['script', { src: '/assets/js/fancybox/3.5.2/jquery.fancybox.min.js' }],
        ['link', { rel: 'stylesheet', type: 'text/css', href: '/assets/css/fancybox/3.5.2/jquery.fancybox.min.css' }]
    ],
    theme:defaultTheme({
        locales: {
            '/':
            {
                selectText: '选择语言',
                selectLanguageName: '简体中文',
                logo: '/assets/img/logo.png',
                lastUpdated: '上次更新',
                smoothScroll: true,
                navbar: 
              [
                   { text: 使用指引', 
                    ariaLabel: 'Apos micro-mall operation guidelines',
                    children:
                        [
                          { text: '基本功能流程指引', link: '/zh-cn/ttttttt.html'},
                          { text: '商城', link: '/zh-cn/t.html'},
                            ]
                         },
                   { text: '业务系统使用指引', 
                    ariaLabel: 'Apos cashier operation guidelines',
                    children:
                        [
                          { text:'商品管理',link: '/zh-cn/gg.html'},
                          { text: '库存管理', link: '/zh-cn/gg1.html'}
                            ]
                         }
                    ],
                sidebar: 'auto'
            },
            '/en-us/':
            {
                selectText: 'Languages',
                selectLanguageName: 'English',
                logo: '/assets/img/logo.png',
                lastUpdated: 'Last Updated',
                smoothScroll: true,
                navbar:
                    [
                        { text: 'Doc Guide', link: '/en-us/product/guide/' }
                    ],
                sidebar: 'auto'
            },
        }
    }),
    locales:  //注意一定要在最外层定义了locales才会显示出选择语言
    {
        '/':
        {
            lang: 'zh-CN',
            title: '测试帮助中心',
            description: ''
        },
        '/en-us/':
        {
            lang: 'en-US',
            title: 'Helper Center',
            description: ' '
        },
    }
}

sidebar

全局sidebar

在config.js中配置sidebar:auto将自动将markdown的2级和3级标题显示在sidebar上,如果需要自定义sidebar可配置为(config.js):

sidebar:[
						{
							text:'新手入门',
							sidebarDepth:1, 
							collapsible:true,
							children:[
								{text:'新手入门指导', link:'/hello/first.md'},
							]
						},
						{
							text:'店铺认证',
							sidebarDepth:1, 
							collapsible:true,
							children:[
								{text:'主题认证教程', link:'/auth/body'},
								{text:'品牌认证教程', link:'/auth/pp'},
								{text:'入驻资质教程', link:'/auth/rz'},
								{text:'店铺命名指引', link:'/auth/dp'},
							]
						},
					],

link表示跳转的markdown文件

注意如果跳转到其他的markdown了,其他markdown没有配置页面级别sidebar将引用全局config.js的sidebar。

页面sidebar

也可以在单独的markdown使用yaml配置

---
 sidebar: 
  - text: "Group"
    children: 
    - text: "SubGroup"
      children: 
        - text: "hello1"
          link: "/group/a/"
        - text: "hello2"
          link: "/group/b/"
  - text: "Group 2"
    children: 
    - text: "gg1"
      link: "/group/a/"
    - text: "gg2"
      link: "/hello/second/"
---
# ttt
## aaa


## bbb

当浏览器访问该页面时自动引用当前页面的sidebar,同时也可以指定sidebarDepth来当前页面sidebar激活的标题显示深度,0表示不显示markdown文件的标题,1表示显示2级标题,2表示显示3级标题,1级标题永远不显示。

navbar

集成ui框架elementplus

vuepress2使用vue3.0开发,这里选择集成elementplus使用他的一些菜单和按钮组件。
vue3.0建议使用组合式编程提高复用性。
效果演示:
在这里插入图片描述
引入elemetplus

npm install element-plus --save

在.vuepress/client.js中,use,关注enhance即可


import { defineClientConfig } from '@vuepress/client'
import Layout from './layouts/Layout.vue'
import * as Icons from '@element-plus/icons-vue'
import ElementPlus from 'element-plus'
import 'element-plus/theme-chalk/index.css'

export default defineClientConfig({
  enhance({ app, router, siteData }){
    app.use(ElementPlus)
    // icon
    for (const icon in Icons) {
      // eslint-disable-next-line import/namespace
      app.component('ElIcon' + icon, Icons[icon])
    }
  },
  setup(){
    
  },
  layouts: {
    Layout
  }
})

新增一个配置导航栏菜单的json文件,新增.vuepress/navbar.json

{
   "tabList":[
    {
        "title":"首页",
        "href":"/"
    },
    {
        "title":"帮助中心",
        "href":"/zh-cn/Open-API/APOS开放平台1210统一对接方案.html",
        "children":[{
                "title":"发货流程",
                "href":"/zh-cn/Help-Document/Apos_cashier/commodity/Commodity_delivery_warehouse.html"
            },
            {
                "title":"商城分销",
                "href":"/zh-cn/Help-Document/Micro_mall/商城分销业务/"
            }
        ]
    },
    {
        "title":"常见问题",
        "href":"/zh-cn/Help-Document/Micro_mall/商城分销业务/independent-distribution.html"
    },
    {
        "title":"技术帮助中心",
        "href":"/zh-cn/Help-Document/Micro_mall/商城分销业务/直接分销.html"
    }
   ]
}

薪资TopHeader.vue替换navbar






config.js设置别名替换

export default {
    alias: {
        '@theme/Navbar.vue': path.resolve(__dirname, './layouts/TopHeader.vue'),
    }
 }

布局继承

需求:
所有的markdown页面拓展底部新增一个好用和不好用的评价按钮
效果:
vue进阶04-vue文档生成工具vuepress2_第1张图片
vuepress在markdown布局时提供了一些插槽可以用于新增内容,比如page-content-bottom就是内容底部:https://v2.vuepress.vuejs.org/zh/reference/default-theme/extending.html#%E5%B8%83%E5%B1%80%E6%8F%92%E6%A7%BD
.vuepress下新建目录和文件layouts/Layout.vue




新增.vuepress/client.js

import { defineClientConfig } from '@vuepress/client'
import Layout from './layouts/Layout.vue'
export default defineClientConfig({
  enhance({ app, router, siteData }){
    
  },
  setup(){
    
  },
  layouts: {
    Layout
  }
})

ssr渲染

布局页面使用ssr将整个vue在服务器上解析,不能出现常用的浏览器对象(window,navigator等),他会将所有的前端页面markdown调用Layout.vue进行渲染。
需求:在layout.vue中排除掉部分页面,不出现有用和无用的按钮。
methods中添加ifExcept方法

   //引用页面数据
  import { usePageData } from '@vuepress/client'
  //method添加方法
  methods:{
    ifExcept(){
      const page = usePageData()//这里就可以获取到页面定义的frontmatter和页面数据
      const compilePath=page._value.path;//获取渲染的页面路径
      let footExceptVar=footExcept?.except||[];
      return footExceptVar.indexOf(decodeURI(compilePath))<0
    }
    }

在#page-content-bottom中添加v-if即可