create-fumadocs-app 15.6.5 → 15.6.6

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.
@@ -59,7 +59,7 @@ async function tryGitInit(cwd2) {
59
59
  }
60
60
 
61
61
  // src/versions.js
62
- var versions = { "fumadocs-core": "15.6.5", "fumadocs-ui": "15.6.5", "fumadocs-mdx": "11.7.0", "@fumadocs/mdx-remote": "1.4.0", "@fumadocs/content-collections": "1.2.1" };
62
+ var versions = { "fumadocs-core": "15.6.6", "fumadocs-ui": "15.6.6", "fumadocs-mdx": "11.7.1", "@fumadocs/mdx-remote": "1.4.0", "@fumadocs/content-collections": "1.2.1" };
63
63
 
64
64
  // ../create-app-versions/package.json
65
65
  var package_default = {
@@ -72,25 +72,25 @@ var package_default = {
72
72
  "@content-collections/core": "^0.10.0",
73
73
  "@content-collections/mdx": "^0.2.2",
74
74
  "@content-collections/next": "^0.2.6",
75
- "@react-router/dev": "^7.7.0",
76
- "@react-router/node": "^7.7.0",
77
- "@react-router/serve": "^7.7.0",
75
+ "@react-router/dev": "^7.7.1",
76
+ "@react-router/node": "^7.7.1",
77
+ "@react-router/serve": "^7.7.1",
78
78
  "@tailwindcss/postcss": "^4.1.11",
79
79
  "@tailwindcss/vite": "^4.1.11",
80
- "@tanstack/react-router": "^1.128.8",
81
- "@tanstack/react-start": "^1.128.8",
80
+ "@tanstack/react-router": "^1.129.0",
81
+ "@tanstack/react-start": "^1.129.0",
82
82
  "@types/mdx": "^2.0.13",
83
- "@types/node": "24.0.15",
83
+ "@types/node": "24.1.0",
84
84
  "@types/react": "^19.1.8",
85
85
  "@types/react-dom": "^19.1.6",
86
86
  "@vitejs/plugin-react": "^4.7.0",
87
87
  "gray-matter": "^4.0.3",
88
88
  isbot: "^5.1.28",
89
- next: "15.4.2",
89
+ next: "15.4.4",
90
90
  postcss: "^8.5.6",
91
91
  react: "^19.1.0",
92
92
  "react-dom": "^19.1.0",
93
- "react-router": "^7.7.0",
93
+ "react-router": "^7.7.1",
94
94
  "react-router-devtools": "^5.0.6",
95
95
  shiki: "^3.8.1",
96
96
  tailwindcss: "^4.1.11",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  create,
3
3
  templates
4
- } from "./chunk-J4NXLHNR.js";
4
+ } from "./chunk-VLVSDHVS.js";
5
5
  export {
6
6
  create,
7
7
  templates
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  getPackageManager,
6
6
  managers,
7
7
  templates
8
- } from "./chunk-J4NXLHNR.js";
8
+ } from "./chunk-VLVSDHVS.js";
9
9
 
10
10
  // src/index.ts
11
11
  import fs from "fs/promises";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fumadocs-app",
3
- "version": "15.6.5",
3
+ "version": "15.6.6",
4
4
  "description": "Create a new documentation site with Fumadocs",
5
5
  "keywords": [
6
6
  "NextJs",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/cross-spawn": "^6.0.6",
31
- "@types/node": "24.0.15",
31
+ "@types/node": "24.1.0",
32
32
  "tinyglobby": "^0.2.14",
33
33
  "eslint-config-custom": "0.0.0",
34
34
  "tsconfig": "0.0.0"
@@ -7,36 +7,42 @@ import {
7
7
  DocsTitle,
8
8
  } from 'fumadocs-ui/page';
9
9
  import { source } from '@/source';
10
+ import { type PageTree } from 'fumadocs-core/server';
10
11
  import defaultMdxComponents from 'fumadocs-ui/mdx';
11
- import { executeMdxSync } from '@fumadocs/mdx-remote/client';
12
- import type { PageTree } from 'fumadocs-core/server';
13
- import { createCompiler } from '@fumadocs/mdx-remote';
14
- import * as path from 'node:path';
15
-
16
- const compiler = createCompiler({
17
- development: false,
18
- });
12
+ import { docs } from '../../source.generated';
13
+ import { toClientRenderer } from 'fumadocs-mdx/runtime/vite';
19
14
 
20
15
  export async function loader({ params }: Route.LoaderArgs) {
21
16
  const slugs = params['*'].split('/').filter((v) => v.length > 0);
22
17
  const page = source.getPage(slugs);
23
18
  if (!page) throw new Response('Not found', { status: 404 });
24
19
 
25
- const compiled = await compiler.compileFile({
26
- path: path.resolve('content/docs', page.path),
27
- value: page.data.content,
28
- });
29
-
30
20
  return {
31
- page,
32
- compiled: compiled.toString(),
21
+ path: page.path,
33
22
  tree: source.pageTree,
34
23
  };
35
24
  }
36
25
 
26
+ const renderer = toClientRenderer(
27
+ docs.doc,
28
+ ({ toc, default: Mdx, frontmatter }) => {
29
+ return (
30
+ <DocsPage toc={toc}>
31
+ <title>{frontmatter.title}</title>
32
+ <meta name="description" content={frontmatter.description} />
33
+ <DocsTitle>{frontmatter.title}</DocsTitle>
34
+ <DocsDescription>{frontmatter.description}</DocsDescription>
35
+ <DocsBody>
36
+ <Mdx components={{ ...defaultMdxComponents }} />
37
+ </DocsBody>
38
+ </DocsPage>
39
+ );
40
+ },
41
+ );
42
+
37
43
  export default function Page(props: Route.ComponentProps) {
38
- const { page, compiled, tree } = props.loaderData;
39
- const { default: Mdx, toc } = executeMdxSync(compiled);
44
+ const { tree, path } = props.loaderData;
45
+ const Content = renderer[path];
40
46
 
41
47
  return (
42
48
  <DocsLayout
@@ -45,15 +51,7 @@ export default function Page(props: Route.ComponentProps) {
45
51
  }}
46
52
  tree={tree as PageTree.Root}
47
53
  >
48
- <title>{page.data.title}</title>
49
- <meta name="description" content={page.data.description} />
50
- <DocsPage toc={toc}>
51
- <DocsTitle>{page.data.title}</DocsTitle>
52
- <DocsDescription>{page.data.description}</DocsDescription>
53
- <DocsBody>
54
- <Mdx components={defaultMdxComponents} />
55
- </DocsBody>
56
- </DocsPage>
54
+ <Content />
57
55
  </DocsLayout>
58
56
  );
59
57
  }
@@ -1,16 +1,9 @@
1
1
  import type { Route } from './+types/search';
2
- import { createSearchAPI } from 'fumadocs-core/search/server';
2
+ import { createFromSource } from 'fumadocs-core/search/server';
3
3
  import { source } from '@/source';
4
- import { structure } from 'fumadocs-core/mdx-plugins';
5
4
 
6
- const server = createSearchAPI('advanced', {
7
- indexes: source.getPages().map((page) => ({
8
- id: page.url,
9
- url: page.url,
10
- title: page.data.title ?? '',
11
- description: page.data.description,
12
- structuredData: structure(page.data.content),
13
- })),
5
+ const server = createFromSource(source, {
6
+ language: 'english',
14
7
  });
15
8
 
16
9
  export async function loader({ request }: Route.LoaderArgs) {
@@ -1,60 +1,7 @@
1
- import {
2
- loader,
3
- type MetaData,
4
- type PageData,
5
- type Source,
6
- type VirtualFile,
7
- } from 'fumadocs-core/source';
8
- import matter from 'gray-matter';
9
- import * as path from 'node:path';
10
-
11
- const files = Object.entries(
12
- import.meta.glob<true, 'raw'>('/content/docs/**/*', {
13
- eager: true,
14
- query: '?raw',
15
- import: 'default',
16
- }),
17
- );
18
-
19
- const virtualFiles: VirtualFile[] = files.flatMap(([file, content]) => {
20
- const ext = path.extname(file);
21
- const virtualPath = path.relative(
22
- 'content/docs',
23
- path.join(process.cwd(), file),
24
- );
25
-
26
- if (ext === '.mdx' || ext === '.md') {
27
- const parsed = matter(content);
28
-
29
- return {
30
- type: 'page',
31
- path: virtualPath,
32
- data: {
33
- ...parsed.data,
34
- content: parsed.content,
35
- },
36
- };
37
- }
38
-
39
- if (ext === '.json') {
40
- return {
41
- type: 'meta',
42
- path: virtualPath,
43
- data: JSON.parse(content),
44
- };
45
- }
46
-
47
- return [];
48
- });
1
+ import { loader } from 'fumadocs-core/source';
2
+ import { create, docs } from '../source.generated';
49
3
 
50
4
  export const source = loader({
51
- source: {
52
- files: virtualFiles,
53
- } as Source<{
54
- pageData: PageData & {
55
- content: string;
56
- };
57
- metaData: MetaData;
58
- }>,
5
+ source: await create.sourceAsync(docs.doc, docs.meta),
59
6
  baseUrl: '/docs',
60
7
  });
@@ -1,4 +1,5 @@
1
1
  {
2
+ "name": "example-react-router",
2
3
  "private": true,
3
4
  "type": "module",
4
5
  "scripts": {
@@ -8,28 +9,26 @@
8
9
  "typecheck": "react-router typegen && tsc"
9
10
  },
10
11
  "dependencies": {
11
- "@fumadocs/mdx-remote": "workspace:*",
12
- "@react-router/node": "^7.6.3",
13
- "@react-router/serve": "^7.6.3",
12
+ "@react-router/node": "^7.7.0",
13
+ "@react-router/serve": "^7.7.0",
14
14
  "fumadocs-core": "workspace:*",
15
+ "fumadocs-mdx": "workspace:*",
15
16
  "fumadocs-ui": "workspace:*",
16
- "gray-matter": "^4.0.3",
17
17
  "isbot": "^5.1.28",
18
18
  "react": "^19.1.0",
19
19
  "react-dom": "^19.1.0",
20
- "react-router": "^7.6.3",
21
- "shiki": "^3.8.0"
20
+ "react-router": "^7.7.0"
22
21
  },
23
22
  "devDependencies": {
24
- "@react-router/dev": "^7.6.3",
23
+ "@react-router/dev": "^7.7.0",
25
24
  "@tailwindcss/vite": "^4.1.11",
26
- "@types/node": "^24.0.13",
25
+ "@types/node": "^24.0.15",
27
26
  "@types/react": "^19.1.8",
28
27
  "@types/react-dom": "^19.1.6",
29
28
  "react-router-devtools": "^5.0.6",
30
29
  "tailwindcss": "^4.1.11",
31
30
  "typescript": "^5.8.3",
32
- "vite": "^7.0.4",
31
+ "vite": "^7.0.5",
33
32
  "vite-tsconfig-paths": "^5.1.4"
34
33
  }
35
34
  }
@@ -1,9 +1,5 @@
1
1
  import type { Config } from '@react-router/dev/config';
2
- import { source } from './app/source';
3
2
 
4
3
  export default {
5
4
  ssr: true,
6
- async prerender({ getStaticPaths }) {
7
- return [...getStaticPaths(), ...source.getPages().map((page) => page.url)];
8
- },
9
5
  } satisfies Config;
@@ -0,0 +1,7 @@
1
+ import { defineConfig, defineDocs } from 'fumadocs-mdx/config';
2
+
3
+ export const docs = defineDocs({
4
+ dir: 'content/docs',
5
+ });
6
+
7
+ export default defineConfig();
@@ -2,12 +2,9 @@ import { reactRouter } from '@react-router/dev/vite';
2
2
  import tailwindcss from '@tailwindcss/vite';
3
3
  import { defineConfig } from 'vite';
4
4
  import tsconfigPaths from 'vite-tsconfig-paths';
5
+ import mdx from 'fumadocs-mdx/vite';
6
+ import * as MdxConfig from './source.config';
5
7
 
6
8
  export default defineConfig({
7
- build: {
8
- rollupOptions: {
9
- external: ['shiki'],
10
- },
11
- },
12
- plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
9
+ plugins: [mdx(MdxConfig), tailwindcss(), reactRouter(), tsconfigPaths()],
13
10
  });
@@ -5,6 +5,8 @@ description: This is another page
5
5
 
6
6
  Hello World again!
7
7
 
8
+ ## Installation
9
+
8
10
  ```npm
9
11
  npm i fumadocs-core fumadocs-ui
10
12
  ```
@@ -1,4 +1,5 @@
1
1
  {
2
+ "name": "example-tanstack-start",
2
3
  "private": true,
3
4
  "sideEffects": false,
4
5
  "type": "module",
@@ -8,28 +9,26 @@
8
9
  "start": "node .output/server/index.mjs"
9
10
  },
10
11
  "dependencies": {
11
- "@fumadocs/mdx-remote": "workspace:*",
12
- "@tanstack/react-router": "^1.128.0",
13
- "@tanstack/react-router-devtools": "^1.128.0",
14
- "@tanstack/react-start": "^1.128.1",
12
+ "@tanstack/react-router": "^1.129.0",
13
+ "@tanstack/react-router-devtools": "^1.129.0",
14
+ "@tanstack/react-start": "^1.129.0",
15
15
  "fumadocs-core": "workspace:*",
16
+ "fumadocs-mdx": "workspace:*",
16
17
  "fumadocs-ui": "workspace:*",
17
- "gray-matter": "^4.0.3",
18
18
  "lucide-static": "^0.525.0",
19
- "react": "^19.1.0",
20
- "react-dom": "^19.1.0",
19
+ "react": "^19.0.0",
20
+ "react-dom": "^19.0.0",
21
21
  "tailwind-merge": "^3.3.1",
22
- "vite": "^7.0.5",
23
- "zod": "^4.0.5"
22
+ "vite": "^7.0.5"
24
23
  },
25
24
  "devDependencies": {
26
25
  "@tailwindcss/vite": "^4.1.11",
27
- "@types/node": "^24.0.14",
28
- "@types/react": "^19.1.8",
29
- "@types/react-dom": "^19.1.6",
30
- "@vitejs/plugin-react": "^4.6.0",
26
+ "@types/node": "^24.0.15",
27
+ "@types/react": "^19.0.8",
28
+ "@types/react-dom": "^19.0.3",
29
+ "@vitejs/plugin-react": "^4.7.0",
31
30
  "tailwindcss": "^4.1.11",
32
- "typescript": "^5.8.3",
31
+ "typescript": "^5.7.2",
33
32
  "vite-tsconfig-paths": "^5.1.4"
34
33
  }
35
34
  }
@@ -0,0 +1,7 @@
1
+ import { defineConfig, defineDocs } from 'fumadocs-mdx/config';
2
+
3
+ export const docs = defineDocs({
4
+ dir: 'content',
5
+ });
6
+
7
+ export default defineConfig();
@@ -1,59 +1,9 @@
1
- import {
2
- loader,
3
- type MetaData,
4
- type PageData,
5
- type Source,
6
- type VirtualFile,
7
- } from 'fumadocs-core/source';
8
- import matter from 'gray-matter';
9
- import * as path from 'node:path';
1
+ import { loader } from 'fumadocs-core/source';
10
2
  import * as icons from 'lucide-static';
11
-
12
- const files = Object.entries(
13
- import.meta.glob<true, 'raw'>('/content/**/*', {
14
- eager: true,
15
- query: '?raw',
16
- import: 'default',
17
- }),
18
- );
19
-
20
- const virtualFiles: VirtualFile[] = files.flatMap(([file, content]) => {
21
- const ext = path.extname(file);
22
- const virtualPath = path.relative('content', path.join(process.cwd(), file));
23
-
24
- if (ext === '.mdx' || ext === '.md') {
25
- const parsed = matter(content);
26
-
27
- return {
28
- type: 'page',
29
- path: virtualPath,
30
- data: {
31
- ...parsed.data,
32
- content: parsed.content,
33
- },
34
- };
35
- }
36
-
37
- if (ext === '.json') {
38
- return {
39
- type: 'meta',
40
- path: virtualPath,
41
- data: JSON.parse(content),
42
- };
43
- }
44
-
45
- return [];
46
- });
3
+ import { create, docs } from '../../source.generated';
47
4
 
48
5
  export const source = loader({
49
- source: {
50
- files: virtualFiles,
51
- } as Source<{
52
- pageData: PageData & {
53
- content: string;
54
- };
55
- metaData: MetaData;
56
- }>,
6
+ source: await create.sourceAsync(docs.doc, docs.meta),
57
7
  baseUrl: '/docs',
58
8
  // @ts-expect-error -- string
59
9
  icon(icon) {
@@ -1,6 +1,6 @@
1
1
  import { createRouter as createTanStackRouter } from '@tanstack/react-router';
2
2
  import { routeTree } from './routeTree.gen';
3
- import { NotFound } from './components/NotFound';
3
+ import { NotFound } from '~/components/not-found';
4
4
 
5
5
  export function createRouter() {
6
6
  return createTanStackRouter({
@@ -1,16 +1,8 @@
1
1
  import { createServerFileRoute } from '@tanstack/react-start/server';
2
- import { createSearchAPI } from 'fumadocs-core/search/server';
3
2
  import { source } from '~/lib/source';
4
- import { structure } from 'fumadocs-core/mdx-plugins';
3
+ import { createFromSource } from 'fumadocs-core/search/server';
5
4
 
6
- const server = createSearchAPI('advanced', {
7
- indexes: source.getPages().map((page) => ({
8
- id: page.url,
9
- url: page.url,
10
- title: page.data.title!,
11
- structuredData: structure(page.data.content),
12
- })),
13
- });
5
+ const server = createFromSource(source);
14
6
 
15
7
  export const ServerRoute = createServerFileRoute('/api/search').methods({
16
8
  GET: async ({ request }) => server.GET(request),
@@ -1,27 +1,25 @@
1
1
  import { createFileRoute, notFound } from '@tanstack/react-router';
2
- import { executeMdxSync } from '@fumadocs/mdx-remote/client';
3
2
  import { DocsLayout } from 'fumadocs-ui/layouts/docs';
3
+ import { createServerFn } from '@tanstack/react-start';
4
+ import { source } from '~/lib/source';
5
+ import type { PageTree } from 'fumadocs-core/server';
6
+ import { useMemo } from 'react';
7
+ import { docs } from '../../../source.generated';
4
8
  import {
5
9
  DocsBody,
6
10
  DocsDescription,
7
11
  DocsPage,
8
12
  DocsTitle,
9
13
  } from 'fumadocs-ui/page';
10
- import { createServerFn } from '@tanstack/react-start';
11
- import { createCompiler } from '@fumadocs/mdx-remote';
12
- import { source } from '~/lib/source';
13
- import path from 'node:path';
14
14
  import defaultMdxComponents from 'fumadocs-ui/mdx';
15
- import type { PageTree } from 'fumadocs-core/server';
16
- import { useMemo } from 'react';
17
-
18
- const compiler = createCompiler();
15
+ import { createClientLoader } from 'fumadocs-mdx/runtime/vite';
19
16
 
20
17
  export const Route = createFileRoute('/docs/$')({
21
18
  component: Page,
22
19
  loader: async ({ params }) => {
23
- const slugs = (params._splat ?? '').split('/');
24
- return loader({ data: slugs });
20
+ const data = await loader({ data: params._splat?.split('/') ?? [] });
21
+ await clientLoader.preload(data.path);
22
+ return data;
25
23
  },
26
24
  });
27
25
 
@@ -34,48 +32,38 @@ const loader = createServerFn({
34
32
  const page = source.getPage(slugs);
35
33
  if (!page) throw notFound();
36
34
 
37
- const { content, ...rest } = page.data;
38
- const compiled = await compiler.compileFile({
39
- path: path.resolve('content', page.path),
40
- value: content,
41
- });
42
-
43
35
  return {
44
36
  tree: source.pageTree as object,
45
- ...rest,
46
- compiled: compiled.toString(),
37
+ path: page.path,
47
38
  };
48
39
  });
49
40
 
41
+ const clientLoader = createClientLoader(docs.doc, {
42
+ id: 'docs',
43
+ component({ toc, frontmatter, default: MDX }) {
44
+ return (
45
+ <DocsPage toc={toc}>
46
+ <DocsTitle>{frontmatter.title}</DocsTitle>
47
+ <DocsDescription>{frontmatter.description}</DocsDescription>
48
+ <DocsBody>
49
+ <MDX
50
+ components={{
51
+ ...defaultMdxComponents,
52
+ }}
53
+ />
54
+ </DocsBody>
55
+ </DocsPage>
56
+ );
57
+ },
58
+ });
59
+
50
60
  function Page() {
51
61
  const data = Route.useLoaderData();
52
- const {
53
- default: MDX,
54
- toc,
55
- tree,
56
- } = useMemo(() => {
57
- const result = executeMdxSync(data.compiled);
58
-
59
- function traverse(folder: PageTree.Folder | PageTree.Root) {
60
- for (const node of folder.children) {
61
- if (node.type === 'page' && typeof node.icon === 'string') {
62
- node.icon = (
63
- <span
64
- dangerouslySetInnerHTML={{
65
- __html: node.icon,
66
- }}
67
- />
68
- );
69
- }
70
-
71
- if (node.type === 'folder') traverse(node);
72
- }
73
- }
74
-
75
- const tree = structuredClone(data.tree) as PageTree.Root;
76
- traverse(tree);
77
- return { ...result, tree };
78
- }, [data]);
62
+ const Content = clientLoader.getComponent(data.path);
63
+ const tree = useMemo(
64
+ () => transformPageTree(data.tree as PageTree.Folder),
65
+ [data.tree],
66
+ );
79
67
 
80
68
  return (
81
69
  <DocsLayout
@@ -84,17 +72,34 @@ function Page() {
84
72
  title: 'Fumadocs Tanstack',
85
73
  }}
86
74
  >
87
- <DocsPage toc={toc}>
88
- <DocsTitle>{data.title}</DocsTitle>
89
- <DocsDescription>{data.description}</DocsDescription>
90
- <DocsBody>
91
- <MDX
92
- components={{
93
- ...defaultMdxComponents,
94
- }}
95
- />
96
- </DocsBody>
97
- </DocsPage>
75
+ <Content />
98
76
  </DocsLayout>
99
77
  );
100
78
  }
79
+
80
+ function transformPageTree(tree: PageTree.Folder): PageTree.Folder {
81
+ function page(item: PageTree.Item) {
82
+ if (typeof item.icon !== 'string') return item;
83
+
84
+ return {
85
+ ...item,
86
+ icon: (
87
+ <span
88
+ dangerouslySetInnerHTML={{
89
+ __html: item.icon,
90
+ }}
91
+ />
92
+ ),
93
+ };
94
+ }
95
+
96
+ return {
97
+ ...tree,
98
+ index: tree.index ? page(tree.index) : undefined,
99
+ children: tree.children.map((item) => {
100
+ if (item.type === 'page') return page(item);
101
+ if (item.type === 'folder') return transformPageTree(item);
102
+ return item;
103
+ }),
104
+ };
105
+ }
@@ -1,14 +1,16 @@
1
+ import react from '@vitejs/plugin-react';
1
2
  import { tanstackStart } from '@tanstack/react-start/plugin/vite';
2
3
  import { defineConfig } from 'vite';
3
4
  import tsConfigPaths from 'vite-tsconfig-paths';
4
5
  import tailwindcss from '@tailwindcss/vite';
5
- import react from '@vitejs/plugin-react';
6
+ import mdx from 'fumadocs-mdx/vite';
6
7
 
7
8
  export default defineConfig({
8
9
  server: {
9
10
  port: 3000,
10
11
  },
11
12
  plugins: [
13
+ mdx(await import('./source.config')),
12
14
  tailwindcss(),
13
15
  tsConfigPaths({
14
16
  projects: ['./tsconfig.json'],