Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all \x3Cpre>\x3Ccode> blocks (function() { function addCopyButtons() { document.querySelectorAll('pre code').forEach(function(codeBlock) { if (codeBlock.parentElement.hasAttribute('data-copy-added')) return; codeBlock.parentElement.setAttribute('data-copy-added', 'true'); var btn = document.createElement('button'); btn.textContent = 'Copy'; btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;'; btn.onmouseover = function() { this.style.opacity = '1'; }; btn.onmouseout = function() { this.style.opacity = '0.7'; }; btn.onclick = function() { navigator.clipboard.writeText(codeBlock.textContent).then(function() { btn.textContent = 'Copied!'; setTimeout(function() { btn.textContent = 'Copy'; }, 1500); }); }; codeBlock.parentElement.style.position = 'relative'; codeBlock.parentElement.appendChild(btn); }); } addCopyButtons(); // Re-run on dynamic content var observer = new MutationObserver(addCopyButtons); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + ' GitHub - AroSwift/personal-website: My personal portfolio website for displaying my work, accomplishments, and more · GitHub
Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AroSwift/personal-website: My personal portfolio website for displaying my work, accomplishments, and more · GitHub
Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AroSwift/personal-website: My personal portfolio website for displaying my work, accomplishments, and more · GitHub
Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - AroSwift/personal-website: My personal portfolio website for displaying my work, accomplishments, and more · GitHub
Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AroSwift/personal-website: My personal portfolio website for displaying my work, accomplishments, and more · GitHub
Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AroSwift/personal-website: My personal portfolio website for displaying my work, accomplishments, and more · GitHub
Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - AroSwift/personal-website: My personal portfolio website for displaying my work, accomplishments, and more · GitHub
Skip to content

Repository files navigation

Personal Website - Aaron Barlow

A modern, responsive personal website for Aaron Barlow built with React, TypeScript, and Tailwind CSS. This website showcases my work, accomplishments, and provides a professional online presence.

Live Site:aaronbarlow.dev

Getting Started

Prerequisites

  • Bun (version 1.3.10 or higher)
  • Docker (for deployment)

Installation

  1. Clone the repository:

    git clone https://github.com/AroSwift/personal-website.git
    cd personal-website
  2. Install dependencies:

    bun install
  3. Start the development server:

    bun dev
  4. Open your browser and navigate to the URL shown in your terminal (usually http://localhost:5173 or similar)

Available Scripts

  • bun dev - Start development server
  • bun run build - Build for production
  • bun run build:check - Typecheck, then build
  • bun run preview - Serve the production build locally
  • bun run typecheck - Type-check without emitting
  • bun run test - Run tests in watch mode
  • bun run test:run - Run tests once (used by CI)
  • bun run lint / bun run lint:fix - Lint, optionally autofixing
  • bun run format / bun run format:check - Format with Prettier

Set VITE_OPEN_BUNDLE_STATS=1 on a build to generate and open the bundle size treemap. It is gated off by default so the bundle map is never emitted into a production dist/.

Testing

The project includes a comprehensive test suite built with Vitest and React Testing Library.

Running Tests

# Run all tests in watch mode (default)
bun run test# Run all tests once (CI mode)
bun run test -- --run
# Run tests with coverage report
bun run test -- --coverage
# Run specific test file
bun run test -- --run src/tests/home.test.tsx
# Run tests matching a pattern
bun run test -- --run --grep "HomePage"

Test Coverage

The test suite covers component rendering, user interactions, routing logic, loading states, and content validation. Coverage reports are generated in multiple formats and saved to the coverage/ directory.

Deployment

Dokploy Deployment

This project is configured for deployment on Dokploy with a fully code-owned Docker setup using docker-compose.yml for proper Traefik integration. It is configured for zero-downtime rolling updates.

Dokploy Setup Steps:

  1. Install Dokploy on your server:

    curl -sSL https://dokploy.com/install.sh | sh
  2. In Dokploy dashboard, create a new application

  3. Connect your Git repository

  4. Set Build Type to "Dockerfile"

  5. Set Port to "80"

  6. Add your domain(s) e.g.: aaronbarlow.dev and www.aaronbarlow.dev

  7. Deploy!

Local Docker Testing

Test the Docker setup locally:

# Build and run with Docker Compose for local development
docker-compose -f docker-compose.local.yml up --build
# Or build and run manually (for local development)
docker build -t personal-website .
docker run -p 3000:80 personal-website

Then visit http://localhost:3000

Alternative Static Hosting

The project can also be deployed to various static hosting platforms:

  1. Vercel: Connect your repository and deploy automatically
  2. Netlify: Drag and drop the dist folder or connect your repository
  3. GitHub Pages: Use GitHub Actions to build and deploy
  4. Any static hosting service: Build the project and upload the dist folder

Note: For static hosting, you'll need to configure the hosting provider to handle SPA routing (similar to the nginx try_files directive).

Features

  • Modern UI/UX: Built with shadcn/ui components and Tailwind CSS for a beautiful, responsive design
  • Multi-page Navigation: Home, About, Projects, and Contact pages with smooth routing
  • Loading Experience: Custom loading screen for first-time visitors
  • Responsive Design: Optimized for desktop, tablet, and mobile devices
  • TypeScript: Full type safety and better development experience
  • Performance: Built with Vite for fast development and optimized builds
  • PWA Support: Progressive Web App with offline functionality and installation capabilities

Performance & Build Metrics

Build Performance

  • Production Deployment Time: 18s (average of 5 runs)
  • Local Build Speed: 2.64s average (compile-only) - optimized chunking
  • Chunking Strategy: 15+ granular chunks for optimal caching and loading performance

Bundle Size

  • Main Bundle: 9.13 kB (2.87 kB gzipped) - optimized chunking
  • Total Initial Load: ~110 kB gzipped - efficient loading
  • Lazy Loading: Pages load on-demand (~1-18 kB each)
  • Core Dependencies: React core (72.38 kB gzipped) and vendor (16.25 kB gzipped) properly separated

Chunking Strategy

The build system now generates 15+ optimized chunks for better performance:

  • Core Chunks: react-core (226.74 kB, 72.38 kB gzipped), vendor (43.80 kB, 16.25 kB gzipped), utils (26.17 kB, 8.42 kB gzipped)
  • Feature Chunks: animations (80.42 kB, 26.12 kB gzipped), components (9.02 kB, 3.09 kB gzipped), layout (7.46 kB, 2.61 kB gzipped)
  • Page Chunks: page-home (7.72 kB, 2.68 kB gzipped), page-about (18.56 kB, 5.48 kB gzipped), page-projects (8.12 kB, 2.83 kB gzipped), page-contact (6.32 kB, 2.00 kB gzipped)
  • Dynamic Imports: Heavy libraries like Framer Motion are loaded on-demand to improve initial page load times

This granular approach ensures:

  • Better Caching: Individual chunks can be cached independently
  • Faster Initial Load: Only essential code is loaded upfront
  • Improved TTI: Time to Interactive is reduced by deferring non-critical animations
  • Efficient Updates: Users only download changed chunks on updates

Page Speed Scores

MetricDesktopMobile
Speed Score10099
Time To First Byte0.01s0.01s
First Contentful Paint0.38s1.66s
Largest Contentful Paint0.42s1.81s
Time to Interactive0.38s1.67s
Total Blocking Time0s0s
Speed Index0.38s1.66s
Cumulative Layout Shift0s0s

Performance measured from Iowa, USA on 2025-08-22 by Cloudflare Observatory

Tech Stack

  • Frontend Framework: React 19 with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS with shadcn/ui components
  • Routing: React Router DOM with lazy loading
  • UI Components: Radix UI primitives with custom styling
  • Animations: Framer Motion
  • Icons: Lucide React
  • Testing: Vitest + React Testing Library

Build Optimizations

  • Advanced Code Splitting: Intelligent manual chunk configuration with dynamic imports for optimal caching
  • Lazy Loading: Route-based component loading with Suspense boundaries for faster initial page loads
  • Animation Optimization: Framer Motion components dynamically imported to reduce initial bundle size
  • Granular Chunking: Page-specific, component-specific, and dependency-specific chunks for better caching
  • Tree Shaking: Automatic dead code elimination with enhanced dependency optimization
  • Bundle Analysis: Rollup plugin visualizer for ongoing optimization monitoring and chunk size analysis
  • Minification: ESBuild for fast and efficient code compression
  • Asset Optimization: Optimized images, CSS compression, and intelligent chunk naming
  • Dynamic Imports: Heavy libraries like Framer Motion loaded on-demand to improve Time to Interactive

Project Structure

personal-website/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── LoadingScreen.tsx # Splash screen
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx # Home page
│ │ ├── AboutPage.tsx # About page
│ │ ├── ProjectsPage.tsx # Projects page
│ │ └── ContactPage.tsx # Contact page
│ ├── lib/ # Utility functions and custom hooks
│ │ ├── utils.ts # General utility functions
│ │ ├── usePWA.ts # PWA functionality hook
│ │ └── useScrollToTop.ts # Scroll behavior hook
│ └── App.tsx # Main application component
├── public/ # Static assets
├── dist/ # Build output
├── Dockerfile # Docker configuration
├── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker Compose for production
├── docker-compose.local.yml # Docker Compose for local testing
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # TypeScript config for Node/Vite
├── eslint.config.js # ESLint configuration
├── components.json # shadcn/ui configuration
└── .prettierrc # Prettier configuration

Pages

  • Home: Landing page with introduction and key highlights
  • About: Personal information, skills, and background
  • Projects: Portfolio of work and projects
  • Contact: Contact information and form

Configuration

Environment Variables

If you plan to use external services, create a .env file in the root directory and add your configuration variables.

Build Configuration

The project uses Vite for building with advanced chunking optimization. Configuration can be modified in vite.config.ts.

Chunking Optimizations

The build system implements several key optimizations:

  1. Dynamic Imports: Heavy components like LoadingScreen and AboutPage use dynamic imports to defer Framer Motion loading
  2. Granular Chunking: Manual chunk configuration separates dependencies by type (core, UI, animations, utilities)
  3. Page-Level Splitting: Each page is split into its own chunk for optimal loading
  4. Component Separation: Layout and common components are separated from page-specific code
  5. Animation Deferral: Framer Motion animations are loaded only when needed, reducing initial bundle size by 32%

Performance Impact

  • Initial Bundle: 9.13 kB main bundle with optimized chunking strategy
  • Animation Loading: Deferred until user interaction, improving Time to Interactive
  • Caching Efficiency: 15+ chunks enable better browser caching strategies
  • Update Performance: Users only download changed chunks on subsequent visits

Nginx Configuration

The nginx.conf file handles:

  • HTTPS/SSL configuration with automatic HTTP to HTTPS redirect
  • SPA routing (React Router support)
  • Static asset caching
  • Security headers (including HSTS)
  • Gzip compression
  • Brotli compression
  • Proxy headers for CDN/reverse proxy compatibility

Contributing

This is a personal project, but if you find any issues or have suggestions, feel free to open an issue or submit a pull request.

License

This project is open source and available under the MIT License. If you use this code or design as inspiration for your own project, please give credit to Aaron Barlow.


Built with React, TypeScript, and Tailwind CSS

About

My personal portfolio website for displaying my work, accomplishments, and more

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages