===============
LIBRARY RULES
===============
From library maintainers:
- BIThesis 文档部署于 bithesis.bitnp.net,主要内容位于该域名下的 /guide/ 和 /faq/
- 这是一个文档网站,用户不关心文档是怎么构建的,只关心文档里写了什么
- 如果 /faq/ 中有解答,可引导用户直接访问网页链接
- 如果用户用中文提问,尽量用中文回答
# BIThesis Wiki Documentation
BIThesis Wiki is a comprehensive documentation website for BIThesis, an unofficial LaTeX template collection for Beijing Institute of Technology. The project serves undergraduate and graduate students by providing thesis templates, formatting guides, and troubleshooting resources. Built with VitePress, this static documentation site offers searchable guides, FAQ sections, and video tutorials to help students write academic papers using LaTeX instead of Word. The project has received official recognition and support from BIT's Graduate School, Academic Affairs Office, and School of Computer Science.
The documentation covers the complete workflow from installing LaTeX distributions (TeX Live/MacTeX) to configuring editors (VS Code, TeXstudio) and compiling documents. It includes detailed solutions to common LaTeX problems, bibliography management with BibTeX, and conversion utilities. The site features Chinese word segmentation for search, custom link rendering for package documentation references, and automatic generation of FAQ navigation. The project emphasizes ease of use while maintaining professional typesetting standards required by university guidelines. Advanced features include Naive UI integration with SSR support, automated sitemap page generation for AI knowledge bases, intelligent prev/next navigation links across FAQ pages, interactive configuration generators for template options, contributor showcase components, and release notes management system.
## Development Setup
```bash
# Clone repository
git clone https://github.com/BITNP/BIThesis-wiki
cd BIThesis-wiki
# Install dependencies using pnpm
pnpm install
# Start development server with hot reload
pnpm dev
# Build static site for production
pnpm build
# Preview production build locally
pnpm preview
```
## Project Structure
```bash
# Main documentation content
wiki/
├── .vitepress/
│ ├── config.mts # VitePress configuration
│ ├── util.ts # Title extraction utilities
│ ├── sitemap_page.ts # Sitemap HTML generator
│ ├── theme/
│ │ ├── index.ts # Theme setup
│ │ ├── Layout.vue # Custom layout with tag display
│ │ ├── FAQList.vue # FAQ list with tag filtering
│ │ ├── BITSetupExample.vue # Interactive template config generator
│ │ ├── PubAuthorAnnotation.vue # Author annotation helper
│ │ ├── Contribution.vue # Contributors grid display
│ │ ├── faq.data.ts # FAQ data loader (runtime)
│ │ ├── faq_data.ts # FAQ data loader (build-time)
│ │ ├── contributors.data.ts # Contributors loader (runtime)
│ │ ├── contributors_data.ts # Contributors data (shared)
│ │ ├── news.data.ts # News/release notes loader
│ │ ├── link_render.ts # Custom markdown link renderer
│ │ ├── util.ts # Tag normalization utilities
│ │ └── custom.css # Custom styles
│ └── naive-ui-adapter/ # Naive UI SSR integration
│ ├── config.ts # Vite SSR config
│ └── theme.ts # Theme adapter with dark mode sync
├── guide/ # User guides
├── faq/ # FAQ articles
├── news/ # Version release notes
└── video/ # Video tutorial pages
# Configuration files
package.json # Project dependencies and scripts
.prettierrc # Code formatting rules
```
## VitePress Configuration
```typescript
// wiki/.vitepress/config.mts
import assert from 'node:assert'
import * as footnote from 'markdown-it-footnote'
import { defineConfig, type DefaultTheme } from 'vitepress'
import LinkRender from './theme/link_render'
import { generate_sitemap_page } from './sitemap_page'
import { vite_ssr, postRender, transformHtml } from './naive-ui-adapter/config'
import { generate_index_tex, generate_prev_next_links } from './theme/faq_data'
export default defineConfig({
lang: 'zh-CN',
title: 'BIThesis',
description: '北京理工大学非官方 LaTeX 模板集合',
// Enable last updated timestamps
lastUpdated: true,
// Sitemap generation
sitemap: {
hostname: 'https://bithesis.bitnp.net',
},
// Head tags for favicons and meta tags
head: [
['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png' }],
['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png' }],
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }],
['link', { rel: 'manifest', href: '/site.webmanifest' }],
['meta', { property: 'og:image', itemprop: 'image primaryImageOfPage', content: '/bithesis.png' }],
],
// Theme configuration with navigation and sidebar
themeConfig: {
logo: '/apple-touch-icon.png',
externalLinkIcon: true,
// Edit link configuration
editLink: {
pattern: 'https://github.com/BITNP/BIThesis-wiki/edit/main/wiki/:path',
text: '帮助我们改善此页面!',
},
nav: [
{ text: '文档指南', link: '/guide/preface' },
{ text: '疑难杂症', link: '/faq/' },
{ text: 'Overleaf', link: '/guide/preface#q-bithesis-都包含哪些模板' },
{ text: '模板下载', link: '/guide/downloading-using-templates' },
{
text: '加入讨论',
items: [
{ text: 'QQ 群:737548118', link: 'https://jq.qq.com/?_wv=1027&k=KYDrmS5z' },
{ text: 'Contributing', link: 'https://github.com/BITNP/BIThesis/blob/master/contributing.md' }
]
},
{ text: 'GitHub', link: 'https://github.com/BITNP/BIThesis' }
],
// Sidebar organized by section
sidebar: {
'/guide': [
{
text: '前言',
items: [{ text: '写在开头', link: '/guide/preface' }]
},
{
text: '食用方法',
items: [
{ text: '简介', link: '/guide/intro' },
{ text: '如何开始', link: '/guide/getting-started' },
{ text: '下载模板', link: '/guide/downloading-using-templates' },
{ text: '编辑器配置与模板编译', link: '/guide/configure-and-compile' }
]
},
{
text: '常见问题',
items: [
{ text: '询问人工智能', link: '/guide/ask-computer' },
{ text: '将 LaTeX 转换为 Word', link: '/guide/converting-to-word' },
{ text: 'LaTeX 学习与使用资源', link: '/guide/resources' },
{ text: '常用命令', link: '/guide/commands' },
{ text: '疑难杂症', link: '/faq/' }
]
},
{
text: '致谢',
items: [{ text: 'Thanks', link: '/guide/acknowledgements' }]
}
],
'/news': [
{
text: '更新说明',
items: [
{ link: '/news/', text: '目录' },
{ link: '/news/2026', text: '2025年11月至 +∞' },
{ link: '/news/2025', text: '2024年11月至2025年10月' },
{ link: '/news/2024', text: '2023年11月至2024年10月' },
{ link: '/news/2023', text: '2022年11月至2023年10月' },
{ link: '/news/2022', text: '2021年11月至2022年10月' },
{ link: '/news/2021', text: '2020年11月至2021年10月' },
{ link: '/news/2020', text: '−∞ 至2020年10月' }
]
}
],
'/video': [
{
text: '视频介绍',
items: [
{ text: '前言', link: '/video/intro' },
{ text: '第一节 综述', link: '/video/episode-1' },
{ text: '第二节 LaTeX 的下载和安装', link: '/video/episode-2' },
{ text: '第三节 LaTeX 基本介绍', link: '/video/episode-3' },
{ text: '第四节 模板的下载和使用', link: '/video/episode-4' },
{ text: '第五节 格式转化', link: '/video/episode-5' },
{ text: '第六节 项目介绍和疑难解惑', link: '/video/episode-6' }
]
}
]
},
// Outline configuration
outline: {
level: [2, 4],
label: '本页目录',
},
// Footer configuration
footer: {
message: 'Released under the LaTeX Project Public License.',
copyright: 'Copyright © 2020–2025 BITNP',
},
// Chinese word segmentation for search
search: {
provider: 'local',
options: {
miniSearch: {
options: {
processTerm: (term) => {
const segmenter = new Intl.Segmenter('zh', { granularity: 'word' })
if (!segmenter) return term
return Array.from(segmenter.segment(term)).map(({ segment }) => segment)
}
}
}
}
}
},
// Markdown extensions
markdown: {
config: (md) => {
md.use(footnote.default ?? footnote).use(LinkRender)
},
anchor: {
getTokensText: (tokens) =>
tokens
// Add `html_inline` from `LinkRender`
.filter((t) => ['text', 'code_inline', 'html_inline'].includes(t.type))
.map((t) => t.meta?.slug ?? t.content)
.join('')
}
},
// Page redirection via HTTP-REFRESH meta tag
transformHead({ pageData: { frontmatter } }) {
if (frontmatter['redirect-to']) {
const to = frontmatter['redirect-to']
return [
['link', { rel: 'canonical', href: to }],
['meta', { 'http-equiv': 'refresh', content: `0; url=${to}` }],
['meta', { name: 'robots', content: 'noindex' }],
['script', {}, `window.location = "${to}"`]
]
}
},
// Transform page data to add prev/next navigation
transformPageData(page, context) {
// Add pre/next links to `/faq/*`
if (page.relativePath === 'faq/index.md') {
const sidebar = context.siteConfig.userConfig.themeConfig.sidebar['/guide'] as DefaultTheme.SidebarItem[]
assert.ok(sidebar)
const section = sidebar.at(-2)
assert.strictEqual(section?.text, '常见问题')
assert.strictEqual(section.items?.at(-1)?.link, '/faq/')
page.frontmatter.prev ??= section.items.at(-2)
page.frontmatter.next ??= sidebar.at(-1)?.items?.at(0)
} else if (page.relativePath.startsWith('faq/')) {
const { prev, next } = generate_prev_next_links(page)
page.frontmatter.prev ??= prev
page.frontmatter.next ??= next
}
// Set outline level for `/news/*`
if (page.relativePath.startsWith('news/')) {
page.frontmatter.outline = { level: 2 }
}
},
// Build hooks for generating index and sitemap
async buildEnd(site) {
await Promise.all([generate_index_tex(site), generate_sitemap_page(site)])
},
// Naive UI adapter
vite: { ssr: vite_ssr },
postRender,
transformHtml
})
```
## Sitemap Page Generation
```typescript
// wiki/.vitepress/sitemap_page.ts
import { readFile, writeFile } from 'node:fs/promises'
import path from 'node:path'
import type { SiteConfig } from 'vitepress'
import { getTitleFromSrc } from './util'
/**
* Generate sitemap page (not sitemap.xml) for AI knowledge base import.
* Creates an HTML file with all site links sorted by category.
*/
export async function generate_sitemap_page(site: SiteConfig) {
const pages = site.pages.map((page) => ({
file: path.join(site.srcDir, page),
url: (site.rewrites.map[page] ?? page)
.replace(/(^|\/)index\.md$/, '$1')
.replace(/\.md$/, site.cleanUrls ? '' : '.html')
}))
const links = await Promise.all(
pages.map(async ({ file, url }) => {
const src = await readFile(file, 'utf-8')
const title = getTitleFromSrc(src) ?? (url || '首页')
return { url, title }
})
)
// Sort by category: homepage first, then guide/, then others alphabetically
links.sort(
(a, b) =>
by_category(a, b, (x) => x.url === '') ??
by_category(a, b, (x) => x.url.startsWith('guide/')) ??
a.url.localeCompare(b.url)
)
await writeFile(
path.join(site.outDir, 'sitemap.html'),
[
'
',
...links.map(({ url, title }) => `- ${title}
`),
'
'
].join('\n')
)
}
function by_category- (a: Item, b: Item, is_superior: (x: Item) => boolean): number | undefined {
const a_superior = is_superior(a)
const b_superior = is_superior(b)
if (a_superior !== b_superior) {
return a_superior ? -1 : +1
}
}
```
## Title Extraction Utility
```typescript
// wiki/.vitepress/util.ts
import matter from 'gray-matter'
/**
* Extract title from markdown source by finding the first H1 heading.
* Removes frontmatter, hyperlinks, and markdown formatting from the title.
*/
export function getTitleFromSrc(src: string): string | undefined {
const lines = matter(src).content.split('\n')
for (const line of lines) {
if (/^# /.test(line)) {
let title = line.replace(/^# /, '')
// Remove hyperlink if exists
if (/\[(.*)]\(.*\)/.test(title)) {
const execValue = /(.*)?\[(.*)]\((.*)\)(.*)?/.exec(title) || ''
title = execValue.length > 0 ? `${execValue[1] || ''}${execValue[2] || ''}${execValue[4] || ''}` : ''
}
// Remove markdown formatting: bold, italic, strikethrough, code
title = title
.replace(/\*{1,2}([^*]+?)\*{1,2}/g, '$1')
.replace(/_{1,2}([^_]+?)_{1,2}/g, '$1')
.replace(/~{1,2}([^~]+?)~{1,2}/g, '$1')
.replace(/`{1,3}([^`]+?)`{1,3}/g, '"$1"')
return title
}
}
}
```
## Custom Link Rendering for Package References
```typescript
// wiki/.vitepress/theme/link_render.ts
// Converts [[pkg:package-name]] and [[texdoc:doc-name]] to external links
import type MarkdownIt from 'markdown-it'
export default function LinkRender(md: MarkdownIt) {
md.inline.ruler.before('link', 'custom_link', (state, silent) => {
// Match [[pkg:package]] or [[texdoc:document|display text]]
const match = state.src.slice(state.pos).match(/^\[\[(pkg|texdoc):([^\]|]+)(?:\|([^\]]+))?\]\]/)
if (!match) return false
const [fullMatch, type, target, displayText] = match
const text = displayText || target
if (!silent) {
const token = state.push('html_inline', '', 0)
if (type === 'pkg') {
token.content = `${text}`
} else if (type === 'texdoc') {
token.content = `${text}`
}
}
state.pos += fullMatch.length
return true
})
}
```
## FAQ Data Loading and Navigation
```typescript
// wiki/.vitepress/theme/faq_data.ts (build-time)
import { writeFileSync } from 'node:fs'
import path from 'node:path'
import { createContentLoader, type PageData, type SiteConfig } from 'vitepress'
import { normalizeTag, tagURL } from './util'
import { getTitleFromSrc } from '../util'
export interface FAQItem {
title: string
url: string
tag: string[]
}
/**
* Factory to create a content loader for FAQ pages.
* The loader extracts titles and tags from frontmatter and sorts by URL.
*/
export const factory = () =>
createContentLoader('faq/*.md', {
includeSrc: true,
transform(raw): FAQItem[] {
return raw
.filter(({ url }) => url !== '/faq/') // Ignore `index.md`
.map(({ url, frontmatter, src }) => {
const title = getTitleFromSrc(src as string)
if (!title) {
console.warn(`未能从 ${url} 中提取 title,将用 URL 替代`)
}
const tag = normalizeTag(frontmatter.tag)
if (tag.length === 0) {
console.warn(`${url}(${title})应当在 frontmatter 中标注至少一个 tag,但目前缺失`)
}
return { title: title ?? url, url, tag }
})
.sort((a, b) => a.url.localeCompare(b.url))
}
})
/**
* Generate `faq/index.tex` for the development of `bithesis.pdf`.
* Creates a LaTeX itemize list with hyperlinks to all FAQ pages.
*/
export async function generate_index_tex(site: SiteConfig) {
const pages = await factory().load()
const index_tex = [
'\\begin{itemize}',
...pages.map(({ title, url }) => ' \\item ' + as_latex_href(title, `https://bithesis.bitnp.net${url}`)),
'\\end{itemize}'
].join('\n')
writeFileSync(path.join(site.outDir, 'faq/index.tex'), index_tex)
}
/**
* Format as a LaTeX \href with proper escaping of special characters.
*/
function as_latex_href(title: string, url: string): string {
const escaped = str_esc(title, [
['\\\\', '\\textbackslash{}'],
['(?', '\\textgreater{}'],
['\\^', '\\textasciicircum{}']
])
return `\\href{${url}}{${escaped}}`
}
function str_esc(s: string, m: [string, string][]): string {
return m.reduce((acc, [re, repl]) => {
return acc.replace(new RegExp(`${re}`, 'g'), repl)
}, s)
}
/**
* Generate prev/next navigation links for FAQ pages.
* Prev always points to /faq/, next points to tag-filtered list if tag exists.
*/
export function generate_prev_next_links(page: PageData): {
prev: { text: string; link: string }
next?: { text: string; link: string }
} {
const prev = { text: '疑难解答', link: '/faq/' }
const tag = normalizeTag(page.frontmatter.tag).at(0)
const next = tag ? { text: `${tag} 问题目录`, link: tagURL(tag) } : undefined
return { prev, next }
}
```
```typescript
// wiki/.vitepress/theme/faq.data.ts (runtime)
import { factory, type FAQItem } from './faq_data'
declare const data: FAQItem[]
export { data }
export default factory()
```
## FAQ List Component with Tag Filtering
```vue
{{ currentTag }}
```
## Interactive BITSetup Configuration Generator
```vue
🔗 分享链接
请编辑main.tex,用\BITSetup设置{{ key }}选项为{{ value }}:
```
## Publication Author Annotation Helper
```vue
中文
English
效果
- 普通模式下:
{{ normal_out }}作者姓名
- 盲审模式下:
{{ blind_out }}
```
## Contributors Data and Display Component
```typescript
// wiki/.vitepress/theme/contributors_data.ts
export interface Contributor {
/** Name, must be unique */
name: string
/** URL to the avatar */
avatar: string
/** URL of the homepage, e.g. GitHub user page. */
homepage?: string
/**
* An alternative text description of the avatar
* Default: `name`
*/
avatar_alt?: string
}
export const contributors: Contributor[] = [
{
name: '子衿',
homepage: 'https://github.com/ZIJIN-Evan',
avatar: 'https://i.loli.net/2020/04/22/1REvcJuP4iLYfQp.jpg',
},
{
name: 'Spencer Woo',
homepage: 'https://github.com/BITNP',
avatar: 'https://i.loli.net/2020/03/10/KqToYeg1buLGwsh.png',
},
// ... more contributors
]
/** Get a `Contributor` by his/her `name` */
export function get_contributor(name: string): Contributor {
const one = contributors.find((c) => c.name === name)
if (one === undefined) {
throw new Error(`Failed to find a contributor with name "${name}".`)
}
return one
}
```
```vue
```
## News Data Loader
```typescript
// wiki/.vitepress/theme/news.data.ts
import { createContentLoader } from 'vitepress'
export interface NewsPost {
/** @example `"−∞ 至2020年10月"` */
period: string
/** @example `"/news/2020"` */
url: string
/**
* 按时间倒序排列。
* @example `["[1.2.0-beta-3] - 2020-06-01", "[1.1.0] - 2020-05-19"]
*/
releases: string[]
}
declare const data: NewsPost[]
export { data }
export default createContentLoader('news/*.md', {
includeSrc: true,
transform(raw): NewsPost[] {
return raw
.filter(({ url }) => url !== '/news/') // Ignore `index.md`
.map(({ url, src }) => parse(url, src as string))
.sort((a, b) => b.url.localeCompare(a.url)) // 按时间倒序排列
},
})
function parse(url: string, src: string): NewsPost {
const lines = src.split('\n')
const period = lines.find((l) => /^# 更新说明:/.test(l))?.replace('# 更新说明:', '')
if (!period) {
console.warn(`未能从 ${url} 中提取一级标题,将用 URL 替代`)
}
const releases = lines
.filter((l) => /^## /.test(l))
?.map((line) => {
const release = /^## (.+?)(?:\{.+\})?$/.exec(line.trim())?.at(1)?.trim()
if (!release) {
console.warn(`未能从 ${url} 中提取二级标题,将跳过:"${line}"`)
}
return release
})
.filter((r) => r !== undefined)
return { period: period ?? url, url, releases }
}
```
## Utility Functions
```typescript
// wiki/.vitepress/theme/util.ts
/**
* Normalize tag from frontmatter (can be string, array, or undefined).
*/
export function normalizeTag(tag: string[] | string | undefined): string[] {
return typeof tag === 'string' ? [tag] : (tag ?? [])
}
/**
* Generate URL for tag-filtered FAQ list.
* If tag is null, returns URL for all FAQs.
*/
export function tagURL(tag: string | null): string {
return '/faq/' + (tag ? `?tag=${tag}` : '') + '#faq-list'
}
/**
* Generate anchor link for news post release section.
*/
export function with_anchor(news_post_url: string, release: string): string {
return news_post_url + '#_' + release.replaceAll(/[\s\[\]]/g, '').replaceAll(/[.]/g, '-')
}
```
## Custom Layout with Tag Display
```vue
```
## Naive UI SSR Integration
```typescript
// wiki/.vitepress/naive-ui-adapter/config.ts
import type { SSGContext, Awaitable } from 'vitepress'
const fileAndStyles: Record = {}
export const vite_ssr = {
noExternal: ['naive-ui', 'date-fns', 'vueuc']
}
/**
* Extract and store Naive UI styles during SSR rendering.
* Removes style tags from content to be reinserted in transformHtml.
*/
export function postRender(context: SSGContext): Awaitable {
const styleRegex = /((.|\s)+)<\/css-render-style>/
const vitepressPathRegex = /(.+)<\/vitepress-path>/
const style = styleRegex.exec(context.content)?.[1]
const vitepressPath = vitepressPathRegex.exec(context.content)?.[1]
if (vitepressPath && style) {
fileAndStyles[vitepressPath] = style
}
context.content = context.content.replace(styleRegex, '')
context.content = context.content.replace(vitepressPathRegex, '')
}
/**
* Insert stored Naive UI styles into the HTML head.
*/
export function transformHtml(code: string, id: string): Awaitable {
const html = id.split('/').pop()
if (!html) return
const style = fileAndStyles[`/${html}`]
if (style) {
return code.replace(/<\/head>/, `${style}`)
}
}
```
```typescript
// wiki/.vitepress/naive-ui-adapter/theme.ts
import { setup } from '@css-render/vue3-ssr'
import { darkTheme, lightTheme, NConfigProvider } from 'naive-ui'
import { useData, useRoute } from 'vitepress'
import { defineComponent, reactive, inject, h, watchEffect } from 'vue'
import Layout from '../theme/Layout.vue'
const CssRenderStyle = defineComponent({
setup() {
const collect = inject('css-render-collect') as () => any
return { style: collect() }
},
render() {
return h('css-render-style', { innerHTML: this.style })
},
})
const VitepressPath = defineComponent({
setup() {
const route = useRoute()
return () => h('vitepress-path', null, [route.path])
},
})
const NaiveUIProvider = defineComponent({
setup() {
const isDark = useData().isDark
const providerProps = reactive({
abstract: true,
inlineThemeDisabled: true,
theme: isDark ? darkTheme : lightTheme,
})
return { isDark, providerProps }
},
mounted() {
watchEffect(() => {
this.providerProps.theme = this.isDark ? darkTheme : lightTheme
})
},
render() {
return h(NConfigProvider, this.providerProps, {
default: () => [
h(Layout, null, { default: this.$slots.default?.() }),
import.meta.env.SSR ? [h(CssRenderStyle), h(VitepressPath)] : null,
],
})
},
})
export { NaiveUIProvider as Layout }
export function enhanceApp({ app }) {
if (import.meta.env.SSR) {
const { collect } = setup(app)
app.provide('css-render-collect', collect)
}
}
```
## Theme Configuration
```typescript
// wiki/.vitepress/theme/index.ts
import { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import { Layout, enhanceApp } from '../naive-ui-adapter/theme'
import './custom.css'
export default {
extends: DefaultTheme,
Layout,
enhanceApp
} satisfies Theme
```
## LaTeX Compilation Commands
```bash
# Method 1: Using latexmk (recommended - handles dependencies automatically)
latexmk
# Method 2: Manual compilation with xelatex and biber
xelatex -no-pdf --interaction=nonstopmode main
biber main
xelatex -no-pdf --interaction=nonstopmode main
xelatex --interaction=nonstopmode main
# Clear auxiliary files and cache
latexmk -c
# Count words in LaTeX document
texcount main.tex -merge -chinese -stat -total
# Count words by chapter
texcount main.tex -merge -sub=chapter
# Search for package documentation
texdoc biblatex-gb7714-2015
# Install missing TeX packages
tlmgr install minted
# Update all TeX packages
tlmgr update --all
# Search for files in TeX distribution
tlmgr search --global --file 'times.sty'
```
## VS Code LaTeX Workshop Configuration
```json
// .vscode/settings.json
{
// Set default recipe to xelatex for Chinese documents
"latex-workshop.latex.recipe.default": "latexmk (xelatex)",
// Define recipes (compilation workflows)
"latex-workshop.latex.recipes": [
{
"name": "latexmk (xelatex)",
"tools": ["xelatexmk"]
}
],
// Define tools (individual commands)
"latex-workshop.latex.tools": [
{
"name": "xelatexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-xelatex",
"-outdir=%OUTDIR%",
"%DOC%"
]
}
],
// Disable auto-build to avoid frequent disk writes
"latex-workshop.latex.autoBuild.run": "never"
}
```
## TeX Live Minimal Installation
```bash
# Linux: Install base infrastructure only
curl -LO https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
tar -zxvf install-tl-unx.tar.gz
cd install-tl-*
mkdir ~/.texlive/
./install-tl --texdir=~/.texlive --scheme=scheme-minimal --no-doc-install --no-src-install
# Add to PATH (add to ~/.bashrc or ~/.zshrc)
export PATH="$HOME/.texlive/bin/x86_64-linux:$PATH"
# Install BIThesis required packages
curl -LO https://github.com/BITNP/BIThesis/raw/refs/heads/main/.github/tl_packages
tlmgr update --self
tlmgr install $(sed -E 's/#.*//' ./tl_packages)
# Windows: Install with PowerShell
curl -LO https://github.com/BITNP/BIThesis/raw/refs/heads/main/.github/tl_packages
tlmgr install ((Get-Content ./tl_packages) -replace '\s*#.*', '')
```
## Page Redirection Configuration
```typescript
// Frontmatter in markdown file
---
redirect-to: /guide/new-location
---
// Handled in config.mts transformHead hook
transformHead({ pageData: { frontmatter } }) {
if (frontmatter['redirect-to']) {
const to = frontmatter['redirect-to']
return [
['link', { rel: 'canonical', href: to }],
['meta', { 'http-equiv': 'refresh', content: `0; url=${to}` }],
['meta', { name: 'robots', content: 'noindex' }],
['script', {}, `window.location = "${to}"`]
]
}
}
```
## Contributing New FAQ Pages
```markdown
---
tag:
- bithesis # BIThesis-specific issue
- package # Requires external package
---
# Problem Title
Description of the problem and solution.
```latex
\documentclass[twoside=false]{bithesis}
\begin{document}
Example solution code here.
\end{document}
```
Link to related resources: [[pkg:algorithm2e]] and [[texdoc:biblatex]].
```
## Code Formatting and Linting
```bash
# Format all files with Prettier
pnpm format
# Check formatting without modifying files
pnpm lint:prettier
# Prettier configuration (.prettierrc)
{
"semi": false,
"singleQuote": true,
"printWidth": 120,
"trailingComma": "es5"
}
```
## Deployment Configuration
```yaml
# Example: Deploy to Vercel or Netlify
# Build command: pnpm build
# Output directory: wiki/.vitepress/dist
# Node version: 22.x
# Vercel configuration (vercel.json)
{
"buildCommand": "pnpm build",
"outputDirectory": "wiki/.vitepress/dist",
"framework": "vitepress"
}
# Netlify configuration (netlify.toml)
[build]
command = "pnpm build"
publish = "wiki/.vitepress/dist"
```
## Summary
BIThesis Wiki demonstrates effective technical documentation practices for academic LaTeX templates. The site combines VitePress's static site generation with custom markdown extensions for package references, enabling seamless navigation between documentation and external resources. The FAQ system with tag filtering helps users quickly find solutions to common LaTeX problems, while the comprehensive guides reduce the barrier to entry for students new to LaTeX. Advanced features include automated sitemap HTML generation for AI knowledge bases, intelligent prev/next navigation links, sophisticated title extraction from markdown sources, and interactive configuration generators with shareable links for template options.
Integration patterns include Chinese text search through Intl.Segmenter, Naive UI components with full SSR support and synchronized dark mode for enhanced interactivity, automated build-time generation of LaTeX index files, and a robust contributors showcase system. The project emphasizes minimal configuration while providing complete control over compilation workflows across different editors. The dual FAQ data loader architecture (runtime and build-time) optimizes both user experience and build performance. Interactive components like BITSetupExample.vue and PubAuthorAnnotation.vue provide user-friendly interfaces for generating LaTeX configuration code with real-time previews and shareable anchor links. Deployment is straightforward through static hosting platforms, with continuous integration ensuring documentation stays synchronized with template releases. The modular architecture supports easy contribution through markdown files, making it simple for the community to expand the knowledge base with comprehensive video tutorials covering all aspects of LaTeX usage.