@mdream/vite 0.11.0 → 0.12.0
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.
- package/README.md +26 -6
- package/dist/index.mjs +23 -11
- 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
|
-
|
|
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
|
-
|
|
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(
|
|
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 ${
|
|
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 ${
|
|
135
|
+
log(`Error serving ${url}: ${message}`);
|
|
127
136
|
res.statusCode = 404;
|
|
128
|
-
res.end(`HTML content not found for ${
|
|
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
|
-
|
|
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(
|
|
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 ${
|
|
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 ${
|
|
180
|
+
log(`Error in preview server for ${url}: ${message}`);
|
|
169
181
|
res.statusCode = 404;
|
|
170
|
-
res.end(`HTML content not found for ${
|
|
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.
|
|
4
|
+
"version": "0.12.0",
|
|
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.
|
|
46
|
+
"mdream": "0.12.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@types/node": "^24.6.
|
|
49
|
+
"@types/node": "^24.6.1",
|
|
50
50
|
"vite": "^7.1.7"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|