适用于 VitePress 的公告插件开发实记

news/2024/11/16 10:28:15/文章来源:https://www.cnblogs.com/roseAT/p/18424345

前言

笔者维护的 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/801138.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4 个

8 9 5 6 6 8 1 6

2024 CSP-S 游记

遗失星海超神摘要等放了假再补8.22 下午 \(huge\) 说要报名 \(CSP\) 的事情,把全网开了,光速上 \(w3\) 扒下照片然后又光速上 \(163\) 邮箱拿验证码然后就注册账号了,过了一会儿就看见教练给报好了 \(CSP-S\) 。拿 \(QQ\) 邮箱的需要验证码所以 \(huge\) 把手机发了下来,还…

基于 Qwen2.5-Coder 模型和 CrewAI 多智能体框架,实现智能编程系统的实战教程

Qwen2.5 开源的系列模型中,Qwen2.5-Coder 模型的推理能力技压群雄,本文集合 CrewAI 框架,让多智能体自己编写符合我们需求的程序……9 月 19 日,阿里开源了 Qwen2.5 系列大模型全家桶:除常规的语言模型 Qwen2.5 之外,还发布了专门针对编程的Qwen2.5-Coder模型和数学的 Qw…

CSP-S 初赛游记

乱游OI 生涯的最后一个赛季了,尽量记录一下吧。 前两天得知衡水今年没什么人参加,只有本部一个考,也省的到处跑了。 考前一天得知就在机房楼考,这下子成原生土著了,布局比教室都熟。晚上布置了考场。 考前上午体活,打了会羽毛球后回宿舍吃泡面,为啥热水水流这么大,应该…

docker阶段03 docker容器内hosts文件, DNS, 查docker空间占用, 部署自动化运维平台spug, 查看docker run启动参数命令

容器内部的hosts文件 容器会自动将容器的ID加入自已的/etc/hosts文件中,并解析成容器的IP 范例: 修改容器的 hosts文件[root@ubuntu1804 ~]#docker run -it --rm --add-host www.wangxiaochun.com:6.6.6.6 --add-host www.wang.org:8.8.8.8 busybox / # cat /etc/hosts 127.…

视频号直播自动循环发评论-自动回复评论 - 浏览器插件

功能介绍 浏览器插件源码开放,可以随意二次开发,无时间限制,无账号限制,无电脑限制 实现原理,纯浏览器插件实现,监控浏览器界面元素变动,获取直播间或者直播中控后台的评论文本,匹配回复关键词或调用AI接口,再利用js模拟输入和点击等操作 支持以下中控台或直播间地址,…

了解如何在 lt;lines (Modulojs) 中创建 API 支持的 Zelda BOTW 怪物画廊 Web 组件

模数教程回来了!大家好!暑假结束后,我带着 modulo 教程回来了。我正在制作更多教程 - 请继续关注。也就是说,如果您对我的下一个主题有任何特别的想法,请务必在评论中告诉我!我的上一篇教程是关于 api 驱动的 pokmon dance party 组件的超级快速且有趣的“仅 html,无 js…

Cortex-A7 MPCore 架构

Cortex-A7 MPCore 架构 1)Cortex-A7 MPCore 简介 Cortex-A7 MPcore 处理器支持 1~4 核,通常是和 Cortex-A15 组成 big.LITTLE 架构的,Cortex-A15 作为大核负责高性能运算,比如玩游戏啥的, Cortex-A7 负责普通应用,因为 CortexA7 省电。 Cortex-A7 本身性能也不弱,不要…

Zlmedia搭建简记

进入新公司之后,发现他们的视频播放使用的是ZlmediaKit这个工具,自己尝试使用了一下发现很好用,于是在自己机器上搭建了一个服务玩玩。 因为没有在线的摄像头,所以这里采用的是ffmpeg推送mp4文件作为视频流输入,推送到zlmedia服务,再利用zlmedia本身所带的拉流服务,最终…

C 风格字符串函数

▲《C++ Primer》 P109 我们无法保证 c_str 函数返回的数组一直有效,事实上,如果后续的操作改变了 string 的值就可能让之前返回的数组失去效用。 WARNING: 如果执行完 c_str() 函数后程序想一直都能使用其返回的数组,最好将该数组重新拷贝一份。

基于IDF的ESP32S3-LVGL DEMO移植

简介 ESP32-32出色的性价比,较好的性能与内存空间,可以好利用来完成GUI显示库的加载 LVGL LVGL是一款比较流行的致力于MCU与MPU创建漂亮UI的嵌入式图形库,免费且开源。 硬件 硬件采用的是正点原子的ESP32-S3 屏幕使用的是SPI通信方式,配合IO口控制(RST,A0),来实现LCD屏幕…

nginx: 按ip地址限流

一,以固定的速度提供服务 语法: 例子 limit_req_zone $binary_remote_addr zone=test:10m rate=2r/s;server { location / { limit_req zone=test; }} 语法: imit_req_zone 用于设置限流和共享内存区域的参数,格式为: limit_req_zone key zone rate。 key: 定…