qwik-llms-txt
v0.2.0
Published
Vite plugin for Qwik City that auto-generates llms.txt and llms-full.txt from SSG pages
Downloads
656
Maintainers
Readme
qwik-llms-txt
Vite plugin for Qwik City that auto-generates llms.txt and llms-full.txt from your SSG pages, following the llmstxt.org standard.
What is llms.txt?
A proposed standard for websites to expose their content to LLMs in a structured way:
llms.txt— Index with page titles, URLs, and descriptionsllms-full.txt— Full content of every page in clean Markdown
Install
bun add -d qwik-llms-txt
# or
npm install -D qwik-llms-txtUsage
Add the plugin to your Qwik City adapter's Vite config:
// adapters/static/vite.config.ts
import { qwikLlmsTxt } from "qwik-llms-txt";
export default defineConfig({
plugins: [
// ... other plugins
qwikLlmsTxt({
origin: "https://example.com",
}),
],
});After bun run build, you'll find llms.txt and llms-full.txt in your dist/ directory.
Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| origin | string | required | Base URL of your site |
| title | string | from index.html | Site title |
| description | string | from index.html | Site description |
| outDir | string | "dist" | SSG output directory |
| exclude | string[] | [] | Route patterns to exclude (glob) |
| include | string[] | ["/**"] | Route patterns to include (glob) |
| wellKnown | boolean | false | Also generate .well-known/llms.txt |
| contentSelector | string | "main, article" | CSS selector for main content |
| stripSelectors | string[] | ["nav", "footer", ...] | Elements to remove before extraction |
| verbose | boolean | false | Log progress to console |
| sections | Record<string, SectionConfig> | {} | Per-section llms.txt generation |
| dynamicRoutes | () => Promise<ParsedPage[]> | — | Inject extra pages not in dist/ |
Output Example
llms.txt
# My Qwik Site
> A modern framework for building instant web apps
## Pages
- [Home](https://example.com/): Welcome to our site
- [Blog](https://example.com/blog/): Latest articles about web development
- [About](https://example.com/about/): Learn more about our teamllms-full.txt
# My Qwik Site
> A modern framework for building instant web apps
---
## Home
URL: https://example.com/
# Welcome to My Qwik Site
This is the homepage of our **amazing** site built with Qwik.
---
## Blog
URL: https://example.com/blog/
# Blog
## Getting Started with Qwik
Qwik is a new kind of framework that delivers instant loading.Sections
Generate a separate llms.txt (and optionally llms-full.txt) for each section of your site:
qwikLlmsTxt({
origin: "https://example.com",
sections: {
"/blog/": {
title: "Blog",
description: "Latest articles",
},
"/docs/": {
title: "Documentation",
description: "Guides and API reference",
fullTxt: false, // skip llms-full.txt for this section
},
},
})This generates dist/blog/llms.txt, dist/blog/llms-full.txt, and dist/docs/llms.txt — each containing only pages within that prefix. The global llms.txt still includes all pages.
Dynamic Routes
Inject pages that aren't pre-rendered in dist/ (SSR routes, CMS content, etc.):
qwikLlmsTxt({
origin: "https://example.com",
dynamicRoutes: async () => {
const res = await fetch("https://api.example.com/posts");
const posts = await res.json();
return posts.map(post => ({
path: `/blog/${post.slug}/`,
title: post.title,
description: post.excerpt,
content: post.content, // plain text or markdown
}));
},
})Dynamic pages are merged with static pages. If a route exists in both, the static version wins. If dynamicRoutes throws, the build continues with static pages only.
How It Works
- During Vite's
closeBundle, registers aprocess.on('beforeExit')hook - Qwik's SSG runs after Vite's bundle phase, writing HTML files to
dist/ - When the process is about to exit, the hook fires — all SSG pages exist
- Scans
dist/for all.htmlfiles - Parses each page to extract title, description, and content
- Converts content HTML to clean Markdown (strips nav, footer, scripts, etc.)
- Writes
llms.txt(index) andllms-full.txt(full content)
Programmatic Usage
You can also use generate() directly as a post-build step:
import { generate } from "qwik-llms-txt";
await generate({
origin: "https://example.com",
outDir: "dist",
});Deduplication
The plugin automatically prevents multiple executions per build. Qwik's build process can trigger the beforeExit hook more than once — the plugin detects this and only runs generation once. If options change (e.g. in watch mode), it re-runs automatically.
License
MIT
