2026-03-25 20:08:25 -05:00
2026-03-25 20:07:27 -05:00
SEO
2026-03-25 20:08:25 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
SEO
2026-03-25 20:08:25 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00
2026-03-25 20:07:27 -05:00

Bay Area IT — Website

Marketing website for Bay Area IT, an IT service provider based in Corpus Christi, TX. Built with React 19, Vite 6, TypeScript, and Tailwind CSS. Deployed as a static site served by Caddy inside Docker.


Table of Contents


Tech Stack

Layer Technology
UI Framework React 19
Build Tool Vite 6
Language TypeScript 5
Styling Tailwind CSS 3
Routing React Router 7
Animations Framer Motion 12, GSAP 3
Smooth Scroll Lenis
Web Server Caddy 2 (inside Docker)
Containerization Docker + Docker Compose

Project Structure

bayarea/
├── components/           # Shared UI components
│   ├── Navbar.tsx
│   ├── Footer.tsx
│   ├── Hero.tsx
│   ├── Services.tsx
│   ├── Blog.tsx
│   ├── CTA.tsx
│   ├── Testimonials.tsx
│   ├── Process.tsx
│   ├── AreasWeServe.tsx
│   ├── SEO.tsx           # Head/meta tag injection
│   ├── Breadcrumb.tsx
│   └── LoadingScreen.tsx
├── src/
│   ├── pages/            # Route-level page components
│   │   ├── HomePage.tsx
│   │   ├── AboutPage.tsx
│   │   ├── ServicesPage.tsx
│   │   ├── ServicePage.tsx       # Dynamic: /services/:slug
│   │   ├── BlogPage.tsx
│   │   ├── BlogPostPage.tsx      # Dynamic: /blog/:slug
│   │   ├── LocationPage.tsx      # Dynamic: /locations/:slug
│   │   ├── LocationsPage.tsx
│   │   ├── ContactPage.tsx
│   │   ├── PrivacyPolicyPage.tsx
│   │   ├── TermsOfServicePage.tsx
│   │   └── LegalPage.tsx
│   ├── data/
│   │   └── seoData.ts    # All location, service, and blog post data
│   ├── routes/           # Route definitions
│   └── index.css         # Global styles
├── scripts/
│   ├── prerender-routes.ts   # Generates per-route index.html files
│   ├── prune-dist-assets.mjs # Removes unused assets from dist/
│   ├── generate-sitemap.ts   # Generates public/sitemap.xml
│   ├── generate-robots.ts    # Generates public/robots.txt
│   └── optimize-images.mjs   # Converts images to WebP
├── public/
│   ├── assets/services/  # Service page images (.webp)
│   ├── images/blog/      # Blog post images (.webp)
│   ├── sitemap.xml
│   └── robots.txt
├── Dockerfile            # Multi-stage: Node build → Caddy serve
├── docker-compose.yml    # Runs the container on localhost:8080
├── Caddyfile             # Caddy config inside the container
├── caddy-host.snippet    # Paste this into your host Caddy config
├── tailwind.config.cjs
├── postcss.config.cjs
├── vite.config.ts
└── tsconfig.json

Local Development

Prerequisites

  • Node.js 22+ (or use nvm)
  • npm

Setup

# Install dependencies
npm install

# Start the dev server
npm run dev

The app runs at http://localhost:3012

Hot Module Replacement (HMR) is enabled. If port 3012 is taken, Vite picks the next available port automatically.


Build & Preview

# Production build (Vite + prerender + asset pruning)
npm run build

# Preview the production build locally
npm run preview

The build pipeline runs three steps in sequence:

  1. vite build — bundles and outputs to dist/
  2. prune-dist-assets.mjs — removes any unreferenced files from dist/assets/
  3. prerender-routes.ts — writes a unique index.html per route into dist/ with correct <title>, <meta>, canonical URLs, Open Graph tags, and JSON-LD schema

The result is a fully static site where every URL has its own HTML file — no server-side rendering required.


Deployment (Docker + Caddy)

This project uses a two-Caddy setup:

Internet
  └── Host Caddy  (HTTPS, port 443)
        └── Docker container  (internal port 80 → host localhost:8080)
              └── Caddy inside container
                    └── /srv  (built static files)

Step 1 — Build and start the container

On your server, copy the project files (or clone the repo), then run:

docker compose up -d --build

This builds the image (Node 22 compiles the app, Caddy serves it) and starts the container. The app is now available at http://localhost:8080 — only reachable from the server itself.

To verify:

curl -I http://localhost:8080
# HTTP/1.1 200 OK

Step 2 — Configure the host Caddy

Add the following to your host Caddy config (usually /etc/caddy/Caddyfile). A ready-to-paste version is in caddy-host.snippet:

bayareait.services, www.bayareait.services {
    encode zstd gzip
    reverse_proxy localhost:8080

    @www host www.bayareait.services
    redir @www https://bayareait.services{uri} permanent
}

Replace bayareait.services with your actual domain.

Step 3 — Reload host Caddy

sudo systemctl reload caddy
# or
caddy reload --config /etc/caddy/Caddyfile

Caddy automatically obtains and renews an SSL certificate from Let's Encrypt — no manual certificate management needed.

Updating the site

# Pull latest changes, rebuild, restart
git pull
docker compose up -d --build

Zero-downtime: Docker Compose replaces the old container while the new one starts.

Useful Docker commands

# View logs
docker compose logs -f

# Stop the container
docker compose down

# Rebuild without cache
docker compose build --no-cache
docker compose up -d

Adding Content

All page content is driven by src/data/seoData.ts. No new page files needed for standard locations, services, or blog posts — just add a new entry to the right array.

Add a location page

// src/data/seoData.ts → locationData array
{
  city: "Sinton",
  slug: "locations/it-support-sinton",
  title: "IT Support Sinton, TX | Bay Area IT",
  description: "...",
  h1: "IT Support for Businesses in Sinton, TX",
  keywords: ["IT support Sinton", "..."],
  content: `<p>...</p>`,
  faq: [
    { question: "...", answer: "..." }
  ]
}

Add a service page

// src/data/seoData.ts → serviceData array
{
  id: "9",
  slug: "services/cloud-backup",
  title: "Cloud Backup Services | Bay Area IT",
  description: "...",
  h1: "Cloud Backup for Corpus Christi Businesses",
  keywords: ["cloud backup", "..."],
  content: `<p>...</p>`,
  faq: []
}

Add a blog post

// src/data/seoData.ts → blogPostData array
{
  slug: "blog/your-post-slug",
  title: "Your Post Title | Bay Area IT",
  description: "...",
  h1: "Your Post Heading",
  keywords: ["..."],
  content: `<p>...</p>`,
  date: "2026-03-25",
  image: "/images/blog/your-image.webp"
}

After adding content, rebuild:

npm run build
# or on the server:
docker compose up -d --build

Scripts Reference

Script Command Description
Dev server npm run dev Starts Vite dev server on port 3012
Production build npm run build Vite build + asset pruning + prerendering
Preview build npm run preview Serves dist/ locally via Vite
Generate sitemap npm run generate:seo Writes public/sitemap.xml and public/robots.txt
Optimize images npm run optimize:images Converts images in public/ to WebP
Prerender only npm run prerender:routes Re-runs route prerendering on existing dist/
Description
No description provided
Readme 16 MiB
Languages
TypeScript 97.5%
JavaScript 1.7%
CSS 0.3%
HTML 0.3%
Vim Snippet 0.1%