Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

241 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Monorepo

A modern monorepo built with Turborepo, pnpm workspaces, and Next.js 16, following individual package architecture for optimal build caching and performance.

๐Ÿ“ Structure

website/
โ”œโ”€โ”€ apps/
โ”‚   โ””โ”€โ”€ web/                          # Next.js 16 app with App Router
โ”‚       โ””โ”€โ”€ content/                  # MDX content (blog, projects)
โ”œโ”€โ”€ configs/
โ”‚   โ”œโ”€โ”€ eslint/                       # Shared ESLint configs (base, Next.js, React library)
โ”‚   โ”œโ”€โ”€ prettier/                     # Shared Prettier config with Tailwind plugin
โ”‚   โ”œโ”€โ”€ tailwind/                     # Shared Tailwind config with design tokens
โ”‚   โ”œโ”€โ”€ typescript/                   # Shared TypeScript configs
โ”‚   โ””โ”€โ”€ vitest/                       # Shared Vitest configs (base, React)
โ””โ”€โ”€ packages/
    โ”œโ”€โ”€ components/
    โ”‚   โ”œโ”€โ”€ design-system/
    โ”‚   โ”‚   โ””โ”€โ”€ button/               # components.design-system.button
    โ”‚   โ””โ”€โ”€ layout/
    โ”‚       โ”œโ”€โ”€ header/               # components.layout.header
    โ”‚       โ””โ”€โ”€ footer/               # components.layout.footer
    โ”œโ”€โ”€ pages/
    โ”‚   โ”œโ”€โ”€ home/                     # pages.home
    โ”‚   โ”œโ”€โ”€ about/                    # pages.about
    โ”‚   โ”œโ”€โ”€ blog-list/                # pages.blog-list
    โ”‚   โ””โ”€โ”€ blog-post/                # pages.blog-post
    โ””โ”€โ”€ utils/
        โ””โ”€โ”€ core/
            โ”œโ”€โ”€ cn/                   # utils.core.cn
            โ””โ”€โ”€ format/               # utils.core.format

๐ŸŽฏ Package Architecture

Individual Packages

Each component, utility, and page is its own package for optimal Turborepo performance:

  • Granular caching - Only rebuild packages that changed
  • Better parallelization - Independent packages build in parallel
  • Precise cache invalidation - Unchanged packages stay cached

Naming Convention

Packages follow dot notation matching their folder hierarchy:

Folder Path Package Name
packages/components/design-system/button/ components.design-system.button
packages/utils/core/cn/ utils.core.cn
packages/pages/home/ pages.home

๐Ÿš€ Getting Started

Prerequisites

  • Node.js 22.x (see .nvmrc)
  • pnpm 9.x
# Use correct Node version
nvm use

# Install pnpm if needed
npm install -g pnpm

Installation

# Install all dependencies
pnpm install

# Start development server
pnpm dev

# Build all packages and apps
pnpm build

# Type check all packages
pnpm typecheck

# Lint all packages
pnpm lint

# Run tests
pnpm test

# Format code
pnpm format

๐Ÿ›  Tech Stack

Core

  • Build System: Turborepo 2.x with remote caching support
  • Package Manager: pnpm 9.x with workspaces and catalogs
  • Framework: Next.js 16 with App Router and Turbopack
  • Language: TypeScript 5.7 with strict mode
  • Styling: Tailwind CSS 3.4 with design system tokens
  • Content: Velite for type-safe MDX content collections

Code Quality

  • Testing: Vitest with React Testing Library
  • Linting: ESLint 9 with flat config format
  • Formatting: Prettier 3.x with Tailwind CSS plugin
  • CI/CD: GitHub Actions for automated checks

Design System

  • CSS variables for light/dark mode theming
  • Theme toggle with system preference detection via next-themes
  • Consistent border radius tokens
  • shadcn/ui compatible color scheme
  • lucide-react icons throughout the UI

๐Ÿ“ Content Management

The web app uses Velite for type-safe content collections, enabling MDX authoring with full TypeScript support.

Content Location

Content files live in apps/web/content/:

apps/web/content/
โ”œโ”€โ”€ blog/           # Blog posts
โ”‚   โ””โ”€โ”€ *.mdx
โ”œโ”€โ”€ changelog/      # Site changelog entries
โ”‚   โ””โ”€โ”€ *.mdx
โ””โ”€โ”€ projects/       # Project showcases
    โ””โ”€โ”€ *.mdx

Content Collections

Blog Posts

Create a new file in apps/web/content/blog/:

---
title: My Post Title
description: A brief description of the post
date: 2025-01-26
tags:
  - example
  - tutorial
draft: false        # Set to true to hide from production
---

Your MDX content here...

Projects

Create a new file in apps/web/content/projects/:

---
title: Project Name
description: What the project does
url: https://example.com          # Live URL (optional)
repo: https://github.com/...      # Repository URL (optional)
tech:
  - Next.js
  - TypeScript
featured: true      # Highlight on homepage
order: 1            # Sort order for featured projects
---

Project description and details...

Changelog

Create a new file in apps/web/content/changelog/:

---
version: "0.1.0"
date: 2025-01-26
title: Initial Release
description: First release with core features    # Optional
breaking: false     # Mark breaking changes
tags:
  - feature         # feature, fix, improvement, breaking, docs
---

Release notes and changes...

Using Content in Code

Import content collections via the #content alias:

import { blog, projects, changelog } from "#content";

// All posts (typed as Post[])
const posts = blog;

// All projects (typed as Project[])
const allProjects = projects;

// All changelog entries (typed as ChangelogEntry[])
const entries = changelog;

// Filter examples
const published = blog.filter((post) => !post.draft);
const featured = projects.filter((p) => p.featured);
const features = changelog.filter((e) => e.tags.includes("feature"));

Development

Velite runs automatically during development and build:

# Development - Velite watches for content changes
pnpm dev

# Build - Velite processes content before Next.js build
pnpm build

Output is generated to apps/web/.velite/ (git-ignored) and includes full TypeScript types.

๐Ÿ“ฆ Creating New Packages

Component Package

# Create directory structure
mkdir -p packages/components/design-system/[name]/src

# Create package.json, tsconfig.json, eslint.config.mjs
# Follow existing patterns in packages/components/design-system/button/

Utility Package

# Create directory structure
mkdir -p packages/utils/core/[name]/src

# Create package.json, tsconfig.json, eslint.config.mjs
# Follow existing patterns in packages/utils/core/cn/

Page Package

# Create directory structure
mkdir -p packages/pages/[name]/src

# Create package.json, tsconfig.json, eslint.config.mjs
# Follow existing patterns in packages/pages/home/

๐Ÿ”„ CI/CD

GitHub Actions workflow runs on all PRs to main:

  • โœ… ESLint checks
  • โœ… TypeScript type checking
  • โœ… Unit tests (Vitest)
  • โœ… E2E tests (Playwright)
  • โœ… Build verification

Playwright HTML reports are attached to CI summaries for easy debugging. All checks must pass before merging.

๐Ÿ“š Documentation

Each package includes its own README with:

  • Usage examples
  • API documentation
  • Features and benefits

๐ŸŽจ Design Philosophy

Individual Packages

We use individual packages rather than grouped packages because:

  1. Turborepo caches each package separately
  2. Changes to one component don't rebuild unrelated components
  3. Parallel builds are more efficient with many small packages
  4. Clear dependency boundaries between components

Portable Pages

Page packages (packages/pages/*) enable:

  • Sharing complete pages across multiple apps
  • Single source of truth for page implementations
  • Consistent user experience across frontends
  • Easy micro-frontend architecture in the future

Shared Configs

Centralized configs (configs/*) ensure:

  • Consistent code style across all packages
  • Easy updates to linting/formatting rules
  • Type safety with shared TypeScript configs
  • Single dependency management via pnpm catalogs

๐Ÿงช Testing

Unit Tests

Unit tests use Vitest with shared configs from configs/vitest/.

# Run all unit tests
pnpm test

# Run tests in watch mode (per-package)
cd packages/utils/core/cn && pnpm test:watch

Test Structure

Each testable package includes:

  • vitest.config.ts - Extends shared config
  • src/*.test.ts(x) - Test files colocated with source

Shared Configs

Config Environment Use Case
configs.vitest Node Utility packages
configs.vitest/react jsdom React components

React component tests use @testing-library/react for accessible, behavior-focused testing.

E2E Tests

End-to-end tests use Playwright for cross-browser testing.

# Run E2E tests
pnpm --filter web e2e

# Run E2E tests with UI
pnpm --filter web e2e --ui

E2E tests are located in apps/web/e2e/ and cover:

  • Theme toggle functionality
  • Mobile navigation
  • Accessibility (skip-to-content links)

๐Ÿ”ฎ Future Plans

  • Set up shadcn/ui components
  • Add contact page
  • Build project portfolio pages
  • Explore other frameworks (Vue, Svelte) in component packages

Releases

Packages

Contributors

Languages