The saga of a SRE sharing his technological adventures.
A modern, performant blog built with SvelteKit 5, featuring enhanced MDX content, advanced syntax highlighting, and automated deployment via GitOps. Built with cutting-edge web technologies for optimal performance and developer experience.
# Clone the repository
git clone https://github.com/techquestsdev/blog.git
cd blog
# Install dependencies
bun install
# Start development server
bun run dev
# Open http://localhost:5173
# Development
bun run dev # Start development server
bun run build # Build for production
bun run preview # Preview production build
# Code Quality
bun run lint # Run ESLint and Prettier checks
bun run format # Format code with Prettier
# Testing
bun run test # Run all tests
bun run test:unit # Run unit tests with Vitest
bun run test:integration # Run E2E tests with Playwright
# Dependencies
bun install # Install dependencies
bun update # Update dependencies
bun audit # Audit for vulnerabilities
During Development: Use watch mode for immediate feedback
bun run test:unit:watch
Before Committing: Run full test suite
bun run test
bun run test:integration -- --headed --timeout=0
The project includes a comprehensive Makefile for common tasks:
# Development Workflow
make help # Show all available commands
make install # Install dependencies (bun install)
make dev # Start development server
make build # Build for production
# Testing commands
make test # Run all tests
make test-unit # Run unit tests only
make test-coverage # Run unit tests with coverage
make test-coverage-watch # Run tests with coverage in watch mode
make test-integration # Run E2E tests
# Performance testing
make lighthouse # Run Lighthouse performance audit (requires build)
make lighthouse-full # Build site + run Lighthouse audit
# Code quality
make lint # Run linter
make format # Format code
make clean # Clean build artifacts, coverage, and test results
# Docker commands (requires pre-built files in build/ directory)
make docker-build # Build Docker image (validates build/ exists)
make docker-build-full # Build site + Docker image in one command
make docker-run # Run Docker container locally
make docker-scan # Security scan with Trivy
make docker-compose-up # Start with docker-compose
# Dependency management
make deps-update # Update dependencies (bun update)
make deps-audit # Audit dependencies (bun audit)
# CI/CD commands
make ci-full # Run complete CI pipeline
The project uses an optimized Docker workflow where the build happens in CI (GitHub Actions) for maximum speed, and Docker simply packages the pre-built static files with Caddy.
graph LR
A[CI: Build with Bun] --> B[Upload Artifact]
B --> C[Docker: Copy Pre-built Files]
C --> D[Caddy Server]
Benefits:
For local development, build first then create the Docker image:
# Option 1: Build site then Docker image separately
bun run build # Build the static site first
make docker-build # Build Docker image (requires build/ directory)
# Option 2: Build everything in one command
make docker-build-full # Runs 'make build' then 'make docker-build'
# Run the container
make docker-run
# Access at http://localhost:3000
Note: The docker-build target now validates that the build/ directory exists before building the image. This prevents common errors from building Docker without first building the site.
# Build and start services
make docker-compose-up
# View logs
make docker-compose-logs
# Stop services
make docker-compose-down
The .dockerignore file uses a whitelist approach for minimal build context:
*)build/, Caddyfile, and README.md# Scan for vulnerabilities
make docker-scan
# Scan for critical issues only
make docker-scan-critical
The blog uses GitHub Actions for continuous integration and deployment with a multi-stage workflow:
graph TB
START[Trigger: Push/PR/Tag] --> SPLIT{Event Type}
SPLIT -->|Push to main only| SV[Semantic Version Job]
SV -->|Calculate bump| DECIDE{Bump Needed?}
DECIDE -->|Yes| NEWTAG[Create and Push Tag]
DECIDE -->|No| SKIP[Skip Versioning]
NEWTAG -.->|Expose vX.Y.Z to build| DOCKERPUSH
SPLIT --> VAL[Validate Job]
VAL -->|Check files| LINT[Lint and Test Job]
LINT -->|Run tests| BUILD[Build Artifact]
BUILD -->|Upload| ARTIFACT[(build artifact)]
LINT -->|Upload| COV[Codecov]
ARTIFACT --> CHECK{Event?}
CHECK -->|Pull Request| DOCKERVAL[Validate Docker Job]
DOCKERVAL -->|Build test| TRIVY1[Trivy Scan]
TRIVY1 -->|Exit 1 on HIGH/CRITICAL| PRBLOCK[Block if vulnerable]
CHECK -->|Push/Tag not PR| DOCKERPUSH[Build and Push Job]
DOCKERPUSH -->|Multi-arch build| PUSH[Push to GHCR]
PUSH --> ATTEST[Generate Attestation]
ATTEST --> TRIVY2[Trivy SARIF + Table]
TRIVY2 --> UPLOAD[Upload SARIF to GitHub Security]
SV -.->|New tag + build success| RELEASE[Create Release Job]
DOCKERPUSH -.->|Success| RELEASE
RELEASE -->|GitHub Release| DONE[✓ Complete]
package.json existsbun.lock is present (generates if missing)# Pull the latest image
docker pull ghcr.io/techquestsdev/blog:latest
# Specific versions
docker pull ghcr.io/techquestsdev/blog:v1.0.0
docker pull ghcr.io/techquestsdev/blog:main-abc123
Image Tags:
latest - Latest from main branchmain - All pushes to main branchv*.*.* - Semantic version tags (e.g., v1.2.3)main-{sha} - Commit-specific builds from mainAll Docker images include:
Security scan results are available in the GitHub Security tab.
Create a new markdown file in src/content/blog/{slug}/+{slug}.md:
---
published: true
name: 'Your Post Title'
icon: 'ph:icon-name'
description: 'Brief description'
date: 2025-01-15
---
Your content here...
src/content/
├── blog/ # Blog posts
│ ├── {slug}/
│ │ ├── +{slug}.md # Main content file
│ │ └── assets/ # Post-specific assets
│ └── ...
└── projects/ # Project showcases
├── {slug}/
│ ├── +{slug}.md # Project description
│ └── assets/ # Project assets
└── ...
Create a new file in src/content/projects/{slug}/+{slug}.md with similar front matter.
The blog provides RSS 2.0 feeds for content syndication:
/rss.xml): All content (blog posts + projects)/blog/rss.xml): Blog posts only/projects/rss.xml): Projects onlyRSS feeds include:
blog/
├── src/
│ ├── routes/ # SvelteKit routes
│ ├── lib/ # Components and utilities
│ │ ├── components/ # Svelte components
│ │ ├── assets/ # Static assets
│ │ └── js/ # JavaScript utilities
│ ├── content/ # MDX content
│ │ ├── blog/ # Blog posts
│ │ └── projects/ # Project showcases
│ └── app.scss # Global styles
├── static/ # Static files
├── Dockerfile # Multi-stage Docker build
├── Caddyfile # Caddy server config
└── Makefile # Development commands
src/app.scss for colors and typographysrc/lib/assets/fonts/src/routes/+layout.js for default metadatasvelte.config.js (Shiki themes)The project uses a comprehensive testing strategy:
# Run all tests
bun run test
# Unit tests with coverage and watch mode
bun run test:unit --coverage --watch
# Generate coverage report only
bun run test:unit --coverage
# Generate coverage in different formats
bun run test:unit --coverage --reporter=html # HTML report in coverage/
bun run test:unit --coverage --reporter=lcov # LCOV format for CI
# E2E tests with different options
bun run test:integration # Headless mode
bun run test:integration --ui # With Playwright UI
bun run test:integration --headed # With browser visible
bun run test:integration --debug # Debug mode
# Update test snapshots
bun run test:integration --update-snapshots
# Install Playwright browsers (first time only)
npx playwright install --with-deps
vitest.config.js - Unit test configuration with coverage settingsplaywright.config.js - E2E test configurationcoverage/ directory (HTML, JSON, LCOV formats)src/test-setup.js and tests/helpers.jsContributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'feat: add amazing feature')git push origin feature/amazing-feature)This project follows Conventional Commits:
feat: - New featuresfix: - Bug fixesdocs: - Documentation changesstyle: - Code style changes (formatting, etc.)refactor: - Code refactoringtest: - Adding or updating testschore: - Maintenance tasksThis project is licensed under the GNU GPLv3 License - see the LICENSE file for details.