A VitePress plugin that keeps pages out of the build
with a .exclude file in the folder that holds them.
VitePress's srcExclude is one list of globs in config.mts, far from the
pages it hides. With this plugin, each folder says what to leave out:
docs/guide/
.exclude
index.md
draft.md
internal-notes.md
drafts/# docs/guide/.exclude
draft.md
internal-*.md
drafts/Those pages are not built, not in search and not in the sitemap. The files stay where they are.
- Same syntax as auto-sidebar.
@binarynoir/vitepress-auto-sidebarand@binarynoir/vitepress-auto-navbarread the same.excludefiles, so one line hides a page from the navigation and keeps it out of the build. - Live in
vitepress dev. Add, change or delete a.excludefile and the dev server restarts with the new rules.
npm install --save-dev @binarynoir/vitepress-excludeWrap your config with withExclude and pass it the docs source directory:
// .vitepress/config.mts
import path from "node:path";
import { defineConfig } from "vitepress";
import { withExclude } from "@binarynoir/vitepress-exclude/vitepress";
export default withExclude(
defineConfig({
// ...your config
}),
path.resolve(import.meta.dirname, ".."),
);withExclude adds the globs to srcExclude and the dev-server plugin to
vite.plugins. It keeps what is already there, so it composes with other
withX() wrappers in any order.
The two pieces are also exported on their own:
// .vitepress/config.mts
import path from "node:path";
import { defineConfig } from "vitepress";
import { excludeSrc, excludeVitePlugin } from "@binarynoir/vitepress-exclude";
const docsRoot = path.resolve(import.meta.dirname, "..");
export default defineConfig({
// Globs for every `.exclude` rule under the docs folder.
srcExclude: [...excludeSrc(docsRoot), "**/_snippets/**"],
vite: {
// Restarts `vitepress dev` when a `.exclude` file changes.
plugins: [excludeVitePlugin()],
},
});One rule per line. Blank lines and lines starting with # are ignored. Rules
are relative to the folder the .exclude file is in, and a .exclude file in
the docs root works too.
| Rule | Excludes |
|---|---|
draft.md |
That file. A name without a / also matches a folder. |
drafts/ |
That folder and everything in it. |
internal-*.md |
Matching files in this folder. * and ? stay in one level. |
**/internal.md |
Matching files in this folder or any folder below it. |
. |
The whole folder the .exclude file is in. |
Rules that cannot be turned into srcExclude globs are skipped with a warning:
!keep.md: VitePress cannot re-include a file that another rule excluded.../other.md: a rule cannot reach outside its own folder. Put a.excludefile in that folder instead.
Folders whose names start with . (such as .vitepress) and node_modules
are not searched for .exclude files. VitePress never builds pages from them.
A .exclude file lists what to leave out from the folder. A page can also say
it for itself, in its frontmatter. List the keys with excludeFrontmatter, and
any page that sets one of them to true is left out of the build:
withExclude(defineConfig({/* ... */}), docsRoot, {
excludeFrontmatter: ["draft"],
});---
title: Pricing changes
draft: true
----
Only
truecounts.draft: false,draft: "yes"or nodraftat all leave the page in. -
Dotted keys read nested values.
["draft", "blog.draft"]also leaves out@binarynoir/vitepress-blogposts markedblog: { draft: true }. The blog then lists only what was built, so a draft is never in a list or feed either. -
The menus follow. Auto Sidebar and Auto Navbar take the same
excludeFrontmatteroption and hide the same pages, just as they read the same.excludefiles. -
Preview drafts in
vitepress devby turning it on for builds only. VitePress setsNODE_ENVtoproductionbefore it loads the config for a build:const excludeFrontmatter = process.env.NODE_ENV === "production" ? ["draft"] : [];
-
In
vitepress dev, a page that gains or losesdraft: truerestarts the server, as an edited.excludefile does, so the change applies right away.
Both withExclude(config, srcDir, options) and excludeSrc(srcDir, options) take:
| Option | Default | Description |
|---|---|---|
excludeFilenames |
[".exclude"] |
Filenames read in each folder. |
excludeFrontmatter |
[] |
Frontmatter keys that leave a page out when true, such as ["draft", "blog.draft"]. See Drafts in frontmatter. |
verbose |
false |
Log each .exclude file, its rules and the globs it made. |
excludeVitePlugin(options) takes excludeFilenames and excludeFrontmatter. Pass it the same lists.
srcExclude is read when VitePress loads the config, so excludeSrc walks the
source folder then and turns each rule into globs. The dev-server plugin
registers every .exclude file as a config dependency. When one changes,
VitePress reloads the config and restarts the server, as it does when you edit
config.mts. The plugin does nothing in vitepress build.
Releases are tag-triggered. To ship a new version, from a clean main that's
in sync with origin/main:
npm run release:patch # or release:minor / release:majorThis runs typecheck/lint/test/build locally, then npm version <bump>
(bumps package.json, commits, and creates a matching vX.Y.Z tag) and
git push --follow-tags. Pushing that tag triggers
.github/workflows/release.yml, which
re-runs the checks, publishes to npm (with
provenance), and
creates a GitHub release with auto-generated notes.
For a prerelease or an explicit version, use npm run release -- <arg>
(e.g. npm run release -- 1.2.3 or npm run release -- prerelease) — see
npm version for the
full list of accepted values.
Publishing uses npm Trusted Publishing
(OIDC): no npm token is stored in the repository. The package's npm settings
trust .github/workflows/release.yml in this repository, so renaming that
file breaks publishing until the setting is updated.
Bug reports, feature requests and questions are all welcome. Please open them on this project's GitHub issue tracker:
- Found a bug? Report it. Include your version and the steps to reproduce it.
- Have an idea? Request a feature. Tell us what you are trying to do.
- Something else? Browse open issues to see if it has already been raised.
Pull requests are welcome too.
Exclude is one of a family of open-source tools from BinaryNoir.
Pairs well with Exclude
- Broken Links: dead links shown as text, not build errors
- Downloads: downloadable files next to your pages
New: Blog: posts anywhere, a main blog and section blogs, with RSS feeds
See them all: VitePress plugins, Vite plugins, editor extensions and command-line tools, with documentation and live demos, at binarynoir.tech.
John Smith III, BinaryNoir. Thanks to all contributors and users for their support and feedback.