Bootstrap

Vitepress 相关问题优化

Vitepress 相关问题优化

非根目录部署

下列配置在./vitepress.config.js中

配置 base

默认情况下,我们假设站点将部署在域名 (/) 的根路径上。如果站点在子路径中提供服务,例如 https://mywebsite.com/blog/,则需要在 VitePress 配置中将 base 选项设置为 ‘/blog/’。

例:如果你使用的是 Github(或 GitLab)页面并部署到 user.github.io/repo/,请将 base 设置为 /repo/。

取消生成简洁的 URL

注意:

  1. 非根目录时, 需要将cleanUrls 设置成 false, 因为默认情况下,VitePress 会生成简洁的 URL,例如 /vite/bar.html 会被重定向到 /vite/bar。但是,当您在该页面上执行原地刷新时,浏览器会将相对路径与当前 URL 组合,导致它尝试加载 /vite/index.md 这样的路径。

  2. 根目录部署时,cleanUrls 推荐设置成 true, 这样网络路径可以省略.html, 显得更专业。

nginx配置如下

location /vite {
			
    #开启gzip
    gzip  on;  
    #低于1kb的资源不压缩 
    gzip_min_length 1k;
    #压缩级别1-9,越大压缩率越高,同时消耗cpu资源也越多,建议设置在5左右。 
    gzip_comp_level 5; 
    #需要压缩哪些响应类型的资源,多个空格隔开。不建议压缩图片.
    gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;  
    #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
    gzip_disable "MSIE [1-6]\.";  
    #是否添加“Vary: Accept-Encoding”响应头
    gzip_vary on;

        alias   /data/web/vite/;
    try_files $uri $uri/ /vite/index.html;
}

开启GZIP压缩

修改package.json

"scripts": {
    "dev": "cross-env NODE_ENV=development vitepress dev docs --port=8732",
    "build": "npm run daily-notes && vitepress build docs",
    "compress": "node ./docs/.vitepress/compress.js", 添加这行
    "postbuild": "npm run compress", 添加这行
    "build:docs": "vitepress build docs",
    "daily-notes": "node ./scripts/daily-notes.js",
    "update:friend": "node ./scripts/update-friend.js",
    "preview": "vitepress preview docs --port 8730",
    "lint": "prettier --write .",
    "prepare": "husky install"
},

对应位置创建compress.js

import { promises as fs } from "fs";
import { gzip } from "zlib";
import { promisify } from "util";
import fg from "fast-glob";
const gzipAsync = promisify(gzip);

async function compressFiles() {
  try {
    const files = await fg(["./dist/**/*.{html,jpg,jpeg,png}"], { onlyFiles: true });
    for (const file of files) {
      const content = await fs.readFile(file);
      const originalSize = content.length;

      // Gzip 压缩
      const gzipped = await gzipAsync(content);
      const gzippedSize = gzipped.length;

      if (gzippedSize < originalSize * 0.95) { // 如果压缩效果超过 5%
        await fs.writeFile(`${file}.gz`, gzipped);
        // console.log(`${file} 已保存为 .gz`);
      } else {
        // console.log(`${file} 的 Gzip 压缩效果不足 5%,跳过。`);
      }
    }
    console.log("Compression complete.");
  } catch (error) {
    console.error("Error during compression:", error);
  }
}

compressFiles();

即在构建完成后执行压缩操作。

nginx配置同上。

添加字数及阅读时长

自定义布局容器

<script setup>
import DefaultTheme from 'vitepress/theme'
const { Layout } = DefaultTheme
....
</script>

<template>
  <Layout v-bind="$attrs">

    <!-- 这里指的是文章前, 同时可以在文章内设置readingTime=false来关闭 -->
    <template #doc-before v-if="frontmatter.readingTime !== false">
      <!-- 计算字数和阅读时间 -->
      <ReadingTime />
    </template>
    
    <!-- 其他可扩展的插槽 -->
    ...
  </Layout>
</template>

计算字数和阅读时间

<script setup>
import { ref, watch, onMounted, nextTick } from 'vue'
import { useData } from 'vitepress'

const { page } = useData()

// 统计逻辑
const stats = ref({ words: 0, minutes: 0 })

const calculateStats = () => {
  // 优先尝试从页面数据中获取内容(如果 theme 或 page 提供了内容字段)
  let content = page.value.content
  if (!content) {
    // 如果没有则通过 DOM 查询获取
    content = document.querySelector('.vp-doc')?.textContent || ''
  }
  // 去除所有空白字符后统计字符数(中文场景下更适合统计“字”)
  const wordCount = content.replace(/\s+/g, '').length
  const readingTime = Math.ceil(wordCount / 350)
  
  stats.value = { 
    words: wordCount,
    minutes: readingTime
  }
}

// 当路由变化时重新计算阅读统计
watch(() => page.value.relativePath, async () => {
  await nextTick()  // 等待 DOM 更新完成
  calculateStats()
})

// 初次挂载后计算一次
onMounted(async () => {
  await nextTick()
  calculateStats()
})
</script>

<template>
  <div class="reading-stats" v-if="stats.words > 10">
    <span class="reading-stats-text">
      全文共 {{ stats.words }}, 预计阅读: {{ stats.minutes }} 分钟
    </span>
  </div>
</template>

<style scoped>
.reading-stats {
  font-size: 0.8em;
  text-align: center;
  margin: 0px 0 25px;
}

.reading-stats-text {
  color: rgb(145, 89, 48);
  background-color: rgba(234, 179, 8, 0.14);
  padding: 5px 16px;
  border-radius: 5px;
}
</style>

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;