⚠️ Warning: This project is work in progress and is currently private. It has not been published yet.

Moss

Moss Logo

A whimsical static site generator for building blogs with Markdown and Vue

InstallationFeaturesGetting StartedCLI ReferenceConfiguration


Installation

System Requirements

  • Node.js 22.17.0 or later
  • npm, yarn, or pnpm

Install Moss

Install Moss globally to use the CLI:

pnpm add -g @znck/moss

Or use it locally in your project:

pnpm add -D @znck/moss

Features

Markdown-First: Write your content in Markdown with frontmatter support
Fast Development: Hot-reload development server with Vite
🔗 Clean URLs: Automatic clean URL generation for better SEO
📱 SEO Optimized: Canonical URLs, meta tags, and structured data
🎭 RSS/Atom Feeds: Automatic feed generation for your blog
📦 Zero Config: Works out of the box with sensible defaults
🔧 Customizable: Flexible configuration and theming options
🚀 TypeScript Support: Built with TypeScript for better developer experience
📝 Syntax Highlighting: Code blocks with syntax highlighting via Shiki
🧮 Math Support: LaTeX math rendering with KaTeX
🏷️ Tag Support: Organize content with tags and categories
💬 Comments: Built-in Giscus integration for GitHub Discussions-powered comments
📊 Analytics: Privacy-focused analytics with Counterscale support

Getting Started

1. Create a new project

mkdir my-blog
cd my-blog
pnpm init -y

2. Install Moss

pnpm add -D @znck/moss

3. Create configuration file (optional)

Moss works out of the box with zero configuration, but you can customize your site by creating a moss.json file or adding configuration to your package.json:

Option A: Using moss.json

{
  "title": "My Blog",
  "description": "This is my first blog using Moss",
  "author": "Your Name"
}

Option B: Using package.json

{
  "name": "my-blog",
  "displayName": "My Blog",
  "description": "This is my first blog using Moss",
  "author": "Your Name"
}
Note
If you use moss.json, package.json fields will be ignored.

4. Create your first post

Create an index.md file:

---
title: Welcome to My Blog
description: This is my first blog post using Moss
---

# Welcome to My Blog

This is my first blog post built with **Moss**!

Moss makes it easy to create beautiful, fast static sites with Markdown and Vue.

## Features I love

- Easy Markdown writing
- Vue component support
- Fast development server
- SEO optimization

5. Start the development server

pnpx moss serve

Your site will be available at http://localhost:5173

6. Build for production

pnpx moss build

The built site will be in the .moss/dist directory.

Deployment

After building, you can deploy the contents of .moss/dist to any static hosting service:

# Build the site
moss build

# Deploy to various platforms
# Netlify
netlify deploy --prod --dir .moss/dist

# Vercel
vercel --prod .moss/dist

# GitHub Pages (copy to docs folder)
cp -r .moss/dist/* docs/

# Or serve locally for testing
cd .moss/dist && python -m http.server 8000

CLI Reference

moss serve [directory]

Starts a development server for your site.

Options:

  • directory - The root directory of your site (defaults to current directory)

Example:

moss serve
moss serve ./my-blog

moss build [directory]

Builds your site for production.

Options:

  • directory - The root directory of your site (defaults to current directory)

Example:

moss build
moss build ./my-blog

moss help

Shows help information and usage examples.

Example:

moss help
moss --help
moss -h

moss version

Shows the current version of Moss.

Example:

moss version
moss --version
moss -v

Configuration

Moss works with zero configuration out of the box, but you can customize your site using either a dedicated moss.json file or by adding configuration to your existing package.json. Configuration in moss.json takes priority over package.json.

Configuration Options

Using moss.json (recommended for dedicated configuration):

{
  "title": "My Awesome Blog",
  "description": "A blog about web development and technology",
  "author": "Your Name",
  "baseUrl": "https://yourdomain.com",
  "icon": "path/to/favicon.ico"
}

Using package.json (convenient for simple projects):

{
  "name": "my-blog",
  "displayName": "My Awesome Blog",
  "description": "A blog about web development and technology",
  "author": "Your Name",
  "homepage": "https://yourdomain.com",
  "icon": "path/to/favicon.ico"
}

Supported Configuration Fields

Field (moss.json)Field (package.json)DescriptionDefault
titledisplayNameSite titlename from package.json
descriptiondescriptionSite description for SEO-
authorauthorAuthor name-
baseUrlhomepageBase URL for the site-
iconiconPath to site icon/favicon-
outDir-Output directory for built site.moss/dist
cleanUrls-Generate clean URLstrue
giscusgiscusGiscus configuration for comments-
counterscalecounterscaleCounterscale analytics configuration-

Ignored Files and Directories

By default, Moss ignores the following directories when scanning for Markdown files:

  • node_modules/ - Node.js dependencies
  • public/ - Static assets (typically served directly)
  • DRAFT/ - Draft content not ready for publication
  • Hidden directories (starting with .)

Clean URLs

Moss automatically generates clean URLs for your pages:

  • about.md/about/
  • posts/my-post.md/posts/my-post/
  • index.md/ (homepage)

Frontmatter Options

Each Markdown file can include frontmatter with the following options:

---
title: Page Title
description: Page description for SEO
layout: default # or 'homepage'
type: article # or 'page' or 'homepage'
tags: [web, javascript, tutorial]
---
FieldDescriptionDefault
titlePage titleFirst H1 heading
descriptionPage descriptionAuto-generated from content
layoutLayout template (article, default or homepage)default
typeContent type (article, page, or homepage)article
tagsArray of tags[]

Comments with Giscus

Moss includes built-in support for Giscus, a comments system powered by GitHub Discussions. Comments are automatically added to all article pages when configured.

Setting up Giscus

  1. Enable GitHub Discussions on your repository (Settings → Features → Discussions)

  2. Install the Giscus app on your repository: github.com/apps/giscus

  3. Configure Giscus by visiting giscus.app and following the setup wizard

  4. Add configuration to your package.json or moss.json:

Using package.json:

{
  "giscus": {
    "repo": "owner/repository",
    "repoId": "R_kgDOxxxxxxx",
    "category": "Announcements",
    "categoryId": "DIC_kwDOxxxxxxx"
  }
}

Using moss.json:

{
  "giscus": {
    "repo": "owner/repository",
    "repoId": "R_kgDOxxxxxxx",
    "category": "Announcements",
    "categoryId": "DIC_kwDOxxxxxxx"
  }
}

Giscus Configuration Options

FieldDescriptionRequired
repoGitHub repository in owner/name formatYes
repoIdRepository ID (get from giscus.app)Yes
categoryDiscussion category nameYes
categoryIdDiscussion category ID (get from giscus.app)Yes

Additional Giscus options are supported. Visit giscus.app for the complete configuration guide.

Disabling reactions on Specific Pages

You can disable reactions on individual pages by adding reactions: false to the frontmatter:

---
title: My Private Post
reactions: false
---

Analytics with Counterscale

Moss supports Counterscale, a privacy-focused, cookieless analytics platform. The analytics script is automatically included in production builds when configured.

Setting up Counterscale

Using package.json:

{
  "counterscale": {
    "siteId": "example.com",
    "script": "https://analytics.example.com/tracker.js"
  }
}

Using moss.json:

{
  "counterscale": {
    "siteId": "example.com",
    "script": "https://analytics.example.com/tracker.js"
  }
}

Counterscale Configuration Options

FieldDescriptionRequired
siteIdYour site identifierYes
scriptURL to the Counterscale trackerYes

Note: The analytics script is only loaded in production builds (moss build), not during development (moss serve).

Directory Structure

A typical Moss project structure:

my-blog/
├── package.json          # Basic project info and optional config
├── moss.json             # Optional dedicated config file
├── index.md              # Homepage
├── about.md              # About page
├── posts/                # Blog posts
│   ├── first-post.md
│   └── second-post.md
└── .moss/                # Generated files (git-ignored)
    └── dist/             # Built site

Advanced Usage

Vue Components

You can use Vue components directly in your Markdown:

# My Post

<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>

Click count: {{ count }}

<button @click="count++">Increment</button>

Moss uses Vue 3 with the Composition API, giving you access to all modern Vue features including:

  • Composition API with <script setup>
  • Reactivity (ref, reactive, computed, watch)
  • Lifecycle hooks (onMounted, onUnmounted, etc.)
  • Custom components and imports

Custom Layouts

Moss supports different layout types via frontmatter:

  • homepage - Minimal layout for your main landing page
  • default - Standard layout with header and navigation (used for both articles and pages)

The layout is determined by the frontmatter layout field, but the type field helps with content categorization:

---
title: My Homepage
layout: homepage # Uses minimal homepage layout
type: homepage # Content type for categorization
---
---
title: My Blog Post
layout: default # Uses standard layout (default)
type: article # Content type for categorization
---

Example Sites

Looking for inspiration? Check out these websites built with Moss:

  • znck.dev - Personal blog with Giscus comments and Counterscale analytics
  • moss.znck.dev - Documentation for Moss

You can also explore the znck.dev source code in this repository under apps/znck.dev/ to see a real-world example of Moss configuration including Giscus and Counterscale setup.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE file for details.


Made with ❤️ by @znck