Building montreuil.dev: A Brutalist Developer Portfolio

How I built my developer portfolio using Astro, React, and MDX, featuring a brutalist design, modern development practices, and excellent performance

astro react typescript web-development devex

Building montreuil.dev

After years of building developer tools and platforms for others, I decided it was time to create a proper home for my own work. I wanted something that would reflect my focus on developer experience while being maintainable and performant. Here’s how it was built!

Design Philosophy

I chose a brutalist design approach for several reasons:

  1. Clarity of Purpose: Like the architectural style it’s named after, brutalist web design emphasizes function and raw materials—in this case, HTML, CSS, and typography.
  2. Developer Focus: The terminal-inspired aesthetic resonates with developers while remaining highly readable.
  3. Performance: Minimal design means minimal JavaScript and faster load times.

The design features:

  • High contrast black/white theme
  • Monospace typography (JetBrains Mono)
  • Terminal-inspired UI elements
  • Visible structural components
  • Dark mode support

Technical Architecture

Core Stack

  • Astro: Static site generation with partial hydration
  • React: Interactive components
  • TypeScript: End-to-end type safety
  • Tailwind CSS: Utility-first styling
  • MDX: Rich content with interactive components

Project Structure

  montreuil.dev/
  ├── src/
  │   ├── components/      # Reusable components
  │   │   ├── layout/     # Layout components
  │   │   ├── home/       # Home page components
  │   │   ├── projects/   # Project-related components
  │   │   ├── articles/   # Article-related components
  │   │   └── mdx/        # MDX-specific components
  │   ├── content/        # MDX content
  │   │   ├── projects/   # Project writeups
  │   │   └── articles/   # Blog posts
  │   ├── layouts/        # Page layouts
  │   ├── pages/         # Route components
  │   ├── styles/        # Global styles
  │   └── types/         # TypeScript types

Implementation Details

Type System

A robust type system was crucial for maintainability. The implementation includes:

  • Generic type utilities for content collections
  • Strict null checks and explicit return types
  • Type-safe MDX content through Astro collections
  • Proper component prop typing

Content Management

Content is managed through Astro’s collection system with:

  • Type-safe frontmatter validation using Zod
  • Automated slug generation
  • Built-in content preprocessing
  • Rich MDX support with component imports

Brutalist Layout

The core layout component embodies brutalist principles through:

  • Terminal-inspired navigation with path-style links (/about, /projects)
  • High contrast borders and structural elements
  • Minimalist status bar showing location and availability
  • System-aware dark mode with smooth transitions
  • Visible grid system and structural elements

Developer Experience

ESLint Configuration

The ESLint setup focuses on maintainable, high-quality code through carefully selected rule sets:

Development Experience:

  • TypeScript-specific rules with sensible defaults
  • React and hooks best practices enforcement
  • Accessibility (a11y) checks for components
  • Import ordering and organization

Quality Controls:

  • Enforced consistent code style
  • Dead code elimination
  • React performance patterns
  • Type safety checks

Custom configurations per file type:

  • .ts/.tsx files for TypeScript code
  • .astro files for Astro components
  • .mdx files for content
  • React component files

Automated Code Quality

Comprehensive scripts for linting and formatting:

package.json
{
  "scripts": {
    "lint": "npm-run-all --parallel lint:*",
    "lint:eslint": "eslint \"src/**/*.{ts,tsx,js,jsx,astro}\" --fix",
    "lint:prettier": "prettier --check \"src/**/*.{ts,tsx,js,jsx,astro,css,md,mdx,json}\"",
    "lint:types": "astro check --silent && tsc --noEmit",
    "lint:spell": "cspell \"**\" --no-progress",
    "format": "npm-run-all --sequential format:*",
    "format:prettier": "prettier --write \"src/**/*.{ts,tsx,js,jsx,astro,css,md,mdx,json}\"",
    "format:eslint": "eslint \"src/**/*.{ts,tsx,js,jsx,astro}\" --fix"
  }
}

Pre-commit Hooks

Using Husky and lint-staged for pre-commit quality checks:

.lintstagedrc.cjs
module.exports = {
  // Type check staged TypeScript files
  '**/*.{ts,tsx}': () => 'pnpm astro check',
  
  // Lint and format staged files
  '**/*.{js,jsx,ts,tsx,astro}': ['eslint --fix', 'prettier --write'],
  
  // Format other files
  '**/*.{css,json,md,mdx,yaml,yml}': ['prettier --write'],
};

Performance Optimization

The site achieves excellent performance metrics, as verified by PageSpeed Insights:

MetricDesktopMobileTarget
Performance99/10092/10090+
Accessibility100/100100/100100
Best Practices93/10093/10090+
SEO100/100100/100100

These scores were achieved through several optimizations:

Build Configuration

The build pipeline is optimized through:

  • Partial hydration with Astro
  • Efficient code splitting
  • Minimal client-side JavaScript
  • Optimized asset handling
  • Cloudflare Pages integration

CSS Optimization

The CSS architecture focuses on performance:

  • Tailwind JIT compilation
  • Custom utility classes
  • Minimal base styles
  • Dark mode optimization
  • Typography-first approach

Deployment Pipeline

The site is deployed using Cloudflare Pages:

package.json deployment scripts
{
  "scripts": {
    "pages:dev": "pnpm run build && wrangler pages dev ./dist",
    "pages:deploy": "pnpm run build && wrangler pages deploy ./dist"
  }
}

Development Workflow

The development workflow is streamlined with key commands:

Local Development

pnpm dev              # Start development server
pnpm pages:dev        # Start with Cloudflare Pages
pnpm build           # Build for production
pnpm preview         # Preview production build

Code Quality

pnpm lint            # Run all linting
pnpm format          # Format all code
pnpm lint:types      # Type check

Deployment

pnpm pages:deploy    # Deploy to Cloudflare Pages

Lessons Learned

  1. Type Safety Investment: Proper TypeScript configuration prevented numerous potential issues and improved maintainability.

  2. Automated Quality Checks: Pre-commit hooks with lint-staged maintain code quality without impeding development speed.

  3. Performance by Design: The brutalist approach naturally led to excellent performance scores.

  4. Developer Experience: Taking time to set up proper tooling and automation made the development process more enjoyable.

  5. Build Pipeline: A well-configured build pipeline with proper type checking and linting catches issues early.

Future Improvements

  1. Analytics: Adding privacy-focused analytics with proper TypeScript types
  2. API Integration: Adding a typed API layer for the contact form
  3. Testing: Adding Jest and Testing Library integration
  4. Performance Monitoring: Implementing automated performance tracking
  5. Component Library: Extracting reusable components into a shared library

Conclusion

Building montreuil.dev has been an exercise in balancing minimalist design with robust development practices. The result is not just a portfolio site, but a platform that’s enjoyable to maintain and extend.

The source code is available on GitHub - feel free to use it as inspiration for your own projects!

montreuil.dev