百家饭团队开发的百家饭OpenAPI平台是用vuepress2.0搭建的,搭建的时候不知道2.0还处在beta状态,所以导致后来踩了一些坑,使用过程中vuepress2.0也从2.0.0-beta.18升到了2.0.0-beta.48,有很多的变化,所以想写一个教程介绍一下vuepress2.0的情况以及使用经验。

大致计划写这些内容吧:

  1. vuepress介绍、选型原因及使用感受(先介绍一下自己用的情况吧)
  2. vuepress2.0使用(搭建一个vuepress支撑的网站)-第一部分
  3. vuepress2.0使用(搭建一个vuepress支撑的网站)-修改默认模板配置
  4. vuepress2.0使用(搭建一个vuepress支撑的网站)-详细配置默认模板
  5. vuepress2.0使用(搭建一个vuepress支撑的网站)-md文件的玩法
  6. vuepress2.0使用(扩展默认主题)- 准备及扩展页面组件
  7. vuepress2.0使用(扩展默认主题)- 提供更多页面模板并引入ElementUI
  8. vuepress2.0使用(扩展默认主题)- 扩展MD页面功能(Section扩展及自定义语法)
  9. vuepress2.0使用(扩展默认主题)- 引入百度搜索支持及其他库的引用
  10. 编写vuepress主题(自定义自己的框架,开发复杂程序)
  11. vuepress2.0使用——编译及站点部署
  12. vuepress2.0当前的状态(版本变化,方便大家升级,占位中,未书写)
  13. 更多读者发起话题点击这里进专题查看,就不更新标题了

这里先给搜索进来的同学提个醒:凡是网上搜索到需要修改clientAppEnhance.js 文件的教程都已经过时,最新版本已不再使用。另外说个题外话,我查了下,我为数不多的搜索关键词里面,vuepress的占了大部分,这里感谢大家的关注,这个教程肯定有不合理的地方,如果有任何需要帮助的,大家都可以留言,我尽力解答。

引入新模板

上一篇文章我们讲了使用默认主题的插槽来达到扩展页面功能的目的,但是有的时候,我们还是需要提供不同的模板来渲染不同的页面,本篇来介绍相关的方法。

模板的引入上一章我们提到过,就是在index.js里面定义更多的layout即可,比如我们有一个欢迎页面,则可以定义一个名叫Welcome的layout,修改index.js如下:

const { defaultTheme } = require('@vuepress/theme-default');
const { path } = require('@vuepress/utils')

module.exports = (options) => {
    return {
        name: 'vuepress-theme-local',
        extends: defaultTheme(options),
        layouts: {
            Layout: path.resolve(__dirname, 'layouts/Layout.vue'),
            Welcome: path.resolve(__dirname, 'layouts/Welcome.vue'),
        },
    }
}

主要添加的就是定义Welcome的那一行

指定页面使用某个模板

那这下我们就有了两个模板了,怎么让md知道使用哪个模板呢?

答案是在md文件的全局标签(关于全局标签的介绍,详见第五章)中指定layout


---
layout: Welcome
---

编写新的页面模板

在自定义模板中调用md文件内容

<template>
<Content></Content>
</template>

一个最简单的可以展示MD文件内容的模板如上段代码所示,其中的Content元素就指代MD文件渲染出来的HTML内容。

因此,如果需要在页面层面部署和定义更丰富的组件,我们直接像编辑普通VUE的形式进行开发即可,最后在需要显示文章内容的地方用<Content></Content>指代就可以了。

在自定义模板中使用默认主题的元素

有时,我们在使用自定义模板的同时,也希望能够用上主题中的导航栏等组件,这时,我们可以直接通过引用相关组件来达到这个效果,我们继承的默认主题为我们提供了四个组件来帮助我们构建自定义模板,他们分别是:

  1. Home.vue:首页组件
  2. Navbar.vue: 导航栏组件
  3. Page.vue:封装过的主要内容组件(和直接引用Content区别在于有文章和边栏部分的样式)
  4. Sidebar.vue: 边栏组件

引用的时候,我们直接像下面这样引用'@theme/xxx.vue'即可,请注意这个方法只有继承了默认主题才有效。

<script setup>
import Home from '@theme/Home.vue'
import Navbar from '@theme/Navbar.vue'
import Page from '@theme/Page.vue'
import Sidebar from '@theme/Sidebar.vue'
</script>

<template>
<Navbar></Navbar>
<Content></Content>
</template>

引入Element-UI

上面我们讲到我们可以直接编程自己想要的各种不同的页面模板,那作为国内常见的vue框架,Elment-UI肯定是很多人想要引用并作为基础使用的一个库,现在我们介绍在vuepress 2.0里面使用Elment-UI会遇到的一些问题。

引用依赖

首先当然是通过npm或者yarn安装element-plus,然后,如果你按照官方Element-UI指引的话,他会建议你安装下面两个库以便使用自动引用功能

unplugin-vue-components unplugin-auto-import

这两个东西如果不是我配置错误的话,我尝试了很多次,并没有用处,依然需要手工引用相关的style等。

我们用最开始创建的welcome.vue为例,引用el-card来做个例子

<script setup>
import { ElCard } from "element-plus"
</script>

<template>
    <el-card>
        <Content></Content>
    </el-card>
</template>

刷新之后,我们可以看到el-card被正确解析为html,但是缺乏必要的样式文件。

这时我们需要手工引用以下依赖,将welcome.vue改为

<script setup>
import { ElCard } from "element-plus"

if (!__VUEPRESS_SSR__) {
    import("element-plus/es/components/card/style/css");
}
</script>

<template>
    <el-card>
        <Content></Content>
    </el-card>
</template>

这里看到,我们加入了对el-card的style文件("element-plus/es/components/card/style/css")的依赖

但是我们把他放到了一个if里面,这里我们扩展讲一个这个问题

vuepress的服务器端渲染(SSR)

vuepress的整个工作流程,会把内容先在服务器端进行渲染,然后再生成vue标准的文件,在请求时,会进行服务器端和客户端比对,一致后才认为正确,这个流程我讲的可能不是很正确,有兴趣的可以进一步调研。

但是这个的结果就是,像element-ui这类的浏览器库就会出现兼容性问题,比如上面这个引用,如果不用if (!__VUEPRESS_SSR__) 括起来,dev的时候没有任何错误,在build时就会出错

Error [ERR_REQUIRE_ESM]: require() of ES Module D:\workspace\vuepress-demo\node_modules\element-plus\es\components\card\style\css.mjs not supported.
Instead change the require of D:\workspace\vuepress-demo\node_modules\element-plus\es\components\card\style\css.mjs to a dynamic import() which is available in all CommonJS modules.
    at D:\workspace\vuepress-demo\docs\.vuepress\.temp\.server\app.js:2484:48 {

那这个if的作用是什么呢?这个__VUEPRESS_SSR__就是用来告诉编译器,当前处在什么样的编译阶段,如果这个常量为真,则是服务器渲染阶段,如果不是,则是客户端阶段,所以针对客户端的模块调用必须使用这个进行判断包括,其余我们发现的需要包裹的情况还包括:

  1. setInterval
  2. setTimeout
  3. 需要调用window的各类函数的操作

好了,完成了这样的步骤,我们就可以使用element-ui了,但是如果每个页面都要重复一遍这种引用,也是一件很费劲的事情,所以我们要介绍一种全局引用的方法。

在client.js文件里完成全局引用

什么是vuepress的client.js

这是一段官方描述

在大多数情况下,配置文件已经足够帮助你配置好你的 VuePress 站点。不过,有些时候用户们可能希望直接添加一些客户端代码。 VuePress 通过客户端配置文件来支持这种需求:

 上面提到的这个client.js,就是我们需要进行客户端配置的地方,这个配置可以放在.vuepress里作为站点配置,也可以放在.vuepress/theme里面作为主题的配置,我们主要讲主题的编辑,所以我们使用主题下的配置。

为了让主题下的client.js生效,我们还需要在theme/index.js里增加以下代码:

const { defaultTheme } = require('@vuepress/theme-default');
const { path } = require('@vuepress/utils')

module.exports = (options) => {
    return {
        ……
        clientConfigFile: path.resolve(__dirname, './client.js'),
        ……
    }
}

也就是增加一个名为clientConfigFile的配置项( 这就是我们一直在系列中提示搜索用户clientAppEnhance.js不再使用的原因,在新版中已经使用这个配置项了),指向client.js,当然这个文件叫其他名称也可以,只要通过这个配置项指定即可。

这样,我们就可以在client.js里为element-ui增加以下两个配置,同样的,仍然需要进行!__VUEPRESS_SSR__的判断。

设置语言

import ElementPlus from 'element-plus'
import { defineClientConfig } from '@vuepress/client'

export default defineClientConfig({
    enhance({ app }) {
        if (!__VUEPRESS_SSR__) {
            import('element-plus/es/locale/lang/zh-cn').then(module => {
                app.use(ElementPlus, {
                    locale: module.default,
                })
            })
        }
    }
});

引用element-ui的语言文件,并通过配置来激活。

全局引用多种element组件

import ElementPlus from 'element-plus'
import { defineClientConfig } from '@vuepress/client'
import { ElCard } from "element-plus"

export default defineClientConfig({
    enhance({ app }) {
        if (!__VUEPRESS_SSR__) {
            import('element-plus/es/locale/lang/zh-cn').then(module => {
                app.use(ElementPlus, {
                    locale: module.default,
                })
            })
            import("element-plus/es/components/card/style/css");
        }
        app.component('el-card', ElCard)
    }
});

这里增加的部分是第三行引用ElCard,13行在if (!__VUEPRESS_SSR__)时引用style,15行,将el-card作为app的通用组件进行注册。

这里注意,app.component('el-card', ElCard)是放在if (!__VUEPRESS_SSR__) 外面的,这样可以保证ssr时可以生成一致的内容。

好了,完成这样的操作后,就可以全局使用ElCard控件了,(其他空间类似)。当然,我们仍然建议在页面级引用不常见组件,而把通用组件放在client.js里面,毕竟vuepress是个多页面应用,不常见的库没必要每个页面都去导入一遍。

Logo

前往低代码交流专区

更多推荐