boltdocs 1.0.4 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/{SearchDialog-R36WKAQ7.mjs → SearchDialog-5EDRACEG.mjs} +1 -1
  2. package/dist/{SearchDialog-PYF3QMYG.css → SearchDialog-X57WPTNN.css} +54 -126
  3. package/dist/cache-EHR7SXRU.mjs +12 -0
  4. package/dist/chunk-GSYECEZY.mjs +381 -0
  5. package/dist/{chunk-TWSRXUFF.mjs → chunk-NS7WHDYA.mjs} +229 -418
  6. package/dist/client/index.css +54 -126
  7. package/dist/client/index.d.mts +5 -4
  8. package/dist/client/index.d.ts +5 -4
  9. package/dist/client/index.js +555 -580
  10. package/dist/client/index.mjs +304 -16
  11. package/dist/client/ssr.css +54 -126
  12. package/dist/client/ssr.js +257 -580
  13. package/dist/client/ssr.mjs +1 -1
  14. package/dist/{config-D2XmHJYe.d.mts → config-BD5ZHz15.d.mts} +7 -0
  15. package/dist/{config-D2XmHJYe.d.ts → config-BD5ZHz15.d.ts} +7 -0
  16. package/dist/node/index.d.mts +2 -2
  17. package/dist/node/index.d.ts +2 -2
  18. package/dist/node/index.js +477 -123
  19. package/dist/node/index.mjs +114 -142
  20. package/package.json +2 -2
  21. package/src/client/app/index.tsx +344 -373
  22. package/src/client/app/preload.tsx +56 -56
  23. package/src/client/index.ts +40 -40
  24. package/src/client/ssr.tsx +51 -51
  25. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +76 -76
  26. package/src/client/theme/components/CodeBlock/index.ts +1 -1
  27. package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +154 -154
  28. package/src/client/theme/components/PackageManagerTabs/index.ts +1 -1
  29. package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +64 -64
  30. package/src/client/theme/components/Playground/Playground.tsx +124 -124
  31. package/src/client/theme/components/Playground/index.ts +1 -1
  32. package/src/client/theme/components/Playground/playground.css +168 -168
  33. package/src/client/theme/components/Video/Video.tsx +84 -84
  34. package/src/client/theme/components/Video/index.ts +1 -1
  35. package/src/client/theme/components/Video/video.css +41 -41
  36. package/src/client/theme/components/mdx/Admonition.tsx +80 -80
  37. package/src/client/theme/components/mdx/Badge.tsx +31 -31
  38. package/src/client/theme/components/mdx/Button.tsx +50 -50
  39. package/src/client/theme/components/mdx/Card.tsx +80 -80
  40. package/src/client/theme/components/mdx/List.tsx +57 -57
  41. package/src/client/theme/components/mdx/Tabs.tsx +94 -94
  42. package/src/client/theme/components/mdx/index.ts +18 -18
  43. package/src/client/theme/components/mdx/mdx-components.css +424 -405
  44. package/src/client/theme/icons/bun.tsx +62 -62
  45. package/src/client/theme/icons/deno.tsx +20 -20
  46. package/src/client/theme/icons/discord.tsx +12 -12
  47. package/src/client/theme/icons/github.tsx +15 -15
  48. package/src/client/theme/icons/npm.tsx +13 -13
  49. package/src/client/theme/icons/pnpm.tsx +72 -72
  50. package/src/client/theme/icons/twitter.tsx +12 -12
  51. package/src/client/theme/styles/markdown.css +343 -343
  52. package/src/client/theme/styles/variables.css +162 -162
  53. package/src/client/theme/styles.css +37 -38
  54. package/src/client/theme/ui/BackgroundGradient/BackgroundGradient.tsx +10 -10
  55. package/src/client/theme/ui/BackgroundGradient/index.ts +1 -1
  56. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +68 -68
  57. package/src/client/theme/ui/Breadcrumbs/index.ts +1 -1
  58. package/src/client/theme/ui/Footer/footer.css +32 -32
  59. package/src/client/theme/ui/Head/Head.tsx +69 -69
  60. package/src/client/theme/ui/Head/index.ts +1 -1
  61. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +125 -125
  62. package/src/client/theme/ui/LanguageSwitcher/index.ts +1 -1
  63. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +98 -98
  64. package/src/client/theme/ui/Layout/Layout.tsx +202 -213
  65. package/src/client/theme/ui/Layout/base.css +76 -76
  66. package/src/client/theme/ui/Layout/index.ts +2 -2
  67. package/src/client/theme/ui/Layout/pagination.css +72 -72
  68. package/src/client/theme/ui/Layout/responsive.css +36 -40
  69. package/src/client/theme/ui/Link/Link.tsx +254 -202
  70. package/src/client/theme/ui/Link/index.ts +2 -2
  71. package/src/client/theme/ui/Loading/Loading.tsx +10 -10
  72. package/src/client/theme/ui/Loading/index.ts +1 -1
  73. package/src/client/theme/ui/Loading/loading.css +30 -30
  74. package/src/client/theme/ui/Navbar/GithubStars.tsx +27 -27
  75. package/src/client/theme/ui/Navbar/Navbar.tsx +145 -145
  76. package/src/client/theme/ui/Navbar/index.ts +2 -2
  77. package/src/client/theme/ui/Navbar/navbar.css +233 -233
  78. package/src/client/theme/ui/NotFound/NotFound.tsx +19 -20
  79. package/src/client/theme/ui/NotFound/index.ts +1 -1
  80. package/src/client/theme/ui/NotFound/not-found.css +64 -64
  81. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +235 -192
  82. package/src/client/theme/ui/OnThisPage/index.ts +1 -1
  83. package/src/client/theme/ui/OnThisPage/toc.css +132 -132
  84. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +18 -18
  85. package/src/client/theme/ui/PoweredBy/index.ts +1 -1
  86. package/src/client/theme/ui/PoweredBy/powered-by.css +76 -76
  87. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +199 -199
  88. package/src/client/theme/ui/SearchDialog/index.ts +1 -1
  89. package/src/client/theme/ui/SearchDialog/search.css +152 -152
  90. package/src/client/theme/ui/Sidebar/Sidebar.tsx +204 -200
  91. package/src/client/theme/ui/Sidebar/index.ts +1 -1
  92. package/src/client/theme/ui/Sidebar/sidebar.css +236 -269
  93. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +69 -69
  94. package/src/client/theme/ui/ThemeToggle/index.ts +1 -1
  95. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +136 -136
  96. package/src/client/theme/ui/VersionSwitcher/index.ts +1 -1
  97. package/src/client/types.ts +50 -50
  98. package/src/client/utils.ts +26 -26
  99. package/src/node/cache.ts +408 -94
  100. package/src/node/config.ts +192 -185
  101. package/src/node/index.ts +21 -21
  102. package/src/node/mdx.ts +120 -41
  103. package/src/node/plugin/entry.ts +58 -58
  104. package/src/node/plugin/html.ts +55 -55
  105. package/src/node/plugin/index.ts +193 -190
  106. package/src/node/plugin/types.ts +11 -11
  107. package/src/node/routes/cache.ts +28 -24
  108. package/src/node/routes/index.ts +167 -152
  109. package/src/node/routes/parser.ts +153 -127
  110. package/src/node/routes/sorter.ts +42 -42
  111. package/src/node/routes/types.ts +49 -49
  112. package/src/node/ssg/index.ts +114 -110
  113. package/src/node/ssg/meta.ts +34 -34
  114. package/src/node/ssg/options.ts +13 -13
  115. package/src/node/ssg/sitemap.ts +54 -54
  116. package/src/node/utils.ts +134 -134
  117. package/tsconfig.json +20 -20
  118. package/tsup.config.ts +22 -22
  119. package/dist/Playground-B2FA34BC.mjs +0 -6
  120. package/dist/chunk-WPT4MWTQ.mjs +0 -89
  121. package/src/client/theme/styles/home.css +0 -60
@@ -1,58 +1,58 @@
1
- import { normalizePath } from "../utils";
2
- import type { BoltdocsConfig } from "../config";
3
- import type { BoltdocsPluginOptions } from "./types";
4
-
5
- /**
6
- * Generates the raw source code for the virtual entry file (`\0virtual:boltdocs-entry`).
7
- * This code initializes the client-side React application.
8
- *
9
- * @param options - Plugin options containing potential custom overrides (like `homePage` or `customCss`)
10
- * @param config - The resolved Boltdocs configuration containing custom plugins and components
11
- * @returns A string of JavaScript code to be evaluated by the browser
12
- */
13
- export function generateEntryCode(
14
- options: BoltdocsPluginOptions,
15
- config?: BoltdocsConfig,
16
- ): string {
17
- const homeImport = options.homePage
18
- ? `import HomePage from '${normalizePath(options.homePage)}';`
19
- : "";
20
- const homeOption = options.homePage ? "homePage: HomePage," : "";
21
- const customCssImport = options.customCss
22
- ? `import '${normalizePath(options.customCss)}';`
23
- : "";
24
-
25
- const pluginComponents =
26
- config?.plugins?.flatMap((p) => Object.entries(p.components || {})) || [];
27
-
28
- const componentImports = pluginComponents
29
- .map(
30
- ([
31
- name,
32
- path,
33
- ]) => `import * as _comp_${name} from '${normalizePath(path)}';
34
- const ${name} = _comp_${name}.default || _comp_${name}['${name}'] || _comp_${name};`,
35
- )
36
- .join("\n");
37
- const componentMap = pluginComponents.map(([name]) => name).join(", ");
38
-
39
- return `
40
- import { createBoltdocsApp as _createApp } from 'boltdocs/client';
41
- import 'boltdocs/style.css';
42
- ${customCssImport}
43
- import _routes from 'virtual:boltdocs-routes';
44
- import _config from 'virtual:boltdocs-config';
45
- ${homeImport}
46
- ${componentImports}
47
-
48
- _createApp({
49
- target: '#root',
50
- routes: _routes,
51
- config: _config,
52
- modules: import.meta.glob('/docs/**/*.{md,mdx}'),
53
- hot: import.meta.hot,
54
- ${homeOption}
55
- components: { ${componentMap} },
56
- });
57
- `;
58
- }
1
+ import { normalizePath } from "../utils";
2
+ import type { BoltdocsConfig } from "../config";
3
+ import type { BoltdocsPluginOptions } from "./types";
4
+
5
+ /**
6
+ * Generates the raw source code for the virtual entry file (`\0virtual:boltdocs-entry`).
7
+ * This code initializes the client-side React application.
8
+ *
9
+ * @param options - Plugin options containing potential custom overrides (like `homePage` or `customCss`)
10
+ * @param config - The resolved Boltdocs configuration containing custom plugins and components
11
+ * @returns A string of JavaScript code to be evaluated by the browser
12
+ */
13
+ export function generateEntryCode(
14
+ options: BoltdocsPluginOptions,
15
+ config?: BoltdocsConfig,
16
+ ): string {
17
+ const homeImport = options.homePage
18
+ ? `import HomePage from '${normalizePath(options.homePage)}';`
19
+ : "";
20
+ const homeOption = options.homePage ? "homePage: HomePage," : "";
21
+ const customCssImport = options.customCss
22
+ ? `import '${normalizePath(options.customCss)}';`
23
+ : "";
24
+
25
+ const pluginComponents =
26
+ config?.plugins?.flatMap((p) => Object.entries(p.components || {})) || [];
27
+
28
+ const componentImports = pluginComponents
29
+ .map(
30
+ ([
31
+ name,
32
+ path,
33
+ ]) => `import * as _comp_${name} from '${normalizePath(path)}';
34
+ const ${name} = _comp_${name}.default || _comp_${name}['${name}'] || _comp_${name};`,
35
+ )
36
+ .join("\n");
37
+ const componentMap = pluginComponents.map(([name]) => name).join(", ");
38
+
39
+ return `
40
+ import { createBoltdocsApp as _createApp } from 'boltdocs/client';
41
+ import 'boltdocs/style.css';
42
+ ${customCssImport}
43
+ import _routes from 'virtual:boltdocs-routes';
44
+ import _config from 'virtual:boltdocs-config';
45
+ ${homeImport}
46
+ ${componentImports}
47
+
48
+ _createApp({
49
+ target: '#root',
50
+ routes: _routes,
51
+ config: _config,
52
+ modules: import.meta.glob('/docs/**/*.{md,mdx}'),
53
+ hot: import.meta.hot,
54
+ ${homeOption}
55
+ components: { ${componentMap} },
56
+ });
57
+ `;
58
+ }
@@ -1,55 +1,55 @@
1
- import type { BoltdocsConfig } from "../config";
2
-
3
- /**
4
- * Injects OpenGraph, Twitter, and generic SEO meta tags into the final HTML output.
5
- * Also ensures the virtual entry file is injected if it's missing (e.g., standard Vite index.html).
6
- *
7
- * @param html - The original HTML string
8
- * @param config - The resolved Boltdocs configuration containing site metadata
9
- * @returns The modified HTML string with injected tags
10
- */
11
- export function injectHtmlMeta(html: string, config: BoltdocsConfig): string {
12
- const title = config.themeConfig?.title || "Boltdocs";
13
- const description = config.themeConfig?.description || "";
14
-
15
- const seoTags = [
16
- `<meta name="description" content="${description}">`,
17
- `<meta property="og:title" content="${title}">`,
18
- `<meta property="og:description" content="${description}">`,
19
- `<meta property="og:type" content="website">`,
20
- `<meta name="twitter:card" content="summary">`,
21
- `<meta name="twitter:title" content="${title}">`,
22
- `<meta name="twitter:description" content="${description}">`,
23
- `<meta name="generator" content="Boltdocs">`,
24
- ].join("\n ");
25
-
26
- const themeScript = `
27
- <script>
28
- (function() {
29
- try {
30
- var stored = localStorage.getItem("boltdocs-theme");
31
- var theme = stored || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
32
- if (theme === "light") {
33
- document.documentElement.classList.add("theme-light");
34
- document.documentElement.dataset.theme = "light";
35
- } else {
36
- document.documentElement.classList.remove("theme-light");
37
- document.documentElement.dataset.theme = "dark";
38
- }
39
- } catch (e) {}
40
- })();
41
- </script>
42
- `;
43
-
44
- html = html.replace(/<title>.*?<\/title>/, `<title>${title}</title>`);
45
- html = html.replace("</head>", ` ${seoTags}\n${themeScript} </head>`);
46
-
47
- if (!html.includes("src/main")) {
48
- html = html.replace(
49
- "</body>",
50
- ' <script type="module">import "virtual:boltdocs-entry";</script>\n </body>',
51
- );
52
- }
53
-
54
- return html;
55
- }
1
+ import type { BoltdocsConfig } from "../config";
2
+
3
+ /**
4
+ * Injects OpenGraph, Twitter, and generic SEO meta tags into the final HTML output.
5
+ * Also ensures the virtual entry file is injected if it's missing (e.g., standard Vite index.html).
6
+ *
7
+ * @param html - The original HTML string
8
+ * @param config - The resolved Boltdocs configuration containing site metadata
9
+ * @returns The modified HTML string with injected tags
10
+ */
11
+ export function injectHtmlMeta(html: string, config: BoltdocsConfig): string {
12
+ const title = config.themeConfig?.title || "Boltdocs";
13
+ const description = config.themeConfig?.description || "";
14
+
15
+ const seoTags = [
16
+ `<meta name="description" content="${description}">`,
17
+ `<meta property="og:title" content="${title}">`,
18
+ `<meta property="og:description" content="${description}">`,
19
+ `<meta property="og:type" content="website">`,
20
+ `<meta name="twitter:card" content="summary">`,
21
+ `<meta name="twitter:title" content="${title}">`,
22
+ `<meta name="twitter:description" content="${description}">`,
23
+ `<meta name="generator" content="Boltdocs">`,
24
+ ].join("\n ");
25
+
26
+ const themeScript = `
27
+ <script>
28
+ (function() {
29
+ try {
30
+ var stored = localStorage.getItem("boltdocs-theme");
31
+ var theme = stored || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
32
+ if (theme === "light") {
33
+ document.documentElement.classList.add("theme-light");
34
+ document.documentElement.dataset.theme = "light";
35
+ } else {
36
+ document.documentElement.classList.remove("theme-light");
37
+ document.documentElement.dataset.theme = "dark";
38
+ }
39
+ } catch (e) {}
40
+ })();
41
+ </script>
42
+ `;
43
+
44
+ html = html.replace(/<title>.*?<\/title>/, `<title>${title}</title>`);
45
+ html = html.replace("</head>", ` ${seoTags}\n${themeScript} </head>`);
46
+
47
+ if (!html.includes("src/main")) {
48
+ html = html.replace(
49
+ "</body>",
50
+ ' <script type="module">import "virtual:boltdocs-entry";</script>\n </body>',
51
+ );
52
+ }
53
+
54
+ return html;
55
+ }
@@ -1,190 +1,193 @@
1
- import { Plugin, ResolvedConfig, loadEnv } from "vite";
2
- import {
3
- generateRoutes,
4
- invalidateRouteCache,
5
- invalidateFile,
6
- } from "../routes";
7
- import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
8
- import { resolveConfig, BoltdocsConfig, CONFIG_FILES } from "../config";
9
- import { generateStaticPages } from "../ssg";
10
- import { normalizePath, isDocFile } from "../utils";
11
- import path from "path";
12
-
13
- import { BoltdocsPluginOptions } from "./types";
14
- import { generateEntryCode } from "./entry";
15
- import { injectHtmlMeta } from "./html";
16
-
17
- export * from "./types";
18
-
19
- /**
20
- * The core Boltdocs Vite plugin.
21
- * Handles virtual module resolution, HMR for documentation files,
22
- * injecting HTML meta tags for SEO, and triggering the SSG process on build.
23
- *
24
- * @param options - Optional configuration for the plugin
25
- * @param passedConfig - Pre-resolved configuration (internal use)
26
- * @returns An array of Vite plugins
27
- */
28
- export function boltdocsPlugin(
29
- options: BoltdocsPluginOptions = {},
30
- passedConfig?: BoltdocsConfig,
31
- ): Plugin[] {
32
- const docsDir = path.resolve(process.cwd(), options.docsDir || "docs");
33
- const normalizedDocsDir = normalizePath(docsDir);
34
- let config: BoltdocsConfig = passedConfig!;
35
- let viteConfig: ResolvedConfig;
36
- let isBuild = false;
37
-
38
- const extraVitePlugins =
39
- config?.plugins?.flatMap((p) => p.vitePlugins || []) || [];
40
-
41
- return [
42
- {
43
- name: "vite-plugin-boltdocs",
44
- enforce: "pre",
45
-
46
- async config(userConfig, env) {
47
- isBuild = env.command === "build";
48
-
49
- // Load env variables and inject into process.env so they are available in boltdocs.config.js
50
- const envDir = userConfig.envDir || process.cwd();
51
- const envs = loadEnv(env.mode, envDir, "");
52
- Object.assign(process.env, envs);
53
-
54
- // Resolve config async if not already passed
55
- if (!config) {
56
- config = await resolveConfig(docsDir);
57
- }
58
-
59
- // If customCss specified in user's config file, use it
60
- if (!options.customCss && config.themeConfig?.customCss) {
61
- options.customCss = config.themeConfig.customCss;
62
- }
63
-
64
- return {
65
- optimizeDeps: { include: ["react", "react-dom"] },
66
- };
67
- },
68
-
69
- configResolved(resolved) {
70
- viteConfig = resolved;
71
- },
72
-
73
- configureServer(server) {
74
- // Explicitly watch config files to trigger server restarts
75
- const configPaths = CONFIG_FILES.map((c) =>
76
- path.resolve(process.cwd(), c),
77
- );
78
- server.watcher.add(configPaths);
79
-
80
- const handleFileEvent = async (
81
- file: string,
82
- type: "add" | "unlink" | "change",
83
- ) => {
84
- const normalized = normalizePath(file);
85
-
86
- // Restart the Vite server if the Boltdocs config changes
87
- if (CONFIG_FILES.some((c) => normalized.endsWith(c))) {
88
- server.restart();
89
- return;
90
- }
91
-
92
- if (
93
- !normalized.startsWith(normalizedDocsDir) ||
94
- !isDocFile(normalized)
95
- )
96
- return;
97
-
98
- // Invalidate appropriately
99
- if (type === "add" || type === "unlink") {
100
- invalidateRouteCache();
101
- } else {
102
- invalidateFile(file);
103
- }
104
-
105
- // Regenerate and push to client
106
- const newRoutes = await generateRoutes(docsDir, config);
107
-
108
- const routesMod = server.moduleGraph.getModuleById(
109
- "\0virtual:boltdocs-routes",
110
- );
111
- if (routesMod) server.moduleGraph.invalidateModule(routesMod);
112
-
113
- server.ws.send({
114
- type: "custom",
115
- event: "boltdocs:routes-update",
116
- data: newRoutes,
117
- });
118
- };
119
-
120
- server.watcher.on("add", (f) => handleFileEvent(f, "add"));
121
- server.watcher.on("unlink", (f) => handleFileEvent(f, "unlink"));
122
- server.watcher.on("change", (f) => handleFileEvent(f, "change"));
123
- },
124
-
125
- resolveId(id) {
126
- if (
127
- id === "virtual:boltdocs-routes" ||
128
- id === "virtual:boltdocs-config" ||
129
- id === "virtual:boltdocs-entry"
130
- ) {
131
- return "\0" + id;
132
- }
133
- },
134
-
135
- async load(id) {
136
- if (id === "\0virtual:boltdocs-routes") {
137
- const routes = await generateRoutes(docsDir, config);
138
- return `export default ${JSON.stringify(routes, null, 2)};`;
139
- }
140
- if (id === "\0virtual:boltdocs-config") {
141
- const clientConfig = {
142
- themeConfig: config?.themeConfig,
143
- i18n: config?.i18n,
144
- versions: config?.versions,
145
- siteUrl: config?.siteUrl,
146
- };
147
- return `export default ${JSON.stringify(clientConfig, null, 2)};`;
148
- }
149
- if (id === "\0virtual:boltdocs-entry") {
150
- const code = generateEntryCode(options, config);
151
- return code;
152
- }
153
- },
154
-
155
- transformIndexHtml: {
156
- order: "pre",
157
- handler(html) {
158
- return injectHtmlMeta(html, config);
159
- },
160
- },
161
-
162
- async closeBundle() {
163
- if (!isBuild) return;
164
- const outDir = viteConfig?.build?.outDir
165
- ? path.resolve(viteConfig.root, viteConfig.build.outDir)
166
- : path.resolve(process.cwd(), "dist");
167
-
168
- await generateStaticPages({ docsDir, outDir, config });
169
- },
170
- },
171
- ViteImageOptimizer({
172
- includePublic: true,
173
- png: { quality: 80 },
174
- jpeg: { quality: 80 },
175
- jpg: { quality: 80 },
176
- webp: { quality: 80 },
177
- avif: { quality: 80 },
178
- svg: {
179
- multipass: true,
180
- plugins: [
181
- {
182
- name: "preset-default",
183
- params: { overrides: { removeViewBox: false } },
184
- },
185
- ] as any,
186
- },
187
- }),
188
- ...extraVitePlugins.filter((p): p is Plugin => !!p),
189
- ];
190
- }
1
+ import { Plugin, ResolvedConfig, loadEnv } from "vite";
2
+ import {
3
+ generateRoutes,
4
+ invalidateRouteCache,
5
+ invalidateFile,
6
+ } from "../routes";
7
+ import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
8
+ import { resolveConfig, BoltdocsConfig, CONFIG_FILES } from "../config";
9
+ import { generateStaticPages } from "../ssg";
10
+ import { normalizePath, isDocFile } from "../utils";
11
+ import path from "path";
12
+
13
+ import { BoltdocsPluginOptions } from "./types";
14
+ import { generateEntryCode } from "./entry";
15
+ import { injectHtmlMeta } from "./html";
16
+
17
+ export * from "./types";
18
+
19
+ /**
20
+ * The core Boltdocs Vite plugin.
21
+ * Handles virtual module resolution, HMR for documentation files,
22
+ * injecting HTML meta tags for SEO, and triggering the SSG process on build.
23
+ *
24
+ * @param options - Optional configuration for the plugin
25
+ * @param passedConfig - Pre-resolved configuration (internal use)
26
+ * @returns An array of Vite plugins
27
+ */
28
+ export function boltdocsPlugin(
29
+ options: BoltdocsPluginOptions = {},
30
+ passedConfig?: BoltdocsConfig,
31
+ ): Plugin[] {
32
+ const docsDir = path.resolve(process.cwd(), options.docsDir || "docs");
33
+ const normalizedDocsDir = normalizePath(docsDir);
34
+ let config: BoltdocsConfig = passedConfig!;
35
+ let viteConfig: ResolvedConfig;
36
+ let isBuild = false;
37
+
38
+ const extraVitePlugins =
39
+ config?.plugins?.flatMap((p) => p.vitePlugins || []) || [];
40
+
41
+ return [
42
+ {
43
+ name: "vite-plugin-boltdocs",
44
+ enforce: "pre",
45
+
46
+ async config(userConfig, env) {
47
+ isBuild = env.command === "build";
48
+
49
+ // Load env variables and inject into process.env so they are available in boltdocs.config.js
50
+ const envDir = userConfig.envDir || process.cwd();
51
+ const envs = loadEnv(env.mode, envDir, "");
52
+ Object.assign(process.env, envs);
53
+
54
+ // Resolve config async if not already passed
55
+ if (!config) {
56
+ config = await resolveConfig(docsDir);
57
+ }
58
+
59
+ // If customCss specified in user's config file, use it
60
+ if (!options.customCss && config.themeConfig?.customCss) {
61
+ options.customCss = config.themeConfig.customCss;
62
+ }
63
+
64
+ return {
65
+ optimizeDeps: { include: ["react", "react-dom"] },
66
+ };
67
+ },
68
+
69
+ configResolved(resolved) {
70
+ viteConfig = resolved;
71
+ },
72
+
73
+ configureServer(server) {
74
+ // Explicitly watch config files to trigger server restarts
75
+ const configPaths = CONFIG_FILES.map((c) =>
76
+ path.resolve(process.cwd(), c),
77
+ );
78
+ server.watcher.add(configPaths);
79
+
80
+ const handleFileEvent = async (
81
+ file: string,
82
+ type: "add" | "unlink" | "change",
83
+ ) => {
84
+ const normalized = normalizePath(file);
85
+
86
+ // Restart the Vite server if the Boltdocs config changes
87
+ if (CONFIG_FILES.some((c) => normalized.endsWith(c))) {
88
+ server.restart();
89
+ return;
90
+ }
91
+
92
+ if (
93
+ !normalized.startsWith(normalizedDocsDir) ||
94
+ !isDocFile(normalized)
95
+ )
96
+ return;
97
+
98
+ // Invalidate appropriately
99
+ if (type === "add" || type === "unlink") {
100
+ invalidateRouteCache();
101
+ } else {
102
+ invalidateFile(file);
103
+ }
104
+
105
+ // Regenerate and push to client
106
+ const newRoutes = await generateRoutes(docsDir, config);
107
+
108
+ const routesMod = server.moduleGraph.getModuleById(
109
+ "\0virtual:boltdocs-routes",
110
+ );
111
+ if (routesMod) server.moduleGraph.invalidateModule(routesMod);
112
+
113
+ server.ws.send({
114
+ type: "custom",
115
+ event: "boltdocs:routes-update",
116
+ data: newRoutes,
117
+ });
118
+ };
119
+
120
+ server.watcher.on("add", (f) => handleFileEvent(f, "add"));
121
+ server.watcher.on("unlink", (f) => handleFileEvent(f, "unlink"));
122
+ server.watcher.on("change", (f) => handleFileEvent(f, "change"));
123
+ },
124
+
125
+ resolveId(id) {
126
+ if (
127
+ id === "virtual:boltdocs-routes" ||
128
+ id === "virtual:boltdocs-config" ||
129
+ id === "virtual:boltdocs-entry"
130
+ ) {
131
+ return "\0" + id;
132
+ }
133
+ },
134
+
135
+ async load(id) {
136
+ if (id === "\0virtual:boltdocs-routes") {
137
+ const routes = await generateRoutes(docsDir, config);
138
+ return `export default ${JSON.stringify(routes, null, 2)};`;
139
+ }
140
+ if (id === "\0virtual:boltdocs-config") {
141
+ const clientConfig = {
142
+ themeConfig: config?.themeConfig,
143
+ i18n: config?.i18n,
144
+ versions: config?.versions,
145
+ siteUrl: config?.siteUrl,
146
+ };
147
+ return `export default ${JSON.stringify(clientConfig, null, 2)};`;
148
+ }
149
+ if (id === "\0virtual:boltdocs-entry") {
150
+ const code = generateEntryCode(options, config);
151
+ return code;
152
+ }
153
+ },
154
+
155
+ transformIndexHtml: {
156
+ order: "pre",
157
+ handler(html) {
158
+ return injectHtmlMeta(html, config);
159
+ },
160
+ },
161
+
162
+ async closeBundle() {
163
+ if (!isBuild) return;
164
+ const outDir = viteConfig?.build?.outDir
165
+ ? path.resolve(viteConfig.root, viteConfig.build.outDir)
166
+ : path.resolve(process.cwd(), "dist");
167
+
168
+ await generateStaticPages({ docsDir, outDir, config });
169
+
170
+ const { flushCache } = await import("../cache");
171
+ await flushCache();
172
+ },
173
+ },
174
+ ViteImageOptimizer({
175
+ includePublic: true,
176
+ png: { quality: 80 },
177
+ jpeg: { quality: 80 },
178
+ jpg: { quality: 80 },
179
+ webp: { quality: 80 },
180
+ avif: { quality: 80 },
181
+ svg: {
182
+ multipass: true,
183
+ plugins: [
184
+ {
185
+ name: "preset-default",
186
+ params: { overrides: { removeViewBox: false } },
187
+ },
188
+ ] as any,
189
+ },
190
+ }),
191
+ ...extraVitePlugins.filter((p): p is Plugin => !!p),
192
+ ];
193
+ }
@@ -1,11 +1,11 @@
1
- /**
2
- * Configuration options specifically for the Boltdocs Vite plugin.
3
- */
4
- export interface BoltdocsPluginOptions {
5
- /** The root directory containing markdown files (default: 'docs') */
6
- docsDir?: string;
7
- /** Path to a custom home page component (relative to project root) to render at '/' */
8
- homePage?: string;
9
- /** Path to a custom CSS file to override theme variables. Can also be set in boltdocs.config.js */
10
- customCss?: string;
11
- }
1
+ /**
2
+ * Configuration options specifically for the Boltdocs Vite plugin.
3
+ */
4
+ export interface BoltdocsPluginOptions {
5
+ /** The root directory containing markdown files (default: 'docs') */
6
+ docsDir?: string;
7
+ /** Path to a custom home page component (relative to project root) to render at '/' */
8
+ homePage?: string;
9
+ /** Path to a custom CSS file to override theme variables. Can also be set in boltdocs.config.js */
10
+ customCss?: string;
11
+ }