diff --git a/docs/site/components/examples-table.tsx b/docs/site/components/examples-table.tsx index 48888598e5591..20721acb8f35e 100644 --- a/docs/site/components/examples-table.tsx +++ b/docs/site/components/examples-table.tsx @@ -1,4 +1,55 @@ -import { EXAMPLES } from "@/example-data/examples"; +import fs from "node:fs"; +import path from "node:path"; +import { z } from "zod"; + +const ExampleMetaSchema = z + .object({ + slug: z.string(), + name: z.string(), + description: z.string(), + template: z.string().optional(), + maintainedByCoreTeam: z.boolean(), + }) + .strict(); + +type ExampleMeta = z.infer; + +// Collect metadata from each example +const EXAMPLES: ExampleMeta[] = []; + +// Get all directories in the examples folder +const examplesDir = path.join(process.cwd() + "../../../examples"); +const examples = fs + .readdirSync(examplesDir, { withFileTypes: true }) + .filter( + (dirent) => + dirent.isDirectory() && + !dirent.name.startsWith(".") && + dirent.name !== "node_modules" + ) + .filter((dirent) => dirent.name !== "with-nextjs") + // @ts-expect-error + .sort((a, b) => a.name - b.name) + .map((dirent) => dirent.name); + +for (const example of examples) { + const metaPath = path.join(examplesDir, example, "meta.json"); + + // Check if meta.json exists + if (fs.existsSync(metaPath)) { + try { + const metaContent = fs.readFileSync(metaPath, "utf8"); + const metaJson = JSON.parse(metaContent); + EXAMPLES.push({ ...metaJson, slug: example }); + } catch (error) { + // @ts-expect-error + throw new Error(error); + } + } +} + +// Validate examples against schema +z.array(ExampleMetaSchema).parse(EXAMPLES); export function ExamplesTable({ coreMaintained, @@ -6,7 +57,7 @@ export function ExamplesTable({ coreMaintained?: boolean; }): JSX.Element { return ( -
+
@@ -19,20 +70,22 @@ export function ExamplesTable({ coreMaintained ? meta.maintainedByCoreTeam : !meta.maintainedByCoreTeam - ).map((example) => ( - - - - - ))} + ).map((example) => { + return ( + + + + + ); + })}
- - {example.slug} - - {example.description}
+ + {example.name} + + {example.description}
diff --git a/docs/site/content/repo-docs/getting-started/examples.mdx b/docs/site/content/repo-docs/getting-started/examples.mdx index 2f3f8248a737f..8016451289bba 100644 --- a/docs/site/content/repo-docs/getting-started/examples.mdx +++ b/docs/site/content/repo-docs/getting-started/examples.mdx @@ -49,7 +49,7 @@ pnpm dlx create-turbo@latest --example [github-url] ## Core-maintained examples -This list is maintained by the Turborepo core team. Dependencies are kept as up-to-date as possible and GitHub Issues are accepted and addressed for these examples. +The following examples are maintained by the Turborepo core team. Dependencies are kept as up-to-date as possible and GitHub Issues are accepted and addressed for these examples. diff --git a/docs/site/example-data/examples.ts b/docs/site/example-data/examples.ts deleted file mode 100644 index 4bf9364aa68c0..0000000000000 --- a/docs/site/example-data/examples.ts +++ /dev/null @@ -1,150 +0,0 @@ -export interface Example { - slug: string; - name: string; - description: string; - template?: string; - featured?: boolean; - boost?: boolean; - maintainedByCoreTeam?: true; -} - -export const EXAMPLES: Example[] = [ - { - slug: "basic", - name: "Next.js", - description: "Minimal Turborepo example for learning the fundamentals.", - template: "https://vercel.com/templates/next.js/turborepo-next-basic", - featured: true, - boost: true, - maintainedByCoreTeam: true, - }, - { - slug: "design-system", - name: "Design System", - description: - "Unify your site's look and feel by sharing a design system across multiple apps.", - template: "https://vercel.com/templates/react/turborepo-design-system", - featured: true, - }, - { - slug: "kitchen-sink", - name: "Kitchen Sink", - description: - "Want to see a more in-depth example? Includes multiple frameworks, both frontend and backend.", - template: "https://vercel.com/templates/remix/turborepo-kitchensink", - featured: true, - maintainedByCoreTeam: true, - }, - { - slug: "non-monorepo", - name: "Non-Monorepo", - description: - "Example of using Turborepo in a single project without workspaces", - maintainedByCoreTeam: true, - }, - { - slug: "with-angular", - name: "Angular", - description: "Minimal Turborepo example using Angular.", - }, - { - slug: "with-berry", - name: "Yarn Berry", - description: "Minimal Turborepo example using Yarn Berry.", - }, - { - slug: "with-changesets", - name: "Monorepo with Changesets", - description: - "Simple Next.js monorepo preconfigured to publish packages via Changesets", - }, - { - slug: "with-docker", - name: "Docker", - description: - "Monorepo with an Express API and a Next.js App deployed with Docker utilizing turbo prune", - }, - { - slug: "with-gatsby", - name: "Gatsby.js", - description: - "Monorepo with a Gatsby.js and a Next.js app both sharing a UI Library", - template: "https://vercel.com/templates/gatsby/turborepo-gatsby-starter", - featured: true, - }, - { - slug: "with-nestjs", - name: "Nest.js", - description: "Minimal Turborepo example with Nest.js.", - featured: true, - boost: true, - }, - { - slug: "with-npm", - name: "npm package manager", - description: "Minimal Turborepoe example using npm as a package manager.", - }, - { - slug: "with-prisma", - name: "Prisma", - description: "Monorepo with a Next.js App fully configured with Prisma", - }, - { - slug: "with-react-native-web", - name: "React Native", - description: - "Simple React Native & Next.js monorepo with a shared UI library", - featured: true, - template: "https://vercel.com/templates/react/turborepo-design-system", - }, - { - slug: "with-rollup", - name: "Rollup", - description: - "Monorepo with a single Next.js app sharing a UI library bundled with Rollup", - }, - { - slug: "with-shell-commands", - name: "Turborepo only", - description: "A Turborepo-only monorepo.", - maintainedByCoreTeam: true, - }, - { - slug: "with-svelte", - name: "SvelteKit", - description: "Monorepo with multiple SvelteKit apps sharing a UI Library", - featured: true, - template: "https://vercel.com/templates/svelte/turborepo-sveltekit-starter", - boost: true, - maintainedByCoreTeam: true, - }, - { - slug: "with-tailwind", - name: "Tailwind CSS", - description: - "Monorepo with multiple Next.js apps sharing a UI Library all using Tailwind CSS with a shared config", - featured: true, - maintainedByCoreTeam: true, - }, - { - slug: "with-typeorm", - name: "TypeORM", - description: "Monorepo with TypeORM", - }, - { - slug: "with-vite", - name: "Vite", - description: - "Monorepo with multiple Vanilla JS apps bundled with Vite, sharing a UI Library", - }, - { - slug: "with-vue-nuxt", - name: "Vue/Nuxt", - description: "Monorepo with Vue and Nuxt, sharing a UI Library", - }, - { - slug: "with-yarn", - name: "Yarn package manager", - description: "Monorepo using Yarn 1 for package management", - }, -]; diff --git a/examples/basic/meta.json b/examples/basic/meta.json index 6fe74c6154b4f..3aacecdfa8709 100644 --- a/examples/basic/meta.json +++ b/examples/basic/meta.json @@ -1,3 +1,5 @@ { + "name": "Basic", + "description": "Basic monorepo example with two Next.js applications", "maintainedByCoreTeam": true } diff --git a/examples/design-system/meta.json b/examples/design-system/meta.json index 08f1bdc2b867b..06c2360c278d6 100644 --- a/examples/design-system/meta.json +++ b/examples/design-system/meta.json @@ -1,6 +1,6 @@ { "name": "Design System", - "description": "Unify your site's look and feel by sharing a design system across multiple apps.", + "description": "Unify your site's look and feel by sharing a design system across multiple apps", "template": "https://vercel.com/templates/react/turborepo-design-system", - "featured": true + "maintainedByCoreTeam": false } diff --git a/examples/kitchen-sink/meta.json b/examples/kitchen-sink/meta.json index e37d37aadf75c..e0f4846abaac9 100644 --- a/examples/kitchen-sink/meta.json +++ b/examples/kitchen-sink/meta.json @@ -1,7 +1,6 @@ { - "name": "Kitchen Sink", - "description": "Want to see a more in-depth example? Includes multiple frameworks, both frontend and backend.", + "name": "Kitchen sink", + "description": "Multiple frameworks, both frontend and backend", "template": "https://vercel.com/templates/remix/turborepo-kitchensink", - "featured": true, "maintainedByCoreTeam": true } diff --git a/examples/with-angular/meta.json b/examples/with-angular/meta.json index d3be701785ede..571a78a8a9770 100644 --- a/examples/with-angular/meta.json +++ b/examples/with-angular/meta.json @@ -1,4 +1,5 @@ { "name": "Angular", - "description": "Minimal Turborepo example for learning the fundamentals." + "description": "Minimal Turborepo example for learning the fundamentals", + "maintainedByCoreTeam": false } diff --git a/examples/with-berry/meta.json b/examples/with-berry/meta.json new file mode 100644 index 0000000000000..f29d687c2c3d7 --- /dev/null +++ b/examples/with-berry/meta.json @@ -0,0 +1,5 @@ +{ + "name": "Yarn Berry", + "description": "Monorepo example using Yarn Berry (Yarn 3)", + "maintainedByCoreTeam": false +} diff --git a/examples/with-changesets/meta.json b/examples/with-changesets/meta.json index d12ef0d07ba5f..64ed6d6cb0040 100644 --- a/examples/with-changesets/meta.json +++ b/examples/with-changesets/meta.json @@ -1,4 +1,5 @@ { - "name": "Monorepo with Changesets", - "description": "Simple Next.js monorepo preconfigured to publish packages via Changesets" + "name": "Changesets", + "description": "Configured to publish packages via Changesets", + "maintainedByCoreTeam": false } diff --git a/examples/with-docker/meta.json b/examples/with-docker/meta.json index f33cceaf7d915..6a5c83d15a5c2 100644 --- a/examples/with-docker/meta.json +++ b/examples/with-docker/meta.json @@ -1,4 +1,5 @@ { "name": "Docker", - "description": "Monorepo with an Express API and a Next.js App deployed with Docker utilizing turbo prune" + "description": "Monorepo with an Express API and a Next.js App deployed with Docker utilizing turbo prune", + "maintainedByCoreTeam": false } diff --git a/examples/with-gatsby/meta.json b/examples/with-gatsby/meta.json index a2bd2fd942d0d..b39b1b2d38c60 100644 --- a/examples/with-gatsby/meta.json +++ b/examples/with-gatsby/meta.json @@ -1,6 +1,6 @@ { - "name": "Gatsby.js", + "name": "Gatsby", "description": "Monorepo with a Gatsby.js and a Next.js app both sharing a UI Library", "template": "https://vercel.com/templates/gatsby/turborepo-gatsby-starter", - "featured": true + "maintainedByCoreTeam": false } diff --git a/examples/with-nestjs/meta.json b/examples/with-nestjs/meta.json index eff0c70a306d0..8a6f0ecd713e4 100644 --- a/examples/with-nestjs/meta.json +++ b/examples/with-nestjs/meta.json @@ -1,7 +1,5 @@ { - "name": "Next.js", - "description": "Minimal Turborepo example for learning the fundamentals.", - "template": "https://vercel.com/templates/next.js/turborepo-next-basic", - "featured": true, - "boost": true + "name": "Nest.js", + "description": "Monorepo with Nest.js", + "maintainedByCoreTeam": false } diff --git a/examples/with-nextjs/meta.json b/examples/with-nextjs/meta.json new file mode 100644 index 0000000000000..03dd01ac659a2 --- /dev/null +++ b/examples/with-nextjs/meta.json @@ -0,0 +1,5 @@ +{ + "name": "Next.js", + "description": "Monorepo example with Next.js applications", + "maintainedByCoreTeam": false +} diff --git a/examples/with-npm/meta.json b/examples/with-npm/meta.json new file mode 100644 index 0000000000000..ef6ef3fc5cdc4 --- /dev/null +++ b/examples/with-npm/meta.json @@ -0,0 +1,5 @@ +{ + "name": "npm workspaces", + "description": "Monorepo example using NPM workspaces", + "maintainedByCoreTeam": false +} diff --git a/examples/with-prisma/meta.json b/examples/with-prisma/meta.json index 3b1c34bebecaf..706350cf6f0a3 100644 --- a/examples/with-prisma/meta.json +++ b/examples/with-prisma/meta.json @@ -1,4 +1,5 @@ { "name": "Prisma", - "description": "Monorepo with a Next.js App fully configured with Prisma" + "description": "Monorepo with a Next.js App fully configured with Prisma", + "maintainedByCoreTeam": false } diff --git a/examples/with-react-native-web/meta.json b/examples/with-react-native-web/meta.json index 09070a994df6f..ffb4fe7a9a92c 100644 --- a/examples/with-react-native-web/meta.json +++ b/examples/with-react-native-web/meta.json @@ -1,6 +1,6 @@ { "name": "React Native", "description": "Simple React Native & Next.js monorepo with a shared UI library", - "featured": true, - "template": "https://vercel.com/templates/react/turborepo-design-system" + "template": "https://vercel.com/templates/react/turborepo-design-system", + "maintainedByCoreTeam": false } diff --git a/examples/with-rollup/meta.json b/examples/with-rollup/meta.json index 8f3a2476045e7..618e6cebb14cf 100644 --- a/examples/with-rollup/meta.json +++ b/examples/with-rollup/meta.json @@ -1,4 +1,5 @@ { "name": "Rollup", - "description": "Monorepo with a single Next.js app sharing a UI library bundled with Rollup" + "description": "Monorepo with a single Next.js app sharing a UI library bundled with Rollup", + "maintainedByCoreTeam": false } diff --git a/examples/with-shell-commands/meta.json b/examples/with-shell-commands/meta.json index 6fe74c6154b4f..a769a401cdffe 100644 --- a/examples/with-shell-commands/meta.json +++ b/examples/with-shell-commands/meta.json @@ -1,3 +1,5 @@ { + "name": "Shell commands", + "description": "A nearly empty Turborepo - useful for creating reproductions for GitHub Issues", "maintainedByCoreTeam": true } diff --git a/examples/with-solid/meta.json b/examples/with-solid/meta.json new file mode 100644 index 0000000000000..32b3eca6f08bb --- /dev/null +++ b/examples/with-solid/meta.json @@ -0,0 +1,5 @@ +{ + "name": "Solid.js", + "description": "Monorepo example with SolidJS applications", + "maintainedByCoreTeam": false +} diff --git a/examples/with-svelte/meta.json b/examples/with-svelte/meta.json index 883164b3d7623..3d6f7066a0aff 100644 --- a/examples/with-svelte/meta.json +++ b/examples/with-svelte/meta.json @@ -1,8 +1,6 @@ { "name": "SvelteKit", "description": "Monorepo with multiple SvelteKit apps sharing a UI Library", - "featured": true, "template": "https://vercel.com/templates/svelte/turborepo-sveltekit-starter", - "boost": true, "maintainedByCoreTeam": true } diff --git a/examples/with-tailwind/meta.json b/examples/with-tailwind/meta.json index 6a40dcd63abba..53cec4ae57116 100644 --- a/examples/with-tailwind/meta.json +++ b/examples/with-tailwind/meta.json @@ -1,6 +1,5 @@ { - "name": "Tailwind CSS", - "description": "Monorepo with multiple Next.js apps sharing a UI Library all using Tailwind CSS with a shared config", - "featured": true, + "name": "TailwindCSS", + "description": "Monorepo with multiple Next.js apps sharing a UI library built with TailwindCSS", "maintainedByCoreTeam": true } diff --git a/examples/with-typeorm/meta.json b/examples/with-typeorm/meta.json index 88ed293ced6e9..dd4b281a700dd 100644 --- a/examples/with-typeorm/meta.json +++ b/examples/with-typeorm/meta.json @@ -1,4 +1,5 @@ { "name": "typeorm", - "description": "Monorepo with a Next.js App fully configured with typeorm" + "description": "Monorepo with a Next.js App fully configured with typeorm", + "maintainedByCoreTeam": false } diff --git a/examples/with-vite-react/meta.json b/examples/with-vite-react/meta.json new file mode 100644 index 0000000000000..3a319c0ef307d --- /dev/null +++ b/examples/with-vite-react/meta.json @@ -0,0 +1,5 @@ +{ + "name": "Vite + React", + "description": "Monorepo example with Vite and React", + "maintainedByCoreTeam": false +} diff --git a/examples/with-vite/meta.json b/examples/with-vite/meta.json index 3432702d5fa60..69ed8725984d7 100644 --- a/examples/with-vite/meta.json +++ b/examples/with-vite/meta.json @@ -1,4 +1,5 @@ { "name": "Vite", - "description": "Monorepo with multiple Vanilla JS apps bundled with Vite, sharing a UI Library" + "description": "Monorepo with multiple Vanilla JS apps bundled with Vite, sharing a UI Library", + "maintainedByCoreTeam": false } diff --git a/examples/with-vitest/meta.json b/examples/with-vitest/meta.json new file mode 100644 index 0000000000000..7d9fddab68b46 --- /dev/null +++ b/examples/with-vitest/meta.json @@ -0,0 +1,5 @@ +{ + "name": "Vitest", + "description": "Monorepo example with Vitest for testing", + "maintainedByCoreTeam": false +} diff --git a/examples/with-vue-nuxt/meta.json b/examples/with-vue-nuxt/meta.json index da9d872e22bf7..dd31c8344507f 100644 --- a/examples/with-vue-nuxt/meta.json +++ b/examples/with-vue-nuxt/meta.json @@ -1,4 +1,5 @@ { "name": "Vue/Nuxt", - "description": "Monorepo with Vue and Nuxt, sharing a UI Library" + "description": "Monorepo with Vue and Nuxt, sharing a UI Library", + "maintainedByCoreTeam": false } diff --git a/examples/with-yarn/meta.json b/examples/with-yarn/meta.json new file mode 100644 index 0000000000000..91b4d457388ca --- /dev/null +++ b/examples/with-yarn/meta.json @@ -0,0 +1,5 @@ +{ + "name": "Yarn", + "description": "Monorepo example using Yarn workspaces", + "maintainedByCoreTeam": false +}