English
VitePress Architecture Refactoring Record: Reject Flatness and Coupling, Refactor Your Independent Documentation Project

I. Why do we need to refactor?
If you have visited the official VitePress documentation, or have built a blog following mainstream tutorials, you will most likely end up with a directory structure like this:
text
my-project/
├── docs/
│ ├── .vitepress/ (config, theme, cache)
│ ├── public/ (static assets)
│ └── zh/en/ (Markdown documents)
└── package.jsonThe original design intention of this architecture was to Embed the product documentation as a subdirectory into the existing business code repository.. For this kind of scenario, this design is indeed very convenient.
But what if you are building an independent blog, knowledge base, or a documentation project that needs to support multiple languages (i18n)?
In this standalone project, there is no backend code and no frontend business components; it is itself a complete engineering project. At this point, if one still forcibly applies docs As a top-level directory, it would create a very strong sense of incongruity:
Responsibilities are extremely unclear.:
.vitepressis project configuration,publicThey are static assets; why should they be shoved into something meant for pure content?docsIn the directory?Violates the design philosophy of i18n: If multilingual support is introduced,
docsThe directory should purely only containdocs/zh,docs/en, it is the purest repository of language content. Putting build configuration inside it is like stuffing the engine into the trunk.Path nesting is extremely deep.: at every turn
../../../docs/.vitepress/config.tsThe path is extremely user-hostile.Ecosystem fragmentation: Many tools (such as Tailwind, ESLint, GitHub Actions) scan and build from the project root by default, nested in
docsThis will make various configurations cumbersome and prone to failure.
Therefore, I decided to carry out an architectural refactoring, so that Documents, resources, and configurations are on equal footing and completely decoupled. The target structure is as follows:
text
my-blog/
├── .vitepress/ (Project configuration and theme)
├── public/ (static assets)
├── docs/ (pure Markdown, e.g. docs/zh, docs/en)
└── package.jsonHowever, this action, which seemed to be just [moving a folder to another location], ended up taking me an entire afternoon. Below are the ten major pitfalls I encountered along the refactoring journey, and I hope they help you.
II. Environment and Basic Configuration Section
Pitfall 1: Git not found, service cannot start (spawnSync git ENOENT)
phenomenon Move .vitepress Afterwards, run npm run docs:dev Throw an error directly spawnSync git ENOENT. Reason: By default, VitePress calls Git commands to retrieve file modification times. Because my terminal environment may have Python venv Interference, or Node environment variable isolation, causing git Not found. Solution method: at config.mts middle Explicit Close lastUpdated: false, and block it in the Vite configuration .git Monitoring:
typescript
vite: { server: { watch: { ignored: ['**/.git/**'] } } }Pitfall 2: Frustrating Cache Drift (docs/.vitepress/cache)
phenomenon: Clearly moved the configuration file to the root directory, but after startup it always docs/ Secretly generate below .vitepress/cache. Reason: When you have configured srcDir: 'docs' At this point, the default relative path inference of Vite will base this cache directory on srcDir Perform concatenation. Solution: use fileURLToPath Absolutely anchor the cache path at the root directory:
javascript
cacheDir: fileURLToPath(new URL('../cache', import.meta.url))III. Rendering and Visuals (a chain of pitfalls that make people think the project is broken)
Pitfall 3: White screen/black screen caused by failed automatic import
Phenomenon: The page is black, and the console shows an error ReferenceError: useVitePressTheme is not defined. Reason:AutoImport The plugin's relative path is invalid, so the API is not injected. Solution: will AutoImport of dirs and dts Use all fileURLToPath Change to an absolute path.
Pitfall 4: Tailwind CSS stops working and the layout falls apart
phenomenon: Content is out, but flex and other styles all became invalid, and the pagination component flew off the screen. Reason:tailwind.config.js The scan path has not been updated, still searching../docs/.vitepress components in it. Solution: Modify the scan scope, explicitly point to the root directory's .vitepress:
javascript
content: ['./docs/**/*.md', './.vitepress/**/*.{vue,js,ts}']Pitfall 5: Archive page data is empty (import.meta.glob Invalid)
phenomenon Archive page (Archive) has no data and does not report an error. Reason: Original path ../../../{zh,en}/data/ Under the new structure, it goes outside the project root, so Vite cannot match the files. Solution method: Add to correction path docs Prefix:../../../docs/{zh,en}/data/archives.json.
Pitfall 6:public Directory Move Triggers the [Ultimate Black Screen]
phenomenon: Take public from docs/ After moving to the root directory, the console reports vitepress data not properly injected in app. reason:publicDir Mismatched pairing, causing the underlying NavBar rendering to fail and the component tree Provide/Inject chain to break. Solution: at vite.config.js that precisely specifies the root directory in public:
javascript
publicDir: fileURLToPath(new URL('../../public', import.meta.url))IV. File False Positives and CI Deployment
Pitfall 7: The disaster brought by global replacement
Phenomenon: The path in Markdown was changed to something strange ../../../../public, the code block highlighting markers were accidentally deleted, and the CSS font path is invalid. Solution:Stop mindless global replacement. Use.git checkout Restore the accidentally affected Markdown; in config.mts remap alias in (~ point to docs,~@ point to .vitepress).
Pitfall 8: Ghost type error (.d.ts Pollution)
phenomenon:auto-import.d.ts A nonexistent import path appears, causing the IDE to show red errors. Solution: This is an automatically generated cache file. Delete it.node_modules/.vite and .vitepress/cache, run again npm run docs:dev Just regenerate it.
Pitfall 9: GitHub Actions CI build failure
Phenomenon: It works locally, but when pushed to GitHub for packaging it cannot be found.dist Table of contents. Reason: The old path is hardcoded in the workflow YAML file. Solution: Modify .github/workflows/ the script below, take docs/.vitepress/dist Updated to .vitepress/dist.
Pitfall 10: Python dependencies and Node fighting each other
phenomenon Installed the yaml package for Python, Node cannot find git; after exiting venv, Python reports an error again. Solution method: Use pip3 install pyyaml --break-system-packages --user Install dependencies into the user directory, or use Makefile Isolated environment.
V. Summary
After refactoring, looking at those under the root directory that are on equal footing .vitepress,public and docs, that refreshing feeling is indescribable.docs Finally returned to pure content attributes, especially when things are neatly placed inside it zh/ and en/ Only then does it truly meet the architectural standards of a multilingual independent website.
Refactoring Advice:
Before you start, first
git commit.Firmly resist using global replace in the IDE!
When encountering path issues, just use it without thinking.
fileURLToPathAbsolute paths keep you safe.
Hope this pitfall avoidance guide helps you smoothly complete the architecture upgrade.