@mdream/vite 0.11.1 → 0.12.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 (3) hide show
  1. package/README.md +26 -6
  2. package/dist/index.mjs +23 -11
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -1,10 +1,15 @@
1
1
  # @mdream/vite
2
2
 
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![License][license-src]][license-href]
6
+
3
7
  Vite plugin for HTML to Markdown conversion with on-demand generation support.
4
8
 
5
9
  ## Features
6
10
 
7
11
  - **🚀 On-Demand Generation**: Access any HTML page as `.md` for instant markdown conversion
12
+ - **🤖 Smart Client Detection**: Automatically serves markdown to LLM bots based on Accept headers
8
13
  - **⚡ Multi-Environment**: Works in development, preview, and production
9
14
  - **📦 Build Integration**: Generate static markdown files during build
10
15
  - **💾 Smart Caching**: Intelligent caching for optimal performance
@@ -14,11 +19,7 @@ Vite plugin for HTML to Markdown conversion with on-demand generation support.
14
19
  ## Installation
15
20
 
16
21
  ```bash
17
- npm install @mdream/vite mdream
18
- # or
19
- pnpm add @mdream/vite mdream
20
- # or
21
- yarn add @mdream/vite mdream
22
+ pnpm add @mdream/vite
22
23
  ```
23
24
 
24
25
  ## Usage
@@ -54,6 +55,15 @@ The plugin enables accessing any HTML path with a `.md` extension:
54
55
  - `/docs/guide.html` → `/docs/guide.md`
55
56
  - `/blog/post` → `/blog/post.md`
56
57
 
58
+ ### Smart Client Detection
59
+
60
+ The plugin automatically detects LLM bots and serves markdown without requiring the `.md` extension:
61
+
62
+ - ✅ **Serves markdown** when `Accept` header contains `*/*` or `text/markdown` (but not `text/html`)
63
+ - ❌ **Serves HTML** to browsers (checks for `text/html` in Accept header or `sec-fetch-dest: document`)
64
+
65
+ This means LLM bots automatically receive optimized markdown responses, reducing token usage by ~10x compared to HTML.
66
+
57
67
  ## Configuration Options
58
68
 
59
69
  ```ts
@@ -206,4 +216,14 @@ app.use(async (req, res, next) => {
206
216
 
207
217
  ## License
208
218
 
209
- MIT
219
+ [MIT License](./LICENSE)
220
+
221
+ <!-- Badges -->
222
+ [npm-version-src]: https://img.shields.io/npm/v/@mdream/vite/latest.svg?style=flat&colorA=18181B&colorB=4C9BE0
223
+ [npm-version-href]: https://npmjs.com/package/@mdream/vite
224
+
225
+ [npm-downloads-src]: https://img.shields.io/npm/dm/@mdream/vite.svg?style=flat&colorA=18181B&colorB=4C9BE0
226
+ [npm-downloads-href]: https://npm.chart.dev/@mdream/vite
227
+
228
+ [license-src]: https://img.shields.io/npm/l/@mdream/vite.svg?style=flat&colorA=18181B&colorB=4C9BE0
229
+ [license-href]: https://npmjs.com/package/@mdream/vite
package/dist/index.mjs CHANGED
@@ -50,7 +50,7 @@ function viteHtmlToMarkdownPlugin(userOptions = {}) {
50
50
  }
51
51
  }
52
52
  async function handleMarkdownRequest(url, server = null, outDir) {
53
- let basePath = url.slice(0, -3);
53
+ let basePath = url.endsWith(".md") ? url.slice(0, -3) : url;
54
54
  if (basePath === "/index") basePath = "/";
55
55
  const source = server ? "dev" : outDir ? "preview" : "build";
56
56
  const cacheKey = `${source}:${basePath}`;
@@ -108,24 +108,33 @@ function viteHtmlToMarkdownPlugin(userOptions = {}) {
108
108
  return regex.test(fileName);
109
109
  });
110
110
  }
111
+ function shouldServeMarkdown(acceptHeader, secFetchDest) {
112
+ const accept = acceptHeader || "";
113
+ if (secFetchDest === "document") return false;
114
+ if (accept.includes("text/html")) return false;
115
+ return accept.includes("*/*") || accept.includes("text/markdown");
116
+ }
111
117
  return {
112
118
  name: "vite-html-to-markdown",
113
119
  configureServer(server) {
114
120
  server.middlewares.use(async (req, res, next) => {
115
- if (!req.url?.endsWith(".md")) return next();
121
+ const hasMarkdownExtension = req.url?.endsWith(".md");
122
+ const clientPrefersMarkdown = shouldServeMarkdown(req.headers.accept, req.headers["sec-fetch-dest"]);
123
+ if (!hasMarkdownExtension && !clientPrefersMarkdown) return next();
124
+ const url = hasMarkdownExtension ? req.url : req.url;
116
125
  try {
117
- const result = await handleMarkdownRequest(req.url, server);
126
+ const result = await handleMarkdownRequest(url, server);
118
127
  res.setHeader("Content-Type", "text/markdown; charset=utf-8");
119
128
  res.setHeader("Cache-Control", "no-cache");
120
129
  res.setHeader("X-Markdown-Source", result.source);
121
130
  res.setHeader("X-Markdown-Cached", result.cached.toString());
122
131
  res.end(result.content);
123
- log(`Served ${req.url} from ${result.source} (cached: ${result.cached})`);
132
+ log(`Served ${url} from ${result.source} (cached: ${result.cached})`);
124
133
  } catch (error) {
125
134
  const message = error instanceof Error ? error.message : String(error);
126
- log(`Error serving ${req.url}: ${message}`);
135
+ log(`Error serving ${url}: ${message}`);
127
136
  res.statusCode = 404;
128
- res.end(`HTML content not found for ${req.url}`);
137
+ res.end(`HTML content not found for ${url}`);
129
138
  }
130
139
  });
131
140
  },
@@ -153,21 +162,24 @@ function viteHtmlToMarkdownPlugin(userOptions = {}) {
153
162
  },
154
163
  configurePreviewServer(server) {
155
164
  server.middlewares.use(async (req, res, next) => {
156
- if (!req.url?.endsWith(".md")) return next();
165
+ const hasMarkdownExtension = req.url?.endsWith(".md");
166
+ const clientPrefersMarkdown = shouldServeMarkdown(req.headers.accept, req.headers["sec-fetch-dest"]);
167
+ if (!hasMarkdownExtension && !clientPrefersMarkdown) return next();
168
+ const url = hasMarkdownExtension ? req.url : req.url;
157
169
  try {
158
170
  const outDir = server.config.build?.outDir || "dist";
159
- const result = await handleMarkdownRequest(req.url, null, outDir);
171
+ const result = await handleMarkdownRequest(url, null, outDir);
160
172
  res.setHeader("Content-Type", "text/markdown; charset=utf-8");
161
173
  res.setHeader("Cache-Control", "public, max-age=3600");
162
174
  res.setHeader("X-Markdown-Source", result.source);
163
175
  res.setHeader("X-Markdown-Cached", result.cached.toString());
164
176
  res.end(result.content);
165
- log(`Served ${req.url} from ${result.source} (cached: ${result.cached})`);
177
+ log(`Served ${url} from ${result.source} (cached: ${result.cached})`);
166
178
  } catch (error) {
167
179
  const message = error instanceof Error ? error.message : String(error);
168
- log(`Error in preview server for ${req.url}: ${message}`);
180
+ log(`Error in preview server for ${url}: ${message}`);
169
181
  res.statusCode = 404;
170
- res.end(`HTML content not found for ${req.url}`);
182
+ res.end(`HTML content not found for ${url}`);
171
183
  }
172
184
  });
173
185
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mdream/vite",
3
3
  "type": "module",
4
- "version": "0.11.1",
4
+ "version": "0.12.1",
5
5
  "description": "Vite plugin for HTML to Markdown conversion with on-demand generation",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -43,10 +43,10 @@
43
43
  "vite": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
44
44
  },
45
45
  "dependencies": {
46
- "mdream": "0.11.1"
46
+ "mdream": "0.12.1"
47
47
  },
48
48
  "devDependencies": {
49
- "@types/node": "^24.6.0",
49
+ "@types/node": "^24.6.2",
50
50
  "vite": "^7.1.7"
51
51
  },
52
52
  "scripts": {