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
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:
- 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.
- Developer Focus: The terminal-inspired aesthetic resonates with developers while remaining highly readable.
- 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:
{
"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:
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:
Metric | Desktop | Mobile | Target |
---|---|---|---|
Performance | 99/100 | 92/100 | 90+ |
Accessibility | 100/100 | 100/100 | 100 |
Best Practices | 93/100 | 93/100 | 90+ |
SEO | 100/100 | 100/100 | 100 |
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:
{
"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
-
Type Safety Investment: Proper TypeScript configuration prevented numerous potential issues and improved maintainability.
-
Automated Quality Checks: Pre-commit hooks with lint-staged maintain code quality without impeding development speed.
-
Performance by Design: The brutalist approach naturally led to excellent performance scores.
-
Developer Experience: Taking time to set up proper tooling and automation made the development process more enjoyable.
-
Build Pipeline: A well-configured build pipeline with proper type checking and linting catches issues early.
Future Improvements
- Analytics: Adding privacy-focused analytics with proper TypeScript types
- API Integration: Adding a typed API layer for the contact form
- Testing: Adding Jest and Testing Library integration
- Performance Monitoring: Implementing automated performance tracking
- 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!