Getting Started

17 minūšu

This guide covers creating an Eleventy Markdown Prime (EMP) repository, configuring the site, adding content and deploying it.

Table of Contents

  1. Create Your Site Repository
  2. Run the Template Locally (Optional)
  3. Site Structure
  4. File Structure
  5. Configuration Files
  6. Posts and Pages
  7. Deploying to Cloudflare Workers
  8. Other Deployment Environments

Create Your Site Repository

To build your website, you need your own copy of the EMP starter repository. This allows you to customize the site, save your changes, and deploy it online. The EMP starter repository is available here: EMP Starter Repository.

Steps to Create Your Repository

  1. Go to the EMP Starter Repository.
  2. Click Use this template or Fork (see the next section for guidance on which to choose).
  3. Name your repository and choose public or private.
  4. If you want to edit files locally on your computer, clone your repository:
    Kods
    git clone 
    cd 
  5. Alternatively, you can edit files directly in your repository using GitHub’s web interface. Simply navigate to the file you want to edit, click the pencil icon, make your changes, and commit them.

Fork vs Template: Which Should You Choose?

  • Use this template: Creates a new repository in your GitHub account with no connection to the original. Best if you want a clean start and don’t plan to sync updates from the EMP repository.
  • Fork: Creates a copy of the repository in your GitHub account, keeping the full history and a link to the original (upstream). Ideal if you want to pull future updates from EMP or contribute back.

Note: Changes to layouts, configuration or build scripts may need manual adaptation when merging upstream updates, especially if your directory structure differs from EMP.

Keeping Your Repository Updated

  • If you forked:

    1. Open your fork on GitHub.
    2. Click Sync fork (or Fetch upstream) to pull updates from the EMP repository.
    3. Alternatively, use the command line after adding the original repository as anupstreamremote (once per clone):
      Kods
      git remote add upstream https://github.com/lastguru-net/emp.git
      Then fetch and merge updates:
      Kods
      git fetch upstream
      git merge upstream/main   # or: git rebase upstream/main
      git push
  • If you used the template:
    Your repository has no shared commit history with EMP, so GitHub’s Sync fork option is not available. If you need updates, you can manually copy changes from the EMP repository.

Run the Template Locally (Optional)

Running the site locally is optional. If you prefer, you can skip this step and deploy your site directly from the repository. See the Deploying to Cloudflare Workers section for details.

If you want to preview and edit your site locally, follow these steps.

Prerequisites

  1. Install Git: Download Git.
  2. Install Node.js 24 or newer and npm:
    • Visit the Node.js Download Page, which provides both prebuilt packages and instructions for setting up a version manager (e.g., nvm).
    • Using a version manager is recommended as it makes it easier to update Node.js in the future.
  3. Verify installation:
    Kods
    node -v
    npm -v

Running the Site Locally

  1. Go to the repository folder.
  2. Install dependencies:
    Kods
    npm install
  3. Start the development server:
    Kods
    npm run dev
  4. Open the URL shown in the terminal (usuallyhttp://localhost:8080) to preview your site.

For more detailed guides on setting up Node.js and npm, check:

Site Structure

The regular layout has four areas:

  1. Sidebar: Always visible on larger screens and hidden on mobile devices. The sidebar is defined in the configuration files and includes:
    • Site logo or profile image
    • Site title and description
    • Main menu (manually defined for full control)
    • Search button (opens a search modal window)
    • Social links (GitHub, LinkedIn, Mastodon, etc.), shown in the sidebar or footer
  2. Top Bar: Displayed only on mobile devices. It shows the site title and provides a hamburger icon to show the sidebar.
  3. Content Area: Always visible on all screens, this is where your site content is displayed. Depending on the location, it serves the following purposes:
    • Index Page (Landing Page): The first page visitors usually see.
      • Features an optional header image on top.
      • Lists non-hidden posts newest first, with pinned posts at the top. Each post includes a title, description (or excerpt), and optional properties like date, location, author, tags, and reading time.
      • Optional thumbnails can be enabled and placed on the left or right; they are responsive and clickable.
      • If there are more than a configured number of posts (10 by default), pagination with navigation controls appears at the bottom.
    • Tag Page: Similar to the landing page but without a header image. Lists posts with a specific tag (e.g., “events”).
      • Supports pagination and is generated automatically for each tag.
    • Author Page: Similar to the landing page but without a header image. Lists posts by a specific author (e.g., “lastguru”).
      • Supports pagination and is generated automatically for each author.
      • When enabled, an author business card (photo, bio, website/email, socials) is displayed above the list.
    • Post: The most common content type - a blog post.
      • Includes a title, date, and optional image. Additional properties like location, author, and tags can be added.
      • Below each post, share buttons and navigation buttons for newer/older posts are available.
    • Page: Special content like “About Us.” Pages are not listed among blog posts and do not include dates, post properties, or navigation buttons. They are typically linked directly in the main menu or from other posts or pages.
  4. Footer: Optional footer with social links, copyright information, privacy policy link and “Powered by” link.

File Structure

Site content, configuration and templates are stored in these files and directories:

  • Utility configuration files are located in the root folder (e.g.,/package.json,/eleventy.config.mjs). Avoid modifying these unless necessary.
  • /_11ty: Contains custom components that enhance Eleventy. Scripts for tasks like image transformation, link transformation, and excerpt generation are located here. Modifications are rarely needed.
  • /assets: Stores shared files for your site. You can modify or add files here. Visitors can access these files via direct links.
    • css: Contains CSS source files. Eleventy assembles them throughcontent/utils/css.njk, and Tailwind CSS compiles and minifies the result into_site/assets/css/min.css. Add custom styles incustom.css.
    • js: Contains JavaScript files. Themin.jsfile is generated by Eleventy (content/utils/js.njk) by inlining feature scripts.
  • /content: Contains all site content.
    • _data: Stores site configuration (see below).
    • _includes: Contains template files for HTML output.
    • images: Stores image files. Images displayed in page content are automatically optimized and converted to various formats and sizes. Special images like the favicon are also stored here.
    • pages: Contains page files.
      • pages.json: Defines default variables for pages.
    • posts: Contains post files. For better organization, posts are subdivided into year-based subfolders (e.g.,/2025/). Subfolder names do not appear in URLs, so you can name them freely. For smaller sites, this organization is optional.
      • posts.json: Defines default variables for posts.
    • utils: Contains additional templates like the “Error 404” page androbots.txt.
    • index.njk: Template for the landing page.
    • index.11tydata.js: Pagination size control for the landing page.
    • author.njk: Template for author pages.
    • tag.njk: Template for tag pages.

Configuration Files

Edit the following files to configure the site:

/content/_data/siteconfig.js

This file contains the essential configuration settings for your site. It defines global properties such as the site title, URL and main images. There are comments for every setting in the file itself. Key sections include:

  • Site Metadata: Title, description, author, and locale settings.
  • Images: Paths for the sidebar profile image, favicon, and OpenGraph default image.
  • Integrations: Optional Google tag and Meta app/pixel configuration.
  • Pagination: number of posts per page, and the link prefixes for author/tag pages.

This file is the starting point for setting up your site.

/content/_data/siteelements.json5

This file contains configuration for site-specific elements such as menu items, fonts, social media links, header and footer settings. Key sections include:

  • Features: Settings for post properties, JSON-LD structured data, sitemap and feed links, and social sharing buttons. The sitemap and feed files are generated regardless of their link settings. Setfeatures.postpropertiesto"below"(default) or"above"for placement relative to the full-post image, orfalseto hide properties everywhere.truealso places properties below the image.
  • Fonts: Google Fonts configuration for body and header typography that can be later used intheme.css.
  • Menu: Labels and URLs for the home link and additional menu items.
  • Header: Header image for the landing page.
  • Social Links: Links to social media profiles (e.g., GitHub, LinkedIn, Mastodon). Also used for share attribution (e.g., X “via”).
  • Privacy Policy: Configuration for the privacy policy link.
  • Powered by: Powered by text and link.
  • Copyright: Settings for copyright year, link, and text.

Modify this file to customize visible elements, navigation and site identity.

Setfeatures.userMenu: truewithfeatures.js: trueto show a User button at the bottom of the regular sidebar. Its modal contains Sign in or Sign out and, whenfeatures.privacyPolicyis"sidebar", the configured policy link. The option is off by default.

The test sign-in storesTest UsernameinlocalStorage.user. The stored name replaces User across pages and reloads. Sign out removesuserand restores the signed-out menu.

JSON postlists

Setfeatures.index: "json"andfeatures.js: trueto load post lists from JSON in the browser. This applies to the homepage and tag and author archives. Usefeatures.index: "postlist"(the default) to render post lists during the build.

The build exports Markdown posts to JSON files in apostlist/directory beneath each list’s first page. For example,/postlist/1.jsoncontains the first page of the homepage list, and/events/postlist/2.jsoncontains the second page of the events list. Your static host serves these files.

SetjsonReadPrefixincontent/_data/siteconfig.jsto change where browsers read postlist and metrics/actions JSON. The default""reads generated files at their normal URLs. With"/api", the homepage still generatespostlist/1.json, while the browser requests/api/postlist/1.json. Generated files and links inside responses keep their canonical paths.

The read prefix goes before the deployment-prefixed path: with/blog/, the request is/api/blog/postlist/1.json. A trailing slash is optional. An absolute HTTP(S) prefix such ashttps://data.example/apisupports another origin, which must allow cross-origin requests (CORS). The host at the read URL supplies the responses.

For a custom list, uselayout: base.njk, a directory permalink such as/events/, and includepostlist.njkin a Nunjucks page with JSON mode enabled. Supply local items throughposts. An empty local list still generates/events/postlist/1.jsonand fetches its read URL, allowing that endpoint to supply posts.

Each JSON response contains the cards for one page and pagination metadata:

JSON
{
  "items": [{ "url": "/workshop/", "title": "Workshop", "excerpt": "A practical introduction." }],
  "pagination": { "page": 1, "totalPages": 8 }
}

pageis a one-based page number andtotalPagesis the number of pages in the list. For an empty list,1.jsonreturnsitems: []andpagination: { "page": null, "totalPages": 0 }.

Each item requires aurland atitle. Optional fields areexcerpt,pinned,thumbnailandproperties. Supply text without HTML or HTML escaping. For links and images, use site-root paths that include the deployment prefix, or absolute URLs. Site-root paths refer to the website, not the JSON host.

Athumbnailcontainssrcand optionalsrcset,sizes,widthandheight. Its optionalsourcesarray contains objects withtypeandsrcsetfor alternative image formats. The optional numericlqipfield supplies the blur placeholder.

Thepropertiesobject accepts:

  • date: formatted date text.
  • author: an object withnameandurl.
  • place: an object withnameand optionaladdress.
  • tags: an array of objects withname,urland optionalicon.
  • readingTime: an object withlabelandwordsLabel.
  • decorations: the post decoration fields.

Icon names refer to entries ininlinesvg.json5. Markdown exports supply formatted text, image variants and links; use an exported JSON file as a reference when creating your own source.

Pagination links use?page=N; JSON requests useN.json. Reload, new tabs and browser Back/Forward select the page in the URL. Without a validpagequery, an HTML page loads its corresponding JSON page. Use one list per HTML page.

If a request fails, the displayed cards and pagination links stay available. Click the link again to repeat the request, or reload if the initial load failed. Configure empty-list and error messages insitestrings.json5.

/content/_data/sitestrings.json5

This file defines text strings used throughout the site. It allows you to customize or translate common UI elements such as:

  • Labels: Words like “Share,” “Older,” “Newer,” and “Events.”
  • Tooltips: Text for actions like “Copy page link to clipboard” and “Copied.”

You can add your own keys and reference them in templates. Use it to adapt the site’s language and tone. Note that multiple languages can be defined there. The language is selected by thelangoption in thesiteconfig.js.

/content/_data/sitetags.json5

This file manages tag-related configurations for posts. It includes:

  • notime: Tags that hide post reading time in post properties (e.g., “events”).
  • notag: Tags that are hidden in post properties (e.g., “article,” “posts”).
  • events: Tags that trigger Event JSON-LD instead of BlogPosting.
  • icons: Overrides for the standard tag icon in post properties.
  • aliases: Overrides the link to the tag page.

This file helps control how tags are presented and used across the site.

/content/_data/siteauthors.json5

This file defines per-author metadata used to render the author business card on author pages. Each top-level key is the author identifier used in your post header variables (author: "name"). If an author has no entry here, the business card is not displayed. The card can show the author’s name, profile image, bio, and links to a website and social media.

/assets/css/theme.css

This file defines the core theme styles for your site, including fonts, colors, and layout spacing. It uses CSS custom properties (variables) to ensure flexibility and consistency across the site. Key sections include:

  • Fonts: Defines the primary fonts for the body and headers using the--font-bodyand--font-headervariables.
  • Colors: Defines the palette for backgrounds, text, and common UI states, plus the accent color (--color-accent) used on interactive highlights and hovers.
  • Spacing: Configures the maximum width for content (--spacing-content) and the width of the sidebar (--spacing-sidebar).

Notes:

  • Use fonts installed on visitors’ devices or load web fonts. EMP supports Google Fonts through/content/_data/siteelements.json5; use the corresponding font family names intheme.css. The fallback fonts in each list are used when the preferred font is unavailable.
  • The content area uses--color-rightarea-bgand--color-rightarea-bg-darkfor its light and dark backgrounds. The mobile top bar uses--color-topbar-bgand--color-topbar-bg-dark, which default to the light content background and sidebar background respectively.
  • The footer background (--color-footer-bg) defaults to the sidebar background (--color-sidebar-bg).

This file is processed by Tailwind CSS to generate the finalmin.cssfile, which is used to style the site. You can extend or override these variables to customize the theme further.

Posts and Pages

Posts and pages are written in Markdown, a simple and widely-used markup language. You can learn more about Markdown’s features on the Text and Typography page. Each Markdown file has a.mdextension and consists of two parts: a header and a content body.

Example:

Markdown
---
title: "Sample 2023 Event"
date: "2023-06-09"
place: "Somewhere over the rainbow"
tags: events
excerpt: "Excerpt of the description for the sample event."
---

## What a Great Event

Sample event. Please visit us.

Post updates

Add dated updates in a folder beside the main post with the same filename stem:

Text
content/posts/2023/sample-event.md
content/posts/2023/sample-event/places-filling.md
content/posts/2023/sample-event/workshop-recap.md

The same convention works directly underposts/and at any nesting depth. Markdown files in the matching folder belong to its sibling post. Each update has a requireddate, an optionaltitle, and a Markdown body:

Markdown
---
date: "2023-06-10T17:30:00+03:00"
title: Thank you for joining
---
Thank you to everyone who joined the **workshop**.

The build renders updates beneath the main body, newest first, using the site’s date/time formatting. Their content becomes part of the parent page, full-content feeds and search text. The latest update date contributes to the parent’s modification date; its publication date and authored excerpt remain as written.

Rebuild after adding, editing or removing an update. The sample event demonstrates the result. When current details such as the venue change, edit those details in the main post and use an update to explain the change.

Editing with PagesCMS (Optional)

If you prefer a more user-friendly editing experience (especially for non-technical editors), you can manage your EMP content with PagesCMS. PagesCMS connects to your GitHub repository and provides a browser-based editor for Markdown content. Changes are saved back to the repository as commits, which then trigger your normal deployment pipeline (e.g., Cloudflare Workers rebuilds automatically).

Header Variables

The header contains metadata for the post or page. Set title for both posts and pages, and an explicit date for posts. Supported variables include:

  • title (required): The title of the post or page. The URL is based on the title unless overridden in the header.
  • date (recommended for posts): The publication date inYYYY-MM-DDformat or with time inYYYY-MM-DD HH:MM:SSorYYYY-MM-DD HH:MM:SS +/-TTTTformat.
  • updated: Optional last modification date in the same formats as date. When present, it is used in JSON-LD, the sitemap, and the Atom and JSON feeds.
  • permalink: Overrides the default URL for the post/page.
  • image: Path to the title image, relative to thecontentfolder.
  • thumbnail: Optional path for a thumbnail image to use in post lists instead of the title image. To hide the thumbnail completely instead, usethumbnail: false.
  • excerpt: A description used in post lists. If defined, it has no length limit. If omitted, an excerpt is generated from the first nonempty line of rendered content after removing HTML tags, shortened to at most 250 characters at a word boundary where possible. An ellipsis is added when content is omitted.
  • tags: One or more tags for the post. Depending on the configuration, some (or all) of the tags are displayed in the post lists.
  • author: The author identifier, matching a key insiteauthors.json5when author metadata is provided. Used to generate author pages; the author’sfullNameis displayed when configured, otherwise the identifier is shown.
  • place: The location of the post. Displayed in post lists, commonly used for events.
  • address: The location address of the event. Displayed as a tooltip for place and in the Event JSON-LD structured data.
  • profilePage: When set totrueon a page (not a post), generates ProfilePage JSON-LD and a corresponding Person/Organization node describing the site publisher. Commonly used for pages like “About Us.”
  • hidden: When set totrueon a post or page, excludes it from listings, search, the sitemap and feeds. Its HTML file is still generated and accessible by URL, so this does not make a draft private.
  • pinned: When set totrue, puts the post ahead of unpinned posts in landing and author/tag listings, the sitemap and feeds. Within each group, posts are sorted newest first.

Theposts.jsonandpages.jsonfiles contain the default header variables. The most important setting there is permalink, which defines how URLs are generated for pages and posts. You can customize the default URL there. Note that the system depends on the layout and tags variables as they are set there, so it is not recommended to change them.

Post decorations

Posts can add optionaldecorationsto their front matter. They appear with post properties in lists and on full posts;siteelements.features.postpropertiescontrols both.

YAML
decorations:
  badges:
    - label: "Workshop"
      variant: primary
  metrics:
    - label: "Participants"
      value: 18
      max: 30
      progress: true
    - label: "Capacity"
      max: 30
  actions:
    - label: "Sign up"
      href: "https://example.org/register"
      icon: calendar
      variant: primary
  • Badges require alabel. Badges and actions share the optionalvariant:neutral(default),primary(site accent),successorwarning.
  • Metrics take alabeland a numericvalue,max, or both. Zero is displayed; a maximum alone does not imply a current count. Optionalprogress: trueadds a bar when a value and positive maximum exist. The text retains the actual numbers even beyond the maximum.
  • Actions require alabel. A suppliedhrefproduces a normal link; without it, the control is a button with no attached behavior. Optionaliconnames an entry ininlinesvg.json5; omit it for text-only controls.
  • disabled: trueproduces a disabled, non-navigating button, even ifhrefis present. For a closed event, you can uselabel: "Closed",variant: warninganddisabled: true. The sample event demonstrates a neutral “Past event” button with an icon. A text-only signup link simply omitsicon.

Each decoration group is optional. Set labels, numbers and availability in front matter; they do not update automatically from the event date or capacity. Point signup links to your registration service.

JSON metrics and actions

Setfeatures.liveMetricsActions: trueincontent/_data/siteelements.json5to load metrics/actions for full posts and static list cards. The defaultfalserenders their authored values directly. JSON lists render metrics/actions from each item in the list response, alongside the rest of the card data.

Eleventy generatesmetrics-actions.jsonbeneath each displayed post’s URL from the prepared front matter used for static rendering and JSON lists. For example,/sample-2023-pinned-event/and its static list cards load/sample-2023-pinned-event/metrics-actions.json. The samejsonReadPrefixapplies to these requests and explicit refreshes.

The sample event’s existing Markdown decorations produce metrics/actions in this format:

JSON
{
  "metrics": [
    { "label": "Participants", "value": 24, "max": 30, "progress": true }
  ],
  "actions": [
    { "label": "Past event", "icon": "calendar", "variant": "neutral", "disabled": true }
  ]
}

When enabled, metrics/actions on full posts and static list cards start empty and load silently from the generated JSON. Posts without metrics or actions export empty arrays. Bothfeatures.jsandfeatures.postpropertiesmust be enabled. Without JavaScript, full posts and static lists keep their content and badges readable.

In JSON list mode, each list response supplies the cards’ metrics/actions, including on pagination. External list publishers supply these fields in each item’sproperties.decorations. Full posts continue to usemetrics-actions.json. The default page layout does not display post properties. Cross-origin requests require CORS. Action URLs in responses must include any deployment prefix.

Every response must contain bothmetricsandactionsarrays, with a stringlabelfor each item. The shared renderer handles the item fields above. Each array replaces its whole group;[]clears it. Numbers must be JSON numbers, not strings. Omit an unknownvalueor set it tonull; it is not zero. A failed request or invalid response structure leaves the last valid presentation intact, or the initial region empty.

For full posts and static list cards, EMP fetches once on initialization. Custom JavaScript can refresh a region through the same loader:

JavaScript
const region = document.querySelector("[data-metrics-actions-url]");
region?.dispatchEvent(new Event("metricsactions:refresh"));

An update affects only that region; responses for removed regions or superseded refreshes are ignored. Action links navigate normally; action buttons require application-provided handlers.

Deploying to Cloudflare Workers

Cloudflare Workers builds the site from your Git repository and serves the generated files over HTTPS. Pushes to the configured production branch trigger a build and deployment.

Steps to Deploy

  1. Ensure you have a Cloudflare account. If not, create one at Cloudflare. It is free.
  2. Push your project to a Git repository (GitHub or GitLab).
  3. Create a new project:
    • Log in to your Cloudflare account and navigate to the Compute section, Workers & Pages subsection.
    • Click Create application, and connect your Git repository.
  4. Configure build settings:
    • In the Create an app step, set:
      • Project name: the name of your deployment
      • Build command: leave the defaultnpm run build
      • Deploy command: leave the defaultnpx wrangler deploy
    • Click on the Advanced settings and add an environment variable (enables HTML, feed and JavaScript minification):
      • Variable name:NODE_ENV
      • Variable value:production
  5. Start Deployment:
    • Click Deploy. Cloudflare Workers will build and deploy your site.
    • Once the deployment is complete, you will receive a unique URL for your site.

Custom Domain (Optional)

To use a custom domain:

  1. Open your Cloudflare Workers project you just created.
  2. Go to the Domains section.
  3. Add your custom domain and follow the instructions to configure DNS settings.

Other Deployment Environments

EMP can also be deployed on Netlify, Vercel, GitHub Pages or another static host. Build withNODE_ENV=productionand publish the contents of_site. Configure the host’s build workflow according to its documentation.

Lietotājs

Privacy Policy