Vitepress主题制作学习笔记-1
记录我在搭建这个博客主题遇到的问题以及学到的东西。这里写最基本的配置问题,包括vitepress的基础使用,以及ts配置文件的编写与使用。
Vitepress安装
参考:VitePress
是什么? | VitePress
我是在npm下安装的,其他同理。
安装:
初始化项目:
然后根据提示初始化你的项目,如果需要自定义主题可以选择Default Theme + Customization
或者Custom Theme
如果正在构建一个独立的 VitePress 站点,可以在当前目录
(./
) 中搭建站点。但是,如果在现有项目中与其他源代码一起安装
VitePress,建议将站点搭建在嵌套目录 (例如 ./docs
)
中,以便它与项目的其余部分分开。
如果在当前目录搭建站点,则需要在package.json
文件中修改:
1 2 3 4 5 6 7 8 9
| { ... "scripts": { "docs:dev": "vitepress dev", "docs:build": "vitepress build", "docs:preview": "vitepress preview" }, ... }
|
初始化主题项目
参考:
theme-default
默认主题的结构如下:
1 2 3 4 5 6 7
| ├─components # 放组件的 │ └─icons ├─composables # 放可复用的js/ts逻辑模块 ├─fonts # 字体文件 ├─styles # 放样式表的 │ └─components └─support # 放外部引用文件的
|
我们根据默认主题结构以及async主题的结构创建我们的主题项目(部分):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ├─docs └─packages ├─create-theme # 用于创建、打包主题 │ ├─public │ │ ├─move # 版本信息 │ │ ├─posts # 博客文章 │ │ └─template # 主题模板 │ └─src # nodejs安装脚本 └─vitepress-theme-censored # 主题主文件 ├─assets # 图片等资源 ├─components # 组件 ├─composables # 构造文件,主要是一些数据处理文件 ├─config # 主题配置文件 ├─layouts ├─plugins # 主题插件 ├─styles ├─types # 配置对象、主题配置、插件接口 └─utils # 工具函数等
|
使用create-theme
的原因(个人看法):
以我的主题为例,首先我们先进入vitepress-theme-censored
中配置package.json
,以便在create-theme
中导入。
使用命令
1
| npm init -y # 跳过输入配置信息直接生成文件
|
在生成的package.json
中写入你想要的配置信息,以下是我的配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| { "name": "vitepress-theme-censored", "version": "1.0.0", "repository": "git@github.com:Cainhappyfish/vitepress-theme-censored.git", "description": "", "author": "破酥 C4iN", "main": "index.ts", "type": "module", "types": "./types/index.d.ts",
"exports": { ".": { "default": "./index.ts", "types": "./types/index.d.ts" }, "./config": { "default": "./config/index.js" } }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "vitepress-theme", "blog-theme" ], "license": "ISC" }
|
配置文件package.json
可以参考nodejs官方文档
然后进入create-theme中,安装
用npm list
检查,成功:
1
| +-- vitepress-theme-censored@1.0.0 -> .\packages\vitepress-theme-censored
|
这里不知道为什么config里面只用js不能用ts
项目基本配置
我们需要配置以下文件:
1 2 3 4
| vitepress-theme-censored/index.ts # 该文件中的参数可以在 VitePress 主题和 Markdown 文件中被引用和调用 vitepress-theme-censored/types/index.d.ts # TypeScript 声明文件 vitepress-theme-censored/types/theme.d.ts # 主题接口配置 create-theme/config.mts # 定义和配置站点的各种设置
|
.d.ts
文件中定义 VitePress
的配置对象和主题配置对象的类型,以及如何导出一个定义配置的方法。这些声明可以帮助
TypeScript 理解 VitePress
的配置结构,并在开发过程中提供类型检查和代码补全。
在config/index.js
写入测试配置信息
1 2 3 4 5 6 7 8 9 10 11
| export const defaultConfig = { };
export const defineConfig = (config) => {
return { ...defaultConfig, ...config }; };
|
还有packages/create-theme/public/template/.vitepress/config.mts
1 2 3 4 5 6 7
| import { defineConfig } from 'vitepress-theme-censored/config';
export default defineConfig({ title: "BLOG THEME CENSORED", description: "A theme for Vitepress" })
|
以及packages/vitepress-theme-censored/index.ts
:
1 2 3 4 5 6 7 8
| import Layout from './layouts/Layout.vue';
export default { Layout, enhanceApp({ app, router, siteData }) { } }
|
packages/vitepress-theme-censored/layouts/Layout.vue
:
1 2 3 4 5 6 7 8 9 10 11
| <script setup>
</script>
<template> <h1> Test </h1> </template>
<style scoped>
</style>
|
在packages/create-theme/public/template
运行npm run dev
,成功运行:
运行效果
要在主题中动态传递内容参数,我们需要配置types/index.d.ts
,types/theme.d.ts
文件,并在packages/create-theme/public/template/.vitepress/config.mts
写入我们想要的内容,这里我参考了async
主题的配置:
theme.d.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| declare const __ALGOLIA__: boolean
declare const __VP_LOCAL_SEARCH__: boolean
declare type AnyObject = Record<string, any>
declare namespace CensoredTheme { type OrderByArg = string | Record<string | number, 1 | -1>;
interface PostData {}
interface NavItemWithLink {} interface NavItemWithChildren {}
interface Links {}
interface MenuItem {}
interface Language {} }
declare namespace CensoredTheme {
interface FaviconConfig {}
interface UserConfig {}
type TobBarsConfig = Array<CensoredTheme.NavItemWithLink | CensoredTheme.NavItemWithChildren>;
interface BannerConfig {}
interface SidebarConfig {}
interface FooterConfig {}
interface AboutPageConfig {}
type LinksConfig = Links[];
interface ConverConfig {}
interface PaginationConfig {}
interface BuiltPageConfig {}
interface FixedBtnConfig {}
interface PostPaginationConfig {}
interface RewardConfig {}
interface CreativeCommonsConfig {}
interface NoticeOutdateConfig {}
}
declare module 'vitepress-theme-censored/config' { import { CensoredThemeConfig } from 'vitepress-theme-censored'; import { UserConfig } from 'vitepress';
export const defineConfig: (config: UserConfig<CensoredThemeConfig>) => UserConfig<CensoredThemeConfig>; export const defaultConfig: CensoredThemeConfig; }
declare module '@localSearchIndex' { const data: Record<string, () => Promise<{ default: string }>>; export default data; }
declare type DeepKeys<T> = T extends object ? { [K in keyof T]-?: K extends string ? (T[K] extends object ? `${K}.${DeepKeys<T[K]>}` : `${K}`) : never; }[keyof T] : never;
declare type DiffDateSuffix = { month: string; day: string; hour: string; min: string; just: string; };
|
index.d.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| import { DefaultTheme } from 'vitepress'; export declare interface CensoredThemeConfig {
pageLoading?: boolean;
themeLoading?: boolean;
customMdStyle?: boolean;
globalComponents?: boolean | Array<string>;
author?: string;
search?: { provider: 'local'; options?: DefaultTheme.LocalSearchOptions };
timeZone?: number;
postDir?: string;
page?: CensoredTheme.BuiltPageConfig;
indexGenerator?: Omit<CensoredTheme.PaginationConfig, 'date_fmt'>;
archiveGenerator?: CensoredTheme.PaginationConfig;
postPagination?: CensoredTheme.PostPaginationConfig;
navBars?: CensoredTheme.TobBarsConfig;
user?: CensoredTheme.UserConfig;
favicon?: CensoredTheme.FaviconConfig;
banner?: CensoredTheme.BannerConfig;
sidebar?: CensoredTheme.SidebarConfig;
footer?: CensoredTheme.FooterConfig;
cover?: CensoredTheme.ConverConfig;
rightside?: CensoredTheme.FixedBtnConfig;
about?: CensoredTheme.AboutPageConfig;
links?: CensoredTheme.LinksConfig;
reward?: CensoredTheme.RewardConfig;
outline?: DefaultTheme.Outline; outlineTitle?: string;
languages?: Record<string, CensoredTheme.Language>; }
import Theme, { defineTheme } from '../index';
import './theme.d.ts'; export default Theme; export { defineTheme };
|
配置完成后,在config.mts
写入你的主题信息,然后就可以开始写组件了。以下是项目目前的样子:
sample
config.mts
的一些参数请看Site Config |
VitePress,也可以参考我的配置。
主题部署
比如我是在GitHub
Page上配的,本来的博客因为刷机刷没了,不是在根目录下搭建。我们需要在create-theme
的config.mts
中加入
1
| base: '/vitepress-theme-censored/',
|
由于非根目录部署的存在,我们需要在用到url的地方使用withBase()
将配置的
base
追加到给定的 URL 路径。另请参阅 Base
URL。
这是我的workflow内容,样例文件可以在Vitepress的官方文档找到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| name: Deploy VitePress site to Pages
on: # 在针对 `main` 分支的推送上运行。如果你 # 使用 `master` 分支作为默认分支,请将其更改为 `master` push: branches: [main]
# 允许你从 Actions 选项卡手动运行此工作流程 workflow_dispatch:
# 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages permissions: contents: read pages: write id-token: write
# 只允许同时进行一次部署,跳过正在运行和最新队列之间的运行队列 # 但是,不要取消正在进行的运行,因为我们希望允许这些生产部署完成 concurrency: group: pages cancel-in-progress: false
jobs: # 构建工作 build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 # 如果未启用 lastUpdated,则不需要 # - uses: pnpm/action-setup@v3 # 如果使用 pnpm,请取消注释 # - uses: oven-sh/setup-bun@v1 # 如果使用 Bun,请取消注释 - name: Setup Node uses: actions/setup-node@v4 with: node-version: 20 cache: npm # 或 pnpm / yarn - name: Setup Pages uses: actions/configure-pages@v4 - name: Install dependencies run: npm ci # 或 pnpm install / yarn install / bun install - name: Build with VitePress run: | cd packages/create-theme/public/template npm run build # 或 pnpm docs:build / yarn docs:build / bun run docs:build - name: Check file run: ls - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: packages/create-theme/public/template/.vitepress/dist
# 部署工作 deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} needs: build runs-on: ubuntu-latest name: Deploy steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4
|
如果你使用vercel,建议在本地进行部署,连接GitHub部署容易出现Permission Denied
类似的错误。下面是我的配置:
vercel部署
注意,相比之前的这里我们的网页是部署在根目录下的,需要把config.mts
中的base
属性改为'/'
,否则你的网页会爆炸的(指找不到静态文件),如果你之前就是部署在根目录请忽略这段话。
byd我忘了这茬debug搞了一晚上,被自己气晕