@next-library/core
v1.0.24
Published
Core functionality for Next.js documentation framework
Maintainers
Readme
@next-library/core
Core functionality for a Next.js documentation framework. This package provides utilities, content management, and processing logic without any UI components.
Looking for a complete solution? Check out
@next-library/themewhich includes ready-made UI components built on top of this core package.
Features
- 🌍 Multi-language Support - Built-in i18n with 20+ languages and RTL support
- 📝 Markdown Processing - Rich markdown processing with syntax highlighting, math, and diagrams
- 🗂️ GitHub Integration - Fetch and manage documentation from GitHub repositories
- ⚡ SEO Utilities - Automatic metadata, structured data generation
- 🔧 Content Management - Content tree generation, path utilities, navigation helpers
- 🎯 Type-Safe - Full TypeScript support with comprehensive types
Installation
# Using npm
npm install @next-library/core
# Using pnpm
pnpm add @next-library/core
# Using yarn
yarn add @next-library/coreQuick Start
1. Create Configuration File
Create a shared configuration file lib/library-config.ts:
// lib/library-config.ts
import { createConfig } from '@next-library/core';
export const libraryConfig = createConfig({
content: {
github: {
user: 'your-username',
repo: 'your-docs-repo', // Your documentation repository
branch: 'main',
token: process.env.GITHUB_TOKEN, // Optional, for private repos
docsPath: '', // Empty if content is at root of the repo
},
},
i18n: {
defaultLocale: 'en', // Locales are automatically detected from your GitHub repository structure
},
seo: {
siteName: 'My Documentation',
siteDescription: 'Comprehensive documentation for my project',
siteUrl: 'https://docs.example.com',
},
});2. Configure Next.js
Update your next.config.ts to use the shared config:
// next.config.ts
import type { NextConfig } from 'next';
import { withLibrary } from '@next-library/core/next';
import { libraryConfig } from './lib/library-config';
const nextConfig: NextConfig = {
// Your Next.js configuration
};
export default withLibrary(libraryConfig)(nextConfig);3. Use Core Utilities
The core package provides utilities for content management, i18n, and SEO. For UI components, see @next-library/theme.
// app/[lang]/docs/[[...slug]]/page.tsx
import {
extractPageData,
generatePageMetadata,
fetchRawFileContent
} from '@next-library/core';
import { MarkdownRenderer } from '@next-library/theme/client';
import type { Metadata } from 'next';
export async function generateMetadata({ params }): Promise<Metadata> {
const { lang, slug } = await params;
const pageData = extractPageData(lang, slug || []);
return generatePageMetadata({
title: pageData.node?.title || 'Documentation',
description: pageData.node?.frontmatter?.description as string,
lang,
});
}
export default async function DocPage({ params }) {
const { lang, slug } = await params;
const pageData = extractPageData(lang, slug || []);
const { node } = pageData;
if (!node) {
return <div>Page not found</div>;
}
// Fetch markdown content from GitHub
const markdown = await fetchRawFileContent(node.githubPath!);
// Use theme package components for rendering
return (
<div>
<h1>{node.title}</h1>
<MarkdownRenderer markdown={markdown} />
</div>
);
}How It Works
The core package follows a two-phase architecture: build-time tree generation and runtime data extraction.
Architecture Overview
graph TB
subgraph "Build Time"
A[GitHub Repository] -->|Webpack Plugin| B[generateContentTree]
B -->|Fetch Files| C[GitHub API]
C -->|Process Files| D[Build Tree Structure]
D -->|Extract Metadata| E[tree.json]
E -->|Store| F[.next/cache/library/tree.json]
end
subgraph "Runtime - Page Request"
G[User Request /en/docs/getting-started] -->|Extract Params| H[extractPageData]
H -->|Load| I[tree.json]
I -->|Parse| J[ContentTree + FlatMap]
J -->|Extract| K[PageData]
K -->|Contains| L[Node, Sidebar, Breadcrumbs, Navigation]
end
subgraph "Content Fetching"
M[PageData.node.githubPath] -->|fetchRawFileContent| N[GitHub API]
N -->|Return| O[Raw Markdown]
O -->|Process| P[Markdown Renderer]
end
subgraph "SEO & Metadata"
K -->|Generate| Q[generatePageMetadata]
K -->|Generate| R[generateArticleSchema]
K -->|Generate| S[generateBreadcrumbSchema]
end
F -.->|Used at Runtime| I
K -->|Provides Data| T[Your UI Components]
P -->|Renders| T
Q -->|Provides| U[Next.js Metadata]
R -->|Provides| V[JSON-LD Structured Data]
S -->|Provides| VBuild-Time Flow
Tree Generation (during
next buildor dev server start):- Webpack plugin (
LibraryTreePlugin) triggersgenerateContentTree() - Fetches repository file tree from GitHub API
- Processes all markdown files concurrently
- Extracts frontmatter, TOC, and metadata
- Builds nested tree structure organized by language
- Adds fallback nodes for missing translations
- Writes
tree.jsonto.next/cache/library/tree.json
- Webpack plugin (
Tree Structure:
- Organized by locale (e.g.,
en,fr,de) - Each locale contains nested folder/file structure
- Includes metadata: title, description, GitHub path, contributors, etc.
- Organized by locale (e.g.,
Runtime Flow
Page Request:
- User visits
/[locale]/docs/[...slug] - Next.js extracts
localeandslugfrom URL params
- User visits
Data Extraction:
extractPageData(locale, slug)is called- Loads
tree.jsonfrom cache (only once, cached in memory) - Builds flat map for fast lookups
- Traverses tree to extract:
- Current page node
- Sidebar navigation (current level, parent, grandparent)
- Breadcrumbs
- Previous/next page navigation
- TOC and contributors (from right sidebar data)
Content Fetching:
- Uses
fetchRawFileContent()to get markdown from GitHub - Returns raw markdown content
- Your UI components (or theme package) handle rendering
- Uses
SEO Generation:
generatePageMetadata()creates Next.js metadatagenerateArticleSchema()creates Article JSON-LDgenerateBreadcrumbSchema()creates BreadcrumbList JSON-LD- All based on PageData and configuration
Data Structures
ContentTree (from tree.json):
{
"en": {
"getting-started": {
"type": "folder",
"children": {
"installation": {
"type": "file",
"title": "Installation",
"githubPath": "getting-started/installation.md",
// ... more metadata
}
}
}
},
"fr": { /* French content */ }
}PageData (returned by extractPageData()):
{
node: ContentNode | null, // Current page
sidebar: { // Left sidebar navigation
items: SidebarNode[],
parent: SidebarNode | null,
grandparent: SidebarNode | null,
currentLevel: number
},
navigation: { // Navigation helpers
breadcrumbs: BreadcrumbItem[],
previous: FlatContentMapItem | null,
next: FlatContentMapItem | null
},
rightSidebar: { // Right sidebar data
toc: TOCItem[],
contributors: Contributor[],
githubPath?: string
},
computed: { // Computed metadata
path: string,
isFolderView: boolean,
lang: Locale,
isFallback?: boolean
}
}Key Design Decisions
- Build-time generation: Tree is generated once at build time, not on every request
- In-memory caching: Tree and flat map are cached after first load
- Optimized traversal: Single pass through tree extracts all needed data
- Flat map for navigation: Fast O(1) lookups for previous/next pages
- Language detection: Automatically detects locales from repository structure
- Fallback support: Shows English content when translation is missing
Configuration
Full Configuration Options
import { createConfig } from '@next-library/core';
const config = createConfig({
// Content Configuration
content: {
// GitHub repository configuration
github: {
user: 'your-username',
repo: 'your-repo',
branch: 'main',
token: process.env.GITHUB_TOKEN, // Optional, required for private repos
docsPath: 'docs', // Path to docs in your repository
},
},
// Internationalization
i18n: {
// Default locale (fallback when content is not available in requested locale)
defaultLocale: 'en',
// Locales are automatically detected from your GitHub repository structure
// The library scans your repository and finds all locale directories
// (e.g., root for English, i18n/fr/, i18n/de/) and uses them automatically
// Optional: Custom locale configurations for display names, flags, etc.
localeConfig: {
'en': {
name: 'English',
nativeName: 'English',
direction: 'ltr',
flag: '🇺🇸',
},
// Add custom configs for locales found in your content
// ... more locales
},
},
// SEO Configuration
seo: {
siteName: 'My Documentation',
siteDescription: 'Documentation for my project',
siteUrl: 'https://docs.example.com',
// Optional: Organization info
organization: {
name: 'My Organization',
logo: 'https://example.com/logo.png',
},
},
// Website Configuration (for SEO and structured data)
website: {
title: 'My Documentation',
description: 'Documentation for my project',
siteUrl: 'https://docs.example.com',
organizationName: 'My Organization',
organizationLogo: 'https://example.com/logo.png',
},
});Content Management
GitHub Repository Structure
Your documentation should be organized in a separate GitHub repository (different from your Next.js application repository) like this:
your-docs-repo/ # Separate repository for documentation content
├── getting-started.md # English content at root level
├── guides/
│ ├── index.md
│ └── advanced.md
├── api/
│ └── reference.md
└── i18n/ # Other languages in i18n folder
├── fr/
│ ├── getting-started.md
│ ├── guides/
│ │ ├── index.md
│ │ └── advanced.md
│ └── api/
│ └── reference.md
└── de/
└── ... (same structure with same folder and file names)Note:
- English content is placed at the root level of the repository
- Other languages are organized in the
i18nfolder with the same folder structure and file names - The documentation repository is separate from your Next.js application repository
Note: UI components are available in
@next-library/theme. This core package focuses on utilities and functionality.
Utilities
Content Utilities
import {
loadContentTree,
extractPageData,
generateStaticContentPaths,
getBreadcrumbs,
getSiblingPages,
getContentMetadataBySlug,
} from '@next-library/core';
// Load the content structure (automatically indexed from your GitHub repo)
const tree = loadContentTree();
// Get page data for rendering
const pageData = extractPageData('en', ['getting-started', 'installation']);
// Get all paths for static generation
const paths = generateStaticContentPaths();
// Get breadcrumbs
const breadcrumbs = getBreadcrumbs('getting-started/installation', 'en');
// Get sibling pages
const siblings = getSiblingPages('getting-started/installation', 'en');
// Get content metadata by slug
const metadata = getContentMetadataBySlug(['getting-started', 'installation'], 'en');i18n Utilities
import {
isValidLocale,
isLocaleEnabled,
getTextDirection,
getLocaleMetadata,
isRightToLeft,
getSupportedLocales,
} from '@next-library/core';
// Check if locale is valid
isValidLocale('en'); // true
// Check if locale is enabled (available in content tree)
isLocaleEnabled('en'); // true
// Get text direction
getTextDirection('ar'); // 'rtl'
// Get locale metadata
const metadata = getLocaleMetadata('fr');
// { name: 'French', nativeName: 'Français', direction: 'ltr', ... }
// Check if RTL
isRightToLeft('he'); // true
// Get all supported locales (from content tree)
const locales = getSupportedLocales();SEO Utilities
import {
generatePageMetadata,
generateArticleSchema,
generateBreadcrumbSchema,
} from '@next-library/core';
// Generate Next.js metadata
const metadata = generatePageMetadata({
title: 'Getting Started',
description: 'Learn how to get started',
lang: 'en',
});
// Generate structured data
const articleSchema = generateArticleSchema({
title: 'Getting Started',
description: 'Learn how to get started',
url: '/en/docs/getting-started',
author: 'John Doe',
publishedTime: '2024-01-01',
}, 'https://docs.example.com', 'My Organization');
const breadcrumbSchema = generateBreadcrumbSchema([
{ label: 'Home', href: '/' },
{ label: 'Docs', href: '/docs' },
{ label: 'Getting Started', href: '/docs/getting-started' },
], 'https://docs.example.com');Hooks
import { useLocale } from '@next-library/core/hooks';
function MyComponent() {
const { locale, setLocale, isLoading } = useLocale();
return <div>Current locale: {locale}</div>;
}Note: Hooks must be imported from @next-library/core/hooks and used in client components (with 'use client' directive).
Static Generation
Generate Static Params
// app/[lang]/docs/[[...slug]]/page.tsx
import { generateStaticContentPaths } from '@next-library/core';
export async function generateStaticParams() {
// Generate only for default locale at build time
const paths = generateStaticContentPaths()
.filter(path => path.lang === 'en');
return paths.map(path => ({
locale: path.lang,
slug: path.slug,
}));
}
// Enable ISR for other languages
export const dynamicParams = true;
export const revalidate = false;Customization
Custom Markdown Processing
import { processMarkdown } from '@next-library/core';
const processed = await processMarkdown(markdownContent, {
allowHtml: true,
allowMath: true,
syntaxHighlighting: true,
sanitize: true,
cacheEnabled: true,
});
// Result contains:
// - processed.content: string
// - processed.toc: TableOfContentsItem[]GitHub Integration
Fetching Content from GitHub
import { fetchRawFileContent } from '@next-library/core';
import { getConfig } from '@next-library/core';
// In your page component
const config = getConfig();
const markdown = await fetchRawFileContent(
'docs/en/getting-started.md',
{
user: config?.github?.user || 'your-username',
repo: config?.github?.repo || 'your-repo',
branch: config?.github?.branch || 'main',
token: config?.github?.token || process.env.GITHUB_TOKEN,
}
);Note: GitHub UI components (GithubStar, GithubContributors) are available in
@next-library/theme.
Detailed Flow
For a visual overview, see the Architecture Overview section above. Here's a detailed step-by-step breakdown:
PageData Structure
The extractPageData() function returns a comprehensive data object:
interface PageData {
// The current page node
node: ContentNode | null;
// Sidebar navigation
sidebar: {
items: SidebarNode[]; // Current level items
parent: SidebarNode | null; // Parent section
grandparent: SidebarNode | null;
currentLevel: number;
};
// Navigation helpers
navigation: {
breadcrumbs: BreadcrumbItem[];
previous: FlatContentMapItem | null;
next: FlatContentMapItem | null;
};
// Right sidebar data
rightSidebar: {
toc: TOCItem[];
contributors: Contributor[];
githubPath?: string;
};
// Computed metadata
computed: {
path: string;
isFolderView: boolean;
lang: Locale;
isFallback?: boolean;
};
}Routing Logic
The library uses Next.js App Router with catch-all routes:
- Route:
app/[lang]/docs/[[...slug]]/page.tsx - URL:
/en/docs/getting-started/installation - Params:
{ lang: 'en', slug: ['getting-started', 'installation'] }
The library:
- Validates the locale
- Falls back to default locale if invalid
- Looks up content in the tree
- Handles folder views (index pages)
- Supports fallback content (showing English when translation missing)
Static Generation Strategy
// Generate only default locale at build time (faster builds)
export async function generateStaticParams() {
const paths = generateStaticContentPaths()
.filter(path => path.lang === 'en');
return paths.map(path => ({
locale: path.lang,
slug: path.slug,
}));
}
// Enable ISR for other languages (on-demand generation)
export const dynamicParams = true;
export const revalidate = false;This strategy:
- ✅ Fast builds (only English pages pre-rendered)
- ✅ SEO optimized (English pages are static)
- ✅ Scalable (other languages generated on-demand)
- ✅ Cached indefinitely (content doesn't change)
Internationalization Flow
Locale Detection
- Automatically detects available locales from your GitHub repository structure
- Scans repository for locale directories (root for English,
i18n/fr/,i18n/de/, etc.) - Checks URL parameter
[lang]to determine requested locale - Falls back to default locale if requested locale is invalid or unavailable
- Validates against detected locales from repository structure
Content Resolution
- Looks for content in requested locale
- Falls back to default locale if missing
- Marks fallback content with
isFallback: true
UI Localization
- Apply RTL/LTR direction using
getTextDirection(locale)utility - Use theme package components which handle localization automatically
- Theme package includes translations for 20+ languages
- Apply RTL/LTR direction using
Markdown Processing Pipeline
Raw Markdown
↓
Frontmatter Extraction
↓
Remark Plugins
├─> remark-frontmatter
├─> remark-gfm (GitHub Flavored Markdown)
├─> remark-math
└─> remark-github
↓
Rehype Plugins
├─> rehype-raw (HTML support)
├─> rehype-slug (heading IDs)
├─> rehype-autolink-headings
├─> rehype-highlight (syntax highlighting)
├─> rehype-mermaid (diagrams)
└─> rehype-sanitize (security)
↓
HTML Output
↓
TOC Generation
↓
Final RenderAdvanced Usage
Proxy for Locale Detection (Next.js 15+)
For Next.js 15+, use the proxy convention:
// proxy.ts
import { handleLocaleRequest } from '@next-library/core/lib/i18n';
import type { NextRequest } from 'next/server';
export async function proxy(request: NextRequest) {
return handleLocaleRequest(request);
}Note: Locales are automatically detected from your GitHub repository structure. No need to manually specify them.
TypeScript Support
The library is fully typed. Import types as needed:
import type {
LibraryConfig,
ContentTree,
ContentNode,
PageData,
Locale,
} from '@next-library/core';Examples
Basic Documentation Site
// app/[lang]/docs/[[...slug]]/page.tsx
import { extractPageData, fetchRawFileContent } from '@next-library/core';
import { MarkdownRenderer } from '@next-library/theme/client';
import { notFound } from 'next/navigation';
export default async function DocPage({ params }) {
const { lang, slug } = await params;
const pageData = extractPageData(lang, slug || []);
if (!pageData.node) {
notFound();
}
const markdown = await fetchRawFileContent(pageData.node.githubPath!);
return <MarkdownRenderer markdown={markdown} />;
}With Theme Package Layout
// app/[lang]/docs/[[...slug]]/layout.tsx
import { LeftSidebar, RightSidebar } from '@next-library/theme/server';
import { Breadcrumbs } from '@next-library/theme/client';
import { extractPageData } from '@next-library/core';
export default async function DocsLayout({ children, params }) {
const { lang, slug } = await params;
const pageData = extractPageData(lang, slug || []);
return (
<div className="flex">
<LeftSidebar data={pageData} />
<main>
<Breadcrumbs data={pageData} locale={lang} />
{children}
</main>
<RightSidebar data={pageData} />
</div>
);
}Note: For complete UI components, see @next-library/theme.
API Reference
See the full API documentation for detailed information about all exported functions, components, and types.
Contributing
Contributions are welcome! Please see our contributing guide for details.
License
MIT
