前言

笔者维护的 VitePress 博客主题在近1年多的时间里集成了非常多功能,不少用户希望将里面的部分功能分离出来,方便在其它 VitePress 站点也可以独立使用。

其中分离的第一个组件类型的就是呼声较高的 公告插件

最终效果如下:

接下来将介绍一下用法,讲解一下实现原理,提供一个插件模板供大家快速开发同类型插件。

如何使用

只需要 2 步:

  1. 安装插件

pnpm/npm/yarn 均可,笔者比较偏好 pnpm

pnpm add vitepress-plugin-announcement
  1. 配置插件

引入插件在 .vitepress/config.ts VitePress 配置文件中

import { defineConfig } from 'vitepress'
import { AnnouncementPlugin } from 'vitepress-plugin-announcement' export default defineConfig({
vite: {
// ↓↓↓↓↓
plugins: [
AnnouncementPlugin({
title: '标题',
body: [
{ type: 'text', content: '文本内容' },
{
type: 'image',
src: '图片'
}
],
footer: [
{
type: 'button',
content: '按钮',
link: 'https://sugarat.top'
},
],
})
]
// ↑↑↑↑↑
}
})

目前支持 文本/图片/按钮 三种类型。

实现原理

这里只阐述关键点,详细部分将计划单独拆一篇文章进行讲解(完整的搭配插件模板 0 - 1 实现)

注入自定义组件

VitePress 官方文档自定义板块 中可以了解到,

VitePress 入口的组件是在 .vitepress/theme/index 中导出的 Layout.vue 组件。

同时 VitePress 默认主题的 Layout 已经提供了许多可以直接使用的插槽,于是乎,咱们可以把组件直接放入这些位置即可。

VitePress 是由 Vite 驱动,所以按照 Vite 插件的思路去拓展即可。

这里利用插件的 transform 钩子 去处理。

const pluginOps = {
name: 'vitepress-plugin-announcement',
transform(code, id) {
// 具体处理逻辑
}
}

将我们的组件插入到默认主题的 Layout.vue 里即可。

期望插入后的代码如下

<script setup lang="ts">
import Announcement from './Announcement.vue' // [!code ++]
</script> <template>
<div>
<slot name="layout-top" />
<Announcement /> // [!code ++]
</div>
</template>

下面是具体的处理逻辑,简单字符串替换插入我们需要的内容即可

const pluginOps = {
name: 'vitepress-plugin-announcement',
enforce: 'pre',
transform(code, id) {
// 筛选出 Layout 文件
if (id.endsWith('vitepress/dist/client/theme-default/Layout.vue')) {
// 插入自定义组件调用代码
const slotPosition = '<slot name="layout-top" />'
let transformResult = code.replace(slotPosition, `${slotPosition}<Announcement/>`) // 导入自定义组件导入代码
const setupPosition = '<script setup lang="ts">'
transformResult = transformResult.replace(setupPosition, `${setupPosition}\nimport Announcement from './Announcement.vue'`)
return transformResult
}
}
}

同时通过 enforce 参数控制插件顺序,这里需要尽可能的提前执行,处理源代码。

接下来就是处理 import 的导入,如果不做处理,Layout.vue 里是找不到这些组件,就一定会报错。

import Announcement from './Announcement.vue' // [!code ++]

于是这里,再利用 config 钩子,传入 resolve.alias 配置 即可。

// 构造插件里实际组件的路径
const aliasComponentFile = `${getDirname()}/components/Announcement.vue` const pluginOps = {
config() {
return {
resolve: {
alias: {
'./Announcement.vue': aliasComponentFile
}
}
}
}
}

至此自定义组件的注入就算是完成了,接下来介绍如何将外部的参数传入到组件里。

插件配置传递

方式有很多种,笔者这里采用改动最小,使用较为广泛的一种 虚拟模块

官方示例里已经介绍了如何使用,这里不做赘述。

组件中导入配置代码

<script lang="ts" setup>
import announcementOptions from 'virtual:announcement-options'
</script>

插件中处理虚拟模块逻辑。

import { stringify } from 'javascript-stringify'

function AnnouncementPlugin(options) {
const virtualModuleId = 'virtual:announcement-options'
const resolvedVirtualModuleId = `\0${virtualModuleId}` const pluginOps = {
name: 'vitepress-plugin-announcement',
enforce: 'pre',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(this, id) {
if (id === resolvedVirtualModuleId) {
// 虚拟模块处理
return `export default ${stringify(options)}`
}
},
}
return pluginOps
}

tips:由于 JSON.stringify 默认不会处理函数,这里就偷懒用一下社区的库 javascript-stringify 进行处理。

如果要用 JSON.stringify 处理,需要传入第二个 replacer 参数,对函数做特殊处理。

至此,关键的两步就算搞定了,剩余的工作就是具体组件的样式和交互实现开发了,按常规 Vue 组件开发即可。

插件模板介绍

在开发插件的过程中,笔者把此类基于 slot 位置注入的插件分离了一个模板 vitepress-plugin-slot-inject-template

目录结构

├── scripts # 构建相关脚本,无特殊需求可以不用修改
| ├── copyComponents.mjs
| └── watchAndCopy.mjs
├── src
| ├── components # 组件实现
| ├── index.ts # 插件入口
| ├── type.ts # 插件配置参数类型定义
| └── util.ts # 插件使用的工具函数
├── README.md
├── package.json
└── tsconfig.json

参考了 VitePress 默认主题中部分实现。

使用步骤

  1. 插件入口 src/index.ts,修改一下插件&组件命名信息和组件插入位置。
  2. 按照实际需求编写组件实现。
  3. 完善 README.md 使用文档后发布 npm 包即可。

最后

样式实现参考了 reco-1.x 主题 中的 @vuepress-reco/vuepress-plugin-bulletin-popover 插件

后续继续按照 vitepress 插件开发计划 推进,将开发过程内容整理成教程与插件模板。

插件完整源码 vitepress-plugin-announcement

适用于 VitePress 的公告插件开发实记的更多相关文章

  1. Sed 实记 · laoless's Blog

    sed编辑命令 p 打印匹配行 = 打印文件行号 a 在定位行之后追加文本 i 在定位行之前插入文本 d 删除定位行 c 用新文本替换定位文本 s 使用替换模式替换相应模式 r 从另一个文件读取文本 ...

  2. awk处理实记

    经grep日志后得到的数据格式如下: } . [debug][-- ::] SendDataStyled:{ , "innings" : "6189269620_0007 ...

  3. 实记JLink刷固件方法

    最近J-Link调试程序,不知何故,USB报无法连接,试了别的电脑也是这样.文件存于“百度网盘/05.组装维修/4.单片机/1.JLink-ARM仿真器”下.所有的操作基于WIN7 32位系统. 1. ...

  4. tomcat 优化实记

    好记性不如烂笔头,以下是 tomcat 无脑优化 1.内存设置(VM参数调优)(1). Windows环境下,是tomcat解压版(执行startup.bat启动tomcat)  解决办法:修改“%T ...

  5. asp.net mvc项目实记-开启伪静态-Bundle压缩css,js

    百度这些东西,还是会浪费了一些不必要的时间,记录记录以备后续 一.开启伪静态 如果不在web.config中配置管道开关则伪静态无效 首先在RouteConfig.cs中中注册路由 routes.Ma ...

  6. SpringBoot + SpringCloud学习踩坑实记

     踩的坑: 1).springcloud框架中,依赖一直报错,很可能是没有添加springcloud的依赖,或者是依赖的版本号过低.并且springboot也有一个父依赖. 2.springcloud ...

  7. springboot 完整企业项目搭建实记

    昨天搭建ssm框架时突然想到可以搭建springboot来完美解决配置复杂的问题,今天学习了一下springboot的搭建,在此记录一下搭建的过程和踩过的坑 这里给自己定一个该框架搭建完成的目标,如下 ...

  8. 实记处理mongodb的NUMA问题

    一次在启动mongodb的过程中,出现过NUMA这个问题, mongodb日志显示如下: WARNING: You are running on a NUMA machine. We suggest ...

  9. EJB组件开发实记(1)

    安装JBoss或者Wildfly jdk1.4以上. Eclipes安装插件 JBoss Tools: eclipes Jee photon 在eclipes 内部点击 >>Windows ...

  10. Fedora26安装Mysql实记(包含yum换源教程)

    课程实验中有一项是安装Hive,这个过程中需要安装Mysql. 在安装Mysql耗费了好多时间,总是报错数据仓库同步失败什么的. 输入yum install mysql 就提示错误,连接不上数据源.该 ...

随机推荐

  1. 整段 html实现其中的每一个 a 标签跨域下载操作 window.URL.createObjectURL(blob)

    window.URL.createObjectURL(blob) a 标签下载问题,通常在 a 标签中加上download属性,就可完成对href属性链接文件的下载,但仅仅是限于同源文件,如果是非同源 ...

  2. RHCA rh442 001 调优本质 调优方法 监控

    调优是一种感知 调优按照成本和性能 一.架构及调优 二.代码及调优 三.配置类调优 从调优效果和成本成正比 设计电商,日访问百万级,未来可能千万级 数据库 系统 服务器多少台 缓存 appache,n ...

  3. 【Mybatis-Plus】联表分页查询实现

    参考文章: https://blog.csdn.net/weixin_43847283/article/details/125822614 上上周写的SQL案例确实可以重构,所以搬到Demo里面测试看 ...

  4. 【Hibernate】05 缓存与MySQL事务隔离

    Cache 什么是缓存? 数据存储到数据库,是从内存中以流的方式写进[输出]到数据库,其效率并不是很高 - 所以在内存中暂存一部分数据,可以不以流的方式读取,效率是非常高的[相对于流来说] Hiber ...

  5. 【DataBase】MySQL 28 流程控制

    一.分支结构 1.IF函数 语法: IF(表达式1, 表达式2, 表达式3) 类似三元运算符,表达式1返回True Or False True执行表达式2,False执行表达式3 IF实现多分枝结构 ...

  6. 从.net开发做到云原生运维(五)——云原生时代绕不开的Kubernetes

    1. 前言 前面的几篇文章主要是讲.net技术栈里的web开发技术,只是单纯的开发,从一个简单的项目到最后的打包成镜像进行分发. Kubernetes算是开启了一个新时代. 2. Kubernetes ...

  7. 为什么模具设计人员中很多人不喜欢使用CAE仿真软件呢? —— 以汽车制造领域为例

    参考论文: 通常 的有限元分析软件在后处理 上只是将计算结果 以图形或表格的 方式显 示 在屏幕上 , 并没有对计算结果进行系统的整理 和提炼 . 在基于有 限元 计算结果 的反复设计过程 中, 设计 ...

  8. 高校校园网下电脑IP是不是公网IP

    突然想到一个问题,那就是高校校园网中的IP地址是不是公网IP,如果不是公网IP那么就是使用net后的共享IP,还或者是部分人用公网IP然后另一部分人使用net后的共享IP??? =========== ...

  9. &times被替换成x 的解决办法

    今天写代码遇到一个很有趣的问题: 在php中使用echo 输出url的时候当url中包含&times字段时就会被html直接解析成 x (乘号)这样一来我返回的地址就不能正常访问url了: 解 ...

  10. 【入门教程】5分钟教你快速学会集成Java springboot ~

    介绍 Apache DolphinScheduler是一个分布式易扩展的开源分布式调度系统,支持海量数据处理,具有任务流程调度.任务流程编排.任务监控告警.工作流引擎等功能. 本文将介绍如何将Apac ...