使用vitepress搭建博客
前置准备
安装vitepress
安装vitepress依赖
shell
npm add -D vitepress
安装向导
VitePress 附带一个命令行设置向导,可以帮助你构建一个基本项目。安装后,通过运行以下命令启动向导:
shell
npx vitepress init
将需要回答几个简单的问题:
cmd
T Welcome to VitePress!
|
o Where should VitePress initialize the config?
| ./docs
|
o Site title:
| My Awesome Project
|
o Site description:
| A VitePress Site
|
o Theme:
| Default Theme
|
o Use TypeScript for config and theme files?
| Yes
|
o Add VitePress npm scripts to package.json?
| Yes
|
— Done! Now run npm run docs:dev and start writing.
一路选择默认配置
文件结构
cmd
.
├─ docs
│ ├─ .vitepress
│ │ └─ config.mts
│ ├─ api-examples.md
│ ├─ markdown-examples.md
│ └─ index.md
└─ package.json
docs 目录作为 VitePress 站点的项目根目录。.vitepress 目录是 VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的位置。
配置文件
配置文件 (.vitepress/config.mts) 让你能够自定义 VitePress 站点的各个方面,我的配置如下,可以参考一下:
typescript
// .vitepress/config.mts
import { defineConfig } from 'vitepress'
import sidebarConfig from './plugins/generate_sidebar.js'
export default defineConfig({
title: "代码的诗",
description: "分享编程知识",
head: [
// 插入百度统计的脚本
[
'script',
{},
`
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?xxx";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
`,
],
],
themeConfig: {
nav: [
{ text: '首页', link: '/' },
{
text: '计算机基础',
items: [
{ text: '数据结构与算法', link: '/articles/cs/algorithms/introduction' }
]
},
{
text: '编程之美',
items: [
{ text: '设计模式', link: '/articles/code/design-pattern/introduction' },
]
},
{
text: '博客',
items: [
{ text: 'php', link: '/articles/blog/php/introduction' },
{ text: 'frontend', link: '/articles/blog/frontend/introduction' }
]
}
],
sidebar: sidebarConfig('articles'),
socialLinks: [
{ icon: 'github', link: 'https://github.com/shenlink' }
],
footer: {
message: '<a href="https://beian.miit.gov.cn/" style="text-decoration: none" target="_blank">粤ICP备2024331772号</a>',
copyright: 'Copyright © 2024-present <a href="https://github.com/shenlink">shenlink</a>'
}
}
})
自动生成侧边栏的插件代码如下:
typeScript
// SidebarItem.ts
// 定义 SidebarItem 的类型
export interface SidebarItem {
text: string;
link?: string;
collapsed?: boolean;
items?: SidebarItem[];
}
typeScript
// generate_sidebar.ts
import fs from 'fs';
import path from 'path';
import { SidebarItem } from './SidebarItem'
// 递归扫描目录并生成 sidebar
function generateSidebar(articlesDir: string): { [key: string]: SidebarItem[] } {
const sidebar: { [key: string]: SidebarItem[] } = {};
// 构建 articlesDir 的绝对路径
const baseDir = path.resolve(__dirname, '../../', articlesDir);
// 需要跳过的顶级目录列表
const skipDirs = fs.readdirSync(baseDir);
// 扫描目录
function scanDirectory(dir: string): SidebarItem[] {
const items: SidebarItem[] = [];
const files = fs.readdirSync(dir);
// 先收集所有的 .md 文件
const mdFiles: SidebarItem[] = [];
files.forEach((file) => {
const filePath = path.join(dir, file);
// 判断是否是 skipDirs 目录下的 introduction.md 文件,跳过
const dirName = path.basename(dir);
if (skipDirs.includes(dirName) && file === 'introduction.md') return;
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
// 如果是文件夹,递归扫描该文件夹
items.push({
text: file,
collapsed: true,
// 递归进入子目录
items: scanDirectory(filePath),
});
} else if (file.endsWith('.md')) {
// 如果是Markdown文件,添加到列表
mdFiles.push({
text: file.replace('.md', ''),
link: `/${articlesDir}/${dir.replace(baseDir, '').replace(/\\/g, '/').replace(/^\//, '').replace(/\/$/, '')}/${file.replace('.md', '')}`,
});
}
});
// 将 introduction.md 文件放在最前面
const introIndex = mdFiles.findIndex(file => file.text.toLowerCase() === 'introduction');
if (introIndex !== -1) {
// 找到并移除 introduction.md
const introFile = mdFiles.splice(introIndex, 1)[0];
// 将 introduction.md 放在最前面
mdFiles.unshift(introFile);
}
// 将所有文件添加到 items 数组
items.push(...mdFiles);
return items;
}
const categories = fs.readdirSync(baseDir);
categories.forEach((category) => {
const categoryPath = path.join(baseDir, category);
const stat = fs.statSync(categoryPath);
if (stat.isDirectory()) {
// 为每个articlesDir目录的目录生成 sidebar 配置
sidebar[`/${articlesDir}/${category}/`] = scanDirectory(categoryPath);
// 递归处理子目录
const subCategoryPaths = fs.readdirSync(categoryPath);
subCategoryPaths.forEach((subCategory) => {
const subCategoryPath = path.join(categoryPath, subCategory);
const subStat = fs.statSync(subCategoryPath);
if (subStat.isDirectory()) {
sidebar[`/${articlesDir}/${category}/${subCategory}/`] = scanDirectory(subCategoryPath);
}
});
}
});
return sidebar;
}
export default generateSidebar;
可以根据需要修改
部署到nginx
运行命令,生成最终的发布版文件
shell
npm run docs:build
编译后的发布版文件在./docs/.vitepress/dist/目录下面
nginx配置文件参考如下:
nginx
server
{
listen 80;
server_name hxqzzxk.com;
index index.php index.html index.htm default.php default.htm default.html;
root /www/wwwroot/hxqzzxk/docs/.vitepress/dist;
#ERROR-PAGE-START 错误页配置,可以注释、删除或修改
error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END
access_log /www/wwwlogs/hxqzzxk.com.log;
error_log /www/wwwlogs/hxqzzxk.com.error.log;
}