@mdream/nuxt
@mdream/nuxt
Nuxt module for converting HTML pages to Markdown using mdream.
Setup
Installation
pnpm add @mdream/nuxt
Requires Nuxt 3.0.0 or later.
Module Registration
export default defineNuxtConfig({
modules: ['@mdream/nuxt'],
})
Once registered, indexable pages are available as Markdown by appending .md to the path, such as /about.md.
Bots can omit .md when their Accept header ranks text/markdown or text/plain above HTML.
Migrating from v1
These docs cover v2. For an earlier release, read the README at its release tag.
- The
mdreamOptionsdefault is now{ minimal: true }. The v1 default was{ preset: 'minimal' }. mdream never readpreset, so the minimal preset did not apply. - Your
.mdoutput changes because the minimal preset now applies. The output starts with YAML frontmatter. The preset removes navigation, footers, forms, and similar elements, and cleans up links. The auto-importedhtmlToMarkdownandstreamHtmlToMarkdownuse the same default. To turn the preset off, setmdreamOptions: { minimal: false }. mdreamOptions.presetis removed. If you set it, the build fails. PassmdreamOptions: { minimal: true }.- The
cacheoption is removed. It had no effect, so deletecache.maxAgeandcache.swr. - An unknown key in
mdreamOptionsthrows aTypeErrorwhen a page converts.
Pass the Rust engine's options in mdreamOptions.
For browser imports, filtering, and other option changes, see the mdream migration guide.
The client composable imports mdream/browser and awaits the conversion.
Calls to convert() still return Promise<string>.
To keep navigation, forms, and other elements that the minimal preset removes, turn it off:
export default defineNuxtConfig({
modules: ['@mdream/nuxt'],
mdream: {
mdreamOptions: { minimal: false },
},
})
If a mdream:config hook sets options.extraction, the module still extracts page titles and descriptions.
If your hook handles the same selector, both handlers run.
Rebuild prerendered .md files and llms.txt artifacts.
Before deploying, review their titles and content.
Configuration
All options are configured under the mdream key in nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@mdream/nuxt'],
mdream: {
enabled: true,
mdreamOptions: {
minimal: true,
origin: 'https://example.com',
filter: { exclude: ['header'] },
},
},
})
Module Options
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable or disable the module entirely. |
mdreamOptions |
Partial<MdreamOptions> |
{ minimal: true } |
Options passed to htmlToMarkdown. See below. |
mdreamOptions
These are passed directly to htmlToMarkdown from the mdream package.
An unknown key throws a TypeError when a page converts.
| Option | Type | Default | Description |
|---|---|---|---|
minimal |
boolean |
true |
Apply the minimal preset. It enables frontmatter, isolateMain, tailwind, filter, and clean. |
origin |
string |
Site URL from nuxt-site-config |
Origin URL for resolving relative image paths and internal links. |
clean |
boolean | CleanOptions |
undefined |
Clean up markdown output. Pass true for all cleanup or an object for specific features. |
frontmatter |
boolean | function | FrontmatterConfig |
undefined |
Extract frontmatter from the HTML <head>. |
isolateMain |
boolean |
undefined |
Isolate the main content area using semantic HTML. |
tailwind |
boolean |
undefined |
Convert Tailwind utility classes to semantic markdown. |
filter |
{ include?: string[], exclude?: string[], processChildren?: boolean } |
undefined |
Filter elements by tag name. |
extraction |
Record<string, (element) => void> |
undefined |
Extract elements matching CSS selectors during conversion. |
tagOverrides |
Record<string, TagOverride | string> |
undefined |
Override how specific HTML tags are converted. |
Usage
Content Negotiation
The middleware uses content negotiation to decide whether to serve markdown or HTML:
- Serves markdown when
text/markdownortext/plainranks above HTML in theAcceptheader. - Serves HTML for wildcard headers, missing headers, or browser navigation (
sec-fetch-dest: document).
Use the .md extension or explicitly request Markdown. Unsupported media types receive HTTP 406 on HTML routes.
Excluded Paths
The middleware skips these paths:
- Routes starting with
/api - Routes starting with
/_ - Routes starting with
/@ - Routes with file extensions other than
.md(e.g.,.js,.css,.json)
Robot Meta Tag Support
Pages with a noindex robots meta tag return a 404 when accessed as markdown:
<script setup lang="ts">
useHead({
meta: [
{ name: 'robots', content: 'noindex' }
]
})
</script>
Static Generation
When using nuxt generate or when nitro.prerender.routes is configured, the module automatically:
- Generates
.mdfiles alongside HTML for all prerendered pages. - Creates
llms.txtwith a page listing (uses site name and description fromnuxt-site-config). - Creates
llms-full.txtwith the full markdown content of all pages.
These files are written to the Nitro public output directory and served as static assets.
Hooks
Three Nitro runtime hooks (available in server plugins) and one Nuxt build hook (available in nuxt.config.ts).
mdream:config (Nitro)
Type: (options: MdreamOptions) => void | Promise<void>
Modify mdream options before HTML-to-Markdown conversion. Mutate the received object directly. The module adds its title and description extraction handlers after this hook, alongside your handlers.
// server/plugins/mdream-config.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('mdream:config', async (options) => {
options.filter = { exclude: ['nav', 'footer', 'aside'] }
options.origin = 'https://example.com'
})
})
mdream:negotiate (Nitro)
Type: (ctx: MdreamNegotiateContext) => void | Promise<void>
Override the content negotiation decision.
interface MdreamNegotiateContext {
event: H3Event
shouldServe: boolean
}
// server/plugins/mdream-negotiate.ts
import { getHeader, getRequestURL } from 'h3'
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('mdream:negotiate', async (ctx) => {
if (getHeader(ctx.event, 'x-force-markdown')) {
ctx.shouldServe = true
}
if (getRequestURL(ctx.event).pathname.startsWith('/admin')) {
ctx.shouldServe = false
}
})
})
mdream:markdown (Nitro)
Type: (ctx: MdreamMarkdownContext) => void | Promise<void>
Modify the generated markdown after conversion.
interface MdreamMarkdownContext {
html: string
markdown: string
route: string
title: string
description: string
isPrerender: boolean
event: H3Event
}
// server/plugins/mdream-markdown.ts
import { setHeader } from 'h3'
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('mdream:markdown', async (ctx) => {
ctx.markdown += '\n\n---\nGenerated with mdream'
setHeader(ctx.event, 'X-Markdown-Title', ctx.title)
})
})
mdream:llms-txt (Nuxt Build)
Type: (payload: MdreamLlmsTxtGeneratePayload) => void | Promise<void>
Modify llms.txt and llms-full.txt content before the module writes them to disk.
The hook runs once during prerendering, after all routes have been processed.
Mutate the payload properties directly.
interface MdreamLlmsTxtGeneratePayload {
content: string // llms.txt content
fullContent: string // llms-full.txt content
pages: ProcessedFile[] // All processed pages (read-only)
}
interface ProcessedFile {
filePath?: string
title: string
content: string
url: string
metadata?: {
title?: string
description?: string
keywords?: string
author?: string
}
}
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@mdream/nuxt'],
hooks: {
'mdream:llms-txt': async (payload) => {
payload.content += `\n\n## API\n\nSearch available at /api/search\n`
payload.fullContent += `\n\n## API Documentation\n\nDetailed docs here...\n`
},
},
})
Programmatic Usage
The module auto-imports htmlToMarkdown and streamHtmlToMarkdown for server routes.
These server utilities use your module's mdreamOptions as defaults.
It also auto-imports useHtmlToMarkdown for client components.
Pass options to the composable directly.
Server Routes
htmlToMarkdown and streamHtmlToMarkdown are auto-imported in all server routes. They wrap the mdream package with your module config pre-applied.
// server/api/convert.post.ts
export default defineEventHandler(async (event) => {
const { html } = await readBody(event)
// Uses module's mdreamOptions as defaults
return htmlToMarkdown(html)
})
Per-call options merge over module defaults:
// server/api/convert-custom.post.ts
export default defineEventHandler(async (event) => {
const { html } = await readBody(event)
return htmlToMarkdown(html, { origin: 'https://other.com', clean: true })
})
Streaming is also available:
// server/api/stream.post.ts
export default defineEventHandler(async (event) => {
const stream = getRequestWebStream(event) ?? null
const chunks = []
for await (const chunk of streamHtmlToMarkdown(stream)) {
chunks.push(chunk)
}
return chunks.join('')
})
Client Composable
useHtmlToMarkdown provides a reactive wrapper for client-side conversion (uses the WASM build automatically). The first argument accepts a string, a ref, or a getter. When the source changes, the markdown is re-converted automatically.
<script setup lang="ts">
const html = ref('<h1>Hello</h1>')
const { markdown, pending, error } = useHtmlToMarkdown(html)
</script>
<template>
<pre v-if="!pending">{{ markdown }}</pre>
</template>
On-demand conversion:
<script setup lang="ts">
const { markdown, pending, convert } = useHtmlToMarkdown()
async function onPaste(html: string) {
await convert(html, { origin: 'https://example.com' })
}
</script>
The composable returns:
| Property | Type | Description |
|---|---|---|
markdown |
Ref<string> |
The converted markdown output |
pending |
Ref<boolean> |
Whether a conversion is in progress |
error |
ShallowRef<Error | null> |
Error from the last conversion, if any |
convert |
(html?: string, options?: Partial<MdreamOptions>) => Promise<string> |
Trigger a conversion manually |
API Reference
Type Augmentation
The module generates type declarations for all hooks. TypeScript support works automatically in nuxt.config.ts and in Nitro plugins.
Augmented modules:
@nuxt/schema:RuntimeConfig.mdreamandNuxtHooks['mdream:llms-txt']nitropack/nitropack/types:NitroRuntimeHooksformdream:config,mdream:negotiate, andmdream:markdown
Exports
| Entry Point | Contents |
|---|---|
@mdream/nuxt |
The Nuxt module itself |
@mdream/nuxt/runtime/types |
MdreamMarkdownContext, MdreamNegotiateContext, MdreamLlmsTxtGeneratePayload, ModuleRuntimeConfig |
Auto-imported Server Utils
| Function | Signature | Description |
|---|---|---|
htmlToMarkdown |
(html: string, options?: Partial<MdreamOptions>) => string |
Convert HTML to markdown (sync, NAPI) |
streamHtmlToMarkdown |
(stream: ReadableStream, options?: Partial<MdreamOptions>) => AsyncIterable<string> |
Stream HTML to markdown |
Auto-imported Composables
| Composable | Description |
|---|---|
useHtmlToMarkdown |
Reactive HTML to markdown conversion (uses WASM on client) |
License
Version History
| Version | Released | License |
|---|---|---|
| 3.0.0 | MIT | |
| 2.0.1 | MIT | |
| 2.0.0 | MIT | |
| 1.7.2 | MIT | |
| 1.7.1 | MIT | |
| 1.7.0 | MIT | |
| 1.6.3 | MIT | |
| 1.6.2 | MIT | |
| 1.6.1 | MIT | |
| 1.6.0 | MIT | |
| 1.5.13 | MIT | |
| 1.5.12 | MIT | |
| 1.5.11 | MIT | |
| 1.5.10 | MIT | |
| 1.5.8 | MIT | |
| 1.5.7 | MIT | |
| 1.5.6 | MIT | |
| 1.5.5 | MIT | |
| 1.5.4 | MIT | |
| 1.5.3 | MIT | |
| 1.5.2 | MIT | |
| 1.4.1 | MIT | |
| 1.4.0 | MIT | |
| 1.3.0 | MIT | |
| 1.2.2 | MIT | |
| 1.2.1 | MIT | |
| 1.1.2 | MIT | |
| 1.1.1 | MIT | |
| 1.1.0 | MIT | |
| 1.0.7 | MIT |
Showing the latest 30 of 66. See every release on npm
Pre-releases (6)
| Version | Released | License |
|---|---|---|
| 2.0.0-beta.1 | MIT | |
| 1.0.0-beta.14 | MIT | |
| 1.0.0-beta.12 | MIT | |
| 1.0.0-beta.11 | MIT | |
| 1.0.0-beta.10 | MIT | |
| 1.0.0-beta.9 | MIT |