A personal blog built with a custom static site generator using TypeScript, EJS templates, and Markdown content.
- Node.js 22+ (required - see
enginesin package.json) - npm (comes with Node.js)
git clone https://github.com/NickLiffen/nickliffen-me.git
cd nickliffen-me
npm install# Run TypeScript type checking
npm run typecheck
# Run tests
npm test
# Build the site
npm run build
# Validate the output
npm run validateIf all commands pass, you're ready to go!
├── content/ # Markdown articles with frontmatter
├── src/
│ └── templates/ # EJS templates for HTML generation
├── scripts/
│ ├── build.ts # Main build script
│ ├── new-article.ts # CLI to create new articles
│ └── lib/ # Modular TypeScript utilities
│ ├── articles.ts # Article loading and processing
│ ├── assets.ts # Static file copying
│ ├── config.ts # Site configuration
│ ├── dates.ts # Date formatting utilities
│ ├── templates.ts # EJS template rendering
│ ├── types.ts # TypeScript interfaces
│ └── generators/ # Output generators
│ ├── feeds.ts # Sitemap and RSS generation
│ ├── pages.ts # HTML page generation
│ └── pwa.ts # PWA manifest and service worker
├── dist/ # Built output (generated)
├── css/ # Stylesheets (copied to dist)
├── img/ # Images (copied to dist)
└── coverage/ # Test coverage reports (generated)
| Command | Description |
|---|---|
npm run build |
Build the production site to dist/ |
npm run build:dev |
Build with draft articles included |
npm run dev |
Build (with drafts) and serve locally |
npm run validate |
Validate the built output |
npm run new-article "Title" |
Create a new article with frontmatter template |
npm run typecheck |
Run TypeScript type checking |
npm test |
Run unit tests |
npm run test:watch |
Run tests in watch mode |
npm run test:coverage |
Run tests with coverage report |
npm run clean |
Remove the dist/ directory |
npm run new-article "Your Article Title"This creates a new Markdown file in content/ with frontmatter template:
---
slug: "your-article-title"
title: "Nick Liffen's Blog | Your Article Title | Blog Post"
headline: "Your Article Title"
description: "Nick Liffen's Blog | Your Article Title | Blog Post"
date: "2024-12-22"
modified: "2024-12-22"
keywords:
- Nick
- Liffen
- Blog
image: "https://nickliffen.dev/img/tech.jpg"
sections:
- Introduction
- Conclusion
articleBody: "Add a brief excerpt here..."
hasYouTube: false
draft: true
---
## Introduction
Start writing your article here...Edit the generated file in content/:
- Update the frontmatter (title, description, keywords, image, sections)
- Write your article content in Markdown
- The
articleBodyfield is used for RSS feed excerpts
npm run devThis builds with draft: true articles included and serves at http://localhost:3000.
When ready to publish:
- Set
draft: falsein the frontmatter - Update the
modifieddate if needed - Commit and push your changes
git add content/your-article-title.md
git commit -m "Add article: Your Article Title"
git pushThe CI/CD pipeline will automatically build, test, and deploy to Netlify.
# Run all tests once
npm test
# Run tests in watch mode (re-runs on file changes)
npm run test:watch
# Run tests with coverage report
npm run test:coverageCoverage reports are generated in the coverage/ directory. The project maintains 90%+ code coverage.
npm run typecheckThis runs TypeScript's type checker without emitting files.
# Clean previous build
npm run clean
# Type check
npm run typecheck
# Run tests with coverage
npm run test:coverage
# Build production site
npm run build
# Validate output
npm run validate| Field | Required | Description |
|---|---|---|
slug |
Yes | URL-safe identifier (e.g., my-article-title) |
title |
Yes | Full page title for SEO |
headline |
Yes | Article headline displayed on the page |
description |
Yes | Meta description for SEO |
date |
Yes | Publication date (YYYY-MM-DD) |
modified |
No | Last modified date (YYYY-MM-DD) |
keywords |
No | Array of keywords for SEO |
image |
No | Open Graph image URL |
sections |
No | Array of section headings for structured data |
articleBody |
No | Excerpt for RSS feed |
hasYouTube |
No | Set to true to enable YouTube embed styles |
draft |
No | Set to true to exclude from production builds |
The GitHub Actions workflow (.github/workflows/build.yml) runs on every PR and push to main:
- TypeScript Check - Validates types
- Tests with Coverage - Runs Vitest with coverage thresholds
- Build - Generates the static site
- Validate - Checks all HTML and XML files
- Lighthouse - Runs performance audits (on PRs)
Coverage reports are automatically posted as PR comments.
- Node.js 22 - Runtime
- TypeScript - Type-safe JavaScript
- tsx - TypeScript execution
- EJS - HTML templating
- Marked - Markdown to HTML
- gray-matter - Frontmatter parsing
- Vitest - Testing framework
- Netlify - Hosting and deployment