VitePress踩坑记录
ERR_INVALID_FILE_URL_HOST
DANGER
执行打包命令时,出现此错误 TypeError [ERR_INVALID_FILE_URL_HOST]: File URL host must be "localhost" or empty on darwin
形成原因:全局替换时粗心大意造成img src属性多了个'/'
解决
TIP
刚开始我只能猜到某个文件路径有问题 ,又不知道那个文件有问题,最后用上了 排除法 逐个移除文章文件夹最终才定位到出问题的文档。 虽然问题解决的的过程有点费劲,不得不说当问题搞得人想撞墙的时候,无疑也是一个不错的思路和方法!!!
删除多余的'/'就好了,自己解决自己的 issues !!!
实现自动生成文章左侧侧边栏
痛点及需求
WARNING
每次添加文章过程:对应的目录下添加.md文, 修改themeConfig的sidebar属性
,给对象加上新增的文章映射
添加的文章少还好,多了的话就显得很麻烦不够优雅,所有想写个脚本按照目录结构自动生产对应的映射关系。
想法及实现
在package.json添加脚本执行命令
在博客根目录新建scripts
目录并创建文件getSidebar.ts
,添加如下代码
js
/** ****** 读取 zerdocs/docs/ 下的所有文件夹,自动生成侧边栏sidebar.ts文件 */
const fs = require('node:fs')
const path = require('node:path')
const sidebarObj = {}
// 生成一级分组
const topDirArr = fs.readdirSync(path.resolve(__dirname, '../docs')).filter(item => isArticleDir(item))
topDirArr.forEach((item) => {
if (!sidebarObj[`/${item}/`])
sidebarObj[`/${item}/`] = []
})
const sidebars = deepGetFile(path.resolve(__dirname, '../docs')) // 读取 docs 目录下的所有文件夹
const sidebarlist = deepGenerateSidebar(sidebars)
// 写入到docs/.vitepress/sidebar/index.ts
// 把数组里面的每个对象合并到一个对象里面
const sidebar = sidebarlist.reduce((pre, cur) => Object.assign(pre, cur), {})
Object.entries(sidebar).forEach(([key, items]) => {
const keyArr = splitPath(key)
const text = keyArr[keyArr.length - 1]
if (sidebarObj[`/${keyArr[0]}/`]) {
sidebarObj[`/${keyArr[0]}/`].push({
text,
collapsible: true,
collapsed: false,
items,
})
}
else {
sidebarObj[`/${keyArr[0]}/`] = [{
text,
collapsible: true,
collapsed: false,
items,
}]
}
})
const sidebarStr = JSON.stringify(sidebarObj, null, 2)
// 把sidebarStr写入到docs/.vitepress/sidebar/index.ts
const sidebarPath = path.resolve(__dirname, '../docs/.vitepress/sidebar/index.ts')
// 没有则创建
if (!fs.existsSync(sidebarPath))
fs.mkdirSync(path.resolve(__dirname, '../docs/.vitepress/sidebar'))
fs.writeFileSync(sidebarPath, `export default ${sidebarStr}`)
// 判断是否是文件夹
function isArticleDir(dir) {
const exclude = ['public', 'index.md', 'vite.config.ts'] // 排除的文件夹
return !exclude.includes(dir) && !dir.startsWith('.')
}
function splitPath(path) {
return path.split('/').filter(item => item !== '')
}
function deepGetFile(dir) {
let backList = []
const list = fs.readdirSync(dir).filter(item => isArticleDir(item))
for (const index in list) {
let item = path.resolve(dir, list[index])
if (fs.statSync(item).isDirectory()) {
backList = backList.concat(deepGetFile(item))
}
else {
// 输出相对路径
item = item.replace(path.resolve(__dirname, '../docs'), '').replace(/\\/g, '/')
backList.push(item)
}
}
return backList
}
// 生成侧边栏
function deepGenerateSidebar(arr) {
// 递归按照最后一级目录生成侧边栏
const sidebar = {}
sidebars.forEach((item) => {
const [dir] = splitPath(item)
if (!sidebar[dir])
sidebar[dir] = []
sidebar[dir].push(item)
})
const sidebarList = []
// 按最后一级目录分组
for (const key in sidebar) {
let pathPice = sidebar[key].map(item => splitPath(item))
// 如果pathPice[pathPice.length-1]相同,则合并
pathPice = pathPice.reduce((pre, cur) => {
const dirStr = cur.slice(0, -1).join('/') // /problem/vueproject/
const text = cur[cur.length - 1].replace(/\.md$/, '')
const link = `/${cur.join('/').replace(/\.md$/, '')}`
pre[dirStr] = pre[dirStr] ? [...pre[dirStr], { text, link }] : [{ text, link }]
return pre
}, {})
sidebarList.push(pathPice)
}
return sidebarList
}
VitePress添加本地搜索功能
WARNING
折腾了三遍Algolia都没能添加上搜索功能,最后在找到了这个issus里大佬提供的解决方案,成功添加上了本地搜索功能。
安装插件
zsh
npm i vitepress-plugin-search markdown-it flexsearch -D
添加和配置插件
坑点 1.README 没写在哪个目录下存放vite.config.ts
,依据经验放在根目录下不管用,放在.vitepress
也不生效,最后挨个试才发现需要放在docs
2.示例没有引入flexSearchIndexOptions
,需要手动从flexsearch
中引入
3.引入后发现之前搜索框样式没了,需要在.vitepress/theme/styles/index.css
下重新覆盖样式
ts
// vite.config.ts
import { SearchPlugin } from 'vitepress-plugin-search'
import { defineConfig } from 'vite'
import flexSearchIndexOptions from 'flexsearch'
// default options
const options = {
...flexSearchIndexOptions,
previewLength: 100, // 搜索结果预览长度
buttonLabel: '搜索',
placeholder: '情输入关键词',
}
export default defineConfig({
plugins: [SearchPlugin(options)],
})
样式覆盖
css
.DocSearch-Button {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
padding: 0;
width: 32px;
height: 32px;
border-radius: 4px;
background: transparent;
transition: border-color 0.25s;
}
@media (min-width: 768px) {
.DocSearch-Button {
justify-content: flex-start;
border: 1px solid transparent;
border-radius: 8px;
padding: 0 10px 0 12px;
width: 100%;
height: 40px;
background-color: var(--vp-c-bg-alt);
}
}
@media (max-width: 768px) {
.DocSearch-Button-Keys {
display: none;
}
.VPNavBarHamburger {
height: 32px !important;
width: 32px !important;
border-radius: 4px;
}
}