{content.frontmatter.title as string}
-{content.body}
+diff --git a/README.md b/README.md index 6cd3e9c..1043597 100644 --- a/README.md +++ b/README.md @@ -1,566 +1,348 @@ -# vite-plugin-flatwave-react +# 🌊 vite-plugin-flatwave-react -[](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) -[](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) -[](https://github.com/kamansoft/vite-plugin-flatwave-react/actions/workflows/ci.yml) -[](./LICENSE) +[](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) +[](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) +[](https://github.com/kamansoft/vite-plugin-flatwave-react/actions/workflows/ci.yml) +[](./LICENSE) +[](https://nodejs.org/en/about/releases/) +[](https://discord.gg/vite) -A Vite plugin that turns a directory of Markdown files into a **fully typed, i18n-aware, statically generated React site** — zero runtime dependencies, no MDX, no server required. - -At build time the plugin: - -- Scans `src/content/{locale}/*.md` and parses front-matter with [`gray-matter`](https://github.com/jonschlinkert/gray-matter) -- Validates required fields, duplicate IDs, slugs, and missing locale variants -- Exposes a **virtual module** (`virtual:flatwave/content`) with typed helper functions usable in any React component -- Generates locale-prefixed static HTML pages via `react-dom/server` -- Emits `sitemap.xml`, `robots.txt`, and `route-manifest.json` +> **Turn Markdown into a fully-typed, i18n-ready, static React site — zero runtime, no MDX, no server.** +> +> Works in **any Vite + React project**. Drop it in, point to your content folder, done. --- -## Table of Contents - -1. [Installation](#installation) -2. [Integration](#integration) - - [Adding the Plugin to Vite](#adding-the-plugin-to-vite) - - [Content Directory Layout](#content-directory-layout) - - [Frontmatter Schema](#frontmatter-schema) -3. [Features](#features) - - [Automatic Route Generation](#automatic-route-generation) - - [Virtual Module API](#virtual-module-api) - - [React Hooks](#react-hooks) - - [Static Site Generation (SSG)](#static-site-generation-ssg) - - [SSG Hook Phases](#ssg-hook-phases) - - [Custom Render Strategy](#custom-render-strategy) - - [SEO and Meta Tags](#seo-and-meta-tags) - - [Content Validation](#content-validation) - - [Standalone Validation CLI](#standalone-validation-cli) - - [Language Switcher](#language-switcher) - - [Hot Module Replacement](#hot-module-replacement) -4. [Docker-Based Development](#docker-based-development) -5. [Using the Plugin Before npm Publication](#using-the-plugin-before-npm-publication) -6. [Development Commands](#development-commands) -7. [Releases and Versioning](#releases-and-versioning) -8. [Documentation](#documentation) -9. [Contributing](#contributing) +## ✨ Why Flatwave? + +| Problem | Flatwave Solution | +| ------------------------------------ | ------------------------------------------------------------------------------------------------- | +| MDX locks you into custom components | **Pure Markdown** — use any React component via virtual module | +| i18n is an afterthought | **First-class i18n** — locale routes (`/en/about`, `/es/about`), auto hreflang, language switcher | +| TypeScript support is partial | **Fully typed** — virtual module + React hooks with full IntelliSense | +| SSG requires complex config | **Zero-config SSG** — static HTML at build, deploy to Netlify, Vercel, S3, GitHub Pages, Nginx | +| Content validation is manual | **Built-in validation** — catches missing fields, duplicate IDs, broken links at build time | --- -## Installation +## 🚀 Quick Start (30 seconds) ```bash +# 1. Install npm install @kamansoft/vite-plugin-flatwave-react -``` - -**Peer dependencies** (must be installed separately): - -```bash -npm install vite react react-dom -``` - -**Node.js ≥ 22.0.0** is required. - ---- -## Integration - -### Adding the Plugin to Vite - -```ts -// vite.config.ts +# 2. Add to vite.config.ts +import { flatwaveContent } from '@kamansoft/vite-plugin-flatwave-react'; import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import path from 'node:path'; -import { flatwaveContent } from '@kamansoft/vite-plugin-flatwave-react'; export default defineConfig({ plugins: [ react(), flatwaveContent({ - contentDir: path.resolve(__dirname, 'src/content'), // where .md files live - locales: ['es', 'pt'], // all supported locales - defaultLocale: 'es', // must be in locales[] - strictMissingLocales: false, // true → missing locale = build error - sitemap: { - hostname: 'https://example.com', // used in sitemap.xml and robots.txt - }, + contentDir: path.resolve(__dirname, 'src/content'), + locales: ['en', 'es'], + defaultLocale: 'en', }), ], }); -``` -### Content Directory Layout - -The plugin expects one sub-directory per locale inside `contentDir`: - -``` -src/ - content/ - es/ - index.md - about.md - program.md - pt/ - index.md - about.md - program.md -``` - -Each locale must mirror the same set of content IDs. Missing locale variants produce warnings (or errors with `strictMissingLocales: true`). - -### Frontmatter Schema - -Every `.md` file must include these **required fields**: - -```yaml +# 3. Create content +mkdir -p src/content/en +cat > src/content/en/index.md <<'EOF' --- -title: 'About Us' -slug: 'about' # URL segment — becomes /{locale}/about -id: 'about' # groups translations: same id across locales -public: true # false → excluded from routes, sitemap, manifest -description: 'Short description' -canonical: '/es/about' # optional, defaults to /{locale}/{slug} -robots: 'index, follow' -keywords: - - flatwave - - about -# SEO extras -og: - title: 'Custom OG Title' -twitter: - card: 'summary_large_image' -# JSON-LD structured data -jsonLd: - '@context': 'https://schema.org' - '@type': 'WebPage' -# Navigation hints -menu: 'main' -menu_position: 2 -# Any extra keys are preserved in attributes ---- -Markdown body here. GitHub-flavoured Markdown. No MDX in v1. -``` - -**All extra frontmatter keys** not in the baseline list are preserved in `attributes` and accessible via React hooks and the virtual module. - +title: 'Welcome' +slug: '' +id: 'home' +public: true +description: 'My first Flatwave page' --- +# Hello Flatwave! 🌊 -## Features +This is **pure Markdown** — no MDX, no custom components needed. +EOF -### Automatic Route Generation - -Every public `.md` file becomes a locale-prefixed route: - -| File | Route | -| --------------------------- | ------------- | -| `src/content/es/index.md` | `/es/` | -| `src/content/es/about.md` | `/es/about` | -| `src/content/pt/program.md` | `/pt/program` | - -The home page is detected when `slug` is `index` or empty (`/`). +# 4. Run dev server +npm run dev +``` -At build time, the plugin emits one `{locale}/{slug}/index.html` per route, making the output compatible with any static host (Nginx, Netlify, Vercel, S3, GitHub Pages). +Open `http://localhost:5173/en/` — your page is live with hot reload! 🎉 --- -### Virtual Module API - -Import the virtual module anywhere in your app: +## 🎯 Two Ways to Use It -```ts -import { - getContent, - getAllContent, - getRoutes, - getAlternatives, - getLocales, - getDefaultLocale, -} from 'virtual:flatwave/content'; - -// Get one content entry -const aboutEs = getContent('about', 'es'); +### Mode 1: Composable (Recommended for Existing React Apps) -// Get all routes for a locale -const esRoutes = getRoutes('es'); +Use the **virtual module hooks** + **components** in your existing React Router setup: -// Get alternative locale paths for a language switcher -const alternatives = getAlternatives('about', 'es'); -// → { pt: '/pt/about' } +```tsx +// src/pages/[id].tsx +import { getContent, getAlternatives } from 'virtual:flatwave/content'; +import { FlatwaveMDPageComponent } from '@kamansoft/vite-plugin-flatwave-react/react'; +import Layout from '../components/Layout'; -// Get all configured locales -const locales = getLocales(); // ['es', 'pt'] +export default function Page({ params }: { params: { id: string } }) { + const { id } = params; + const locale = import.meta.env.VITE_CURRENT_LOCALE || 'en'; -// Get the default locale -const defaultLocale = getDefaultLocale(); // 'es' -``` + const content = getContent(id, locale); + const alternatives = getAlternatives(id, locale); -**TypeScript declarations** are available via `virtual.d.ts` — add this to your `tsconfig.json`: + if (!content) return
Content not found
; + if (!post) return{content.body}
+