Getting Started

To start a new project simply

npx create-statik-site your-project
cd your-project
npm install
npm start

this will bootstrap a new statik-site in the your-project directory, spin up a server and watch for changes to the src directory

When returning to a project you can simply run

npm start

sitemap.json

The sitemap.json is responsible for 3 things:

  1. page urls and structure of the entire site
  2. defines which template in contentmap.json each page uses
  3. passes strings to replace [placeholders] in the contentmap.json
{
    "index" : ["template-1", "homepage"],
    "404": ["template-1", "four-zero-four"],
    "blog" : {
        "page-1": ["blog-page", "foo", "bar"],
        "page-2": ["blog-page", "baz"]
    }
}

This sitemap would result in 4 pages been created, with the following urls

The "index" and "404" pages would both use the "template-1" template defined in the contentmap.json

"index" would pass the string "homepage" to replace the placeholder [PH1] in the contentmap.json

"404" would pass the string "four-zero-four" to replace [PH1]

Both blog pages would use the "blog-page" template defined in the contentmap.json

"page-1" would pass two strings "foo" and "bar" to replace [PH1] and [PH2]

"page-2" would pass "baz" to replace [PH1] in the contentmap.json

contentmap.json

Below is a simple example of a contentmap.json showing just template-1, click on stages 1 through 9 to see how a page is built.

    {
        "template-1": {
1           "content": "base",
2           "htmlClasses": "[PH1] standard",
            "head": {
3               "content": "head",
4               "favicons": "head/favicons"
            },
            "body": {
5               "content": "body",
6               "header": "body/header",
7               "footer": "body/footer",
8               "main": "body/main/[PH1]"
            }
9        }
    }

Stage 1: The first component, base.html, is added to the page. This component contains 4 replacement markers [[htmlClasses]], [[lang||en]], [[head]] and [[body]]

The [[lang||en]] has a default fallback of "en" if "lang" isn't defined in the template.

<!DOCTYPE html>
<html class="[[htmlClasses]]" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    [[head]]
</head>
<body>
    [[body]]
</body>
</html>

Stage 2: The [[htmlClasses]] marker is replaced by the string "homepage standard" since [PH1] = "homepage" from the sitemap.json

<!DOCTYPE html>
<html class="homepage standard" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    [[head]]
</head>
<body>
    [[body]]
</body>
</html>

Stage 3: The [[head]] marker is replaced by the contents of head.html (highlighted)

<!DOCTYPE html>
<html class="homepage standard" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    [[favicons]]
    <link rel="stylesheet" type="text/css" href="/css/normalize.css">    
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    [[extra-css]]
    <script type="text/javascript" src="/js/main.js"></script>
    [[extra-js]]
</head> <body> [[body]] </body> </html>

Stage 4: The [[favicons]] marker is replaced by the contents of head/favicons.html

<!DOCTYPE html>
<html class="homepage standard" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">    
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/site.webmanifest">
    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
    <meta name="msapplication-TileColor" content="#2d89ef">
    <meta name="theme-color" content="#ffffff">
<link rel="stylesheet" type="text/css" href="/css/normalize.css"> <link rel="stylesheet" type="text/css" href="/css/main.css"> [[extra-css]] <script type="text/javascript" src="/js/main.js"></script> [[extra-js]] </head> <body> [[body]] </body> </html>

Stage 5: The [[body]] marker is replaced by the contents of body.html

<!DOCTYPE html>
<html class="homepage standard" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/site.webmanifest">
    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
    <meta name="msapplication-TileColor" content="#2d89ef">
    <meta name="theme-color" content="#ffffff">
    <link rel="stylesheet" type="text/css" href="/css/normalize.css">
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    [[extra-css]]
    <script type="text/javascript" src="/js/main.js"></script>
    [[extra-js]]
</head>
<body>
    [[header]]    
    [[main]]
    [[footer]]
</body> </html>

Stage 6: The [[header]] marker is replaced by the contents of body/header.html

<!DOCTYPE html>
<html class="homepage standard" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/site.webmanifest">
    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
    <meta name="msapplication-TileColor" content="#2d89ef">
    <meta name="theme-color" content="#ffffff">
    <link rel="stylesheet" type="text/css" href="/css/normalize.css">
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    [[extra-css]]
    <script type="text/javascript" src="/js/main.js"></script>
    [[extra-js]]
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/contact">Contact</a>    
        <a href="/about">About</a>
        <a href="/blog">Blog</a>
    </nav>
[[main]] [[footer]] </body> </html>

Stage 7: The [[footer]] marker is replaced by the contents of body/footer.html

<!DOCTYPE html>
<html class="homepage standard" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/site.webmanifest">
    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
    <meta name="msapplication-TileColor" content="#2d89ef">
    <meta name="theme-color" content="#ffffff">
    <link rel="stylesheet" type="text/css" href="/css/normalize.css">
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    [[extra-css]]
    <script type="text/javascript" src="/js/main.js"></script>
    [[extra-js]]
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/contact">Contact</a>    
        <a href="/about">About</a>
        <a href="/blog">Blog</a>
    </nav>
    [[main]]
    <footer class="body-footer">
        <span>example.com © 2019</span>    
    </footer>
</body> </html>

Stage 8: The [[main]] marker is replaced by the contents of body/main/homepage.html

<!DOCTYPE html>
<html class="homepage standard" lang="[[lang||en]]">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/site.webmanifest">
    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
    <meta name="msapplication-TileColor" content="#2d89ef">
    <meta name="theme-color" content="#ffffff">
    <link rel="stylesheet" type="text/css" href="/css/normalize.css">
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    [[extra-css]]
    <script type="text/javascript" src="/js/main.js"></script>
    [[extra-js]]
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/contact">Contact</a>    
        <a href="/about">About</a>
        <a href="/blog">Blog</a>
    </nav>
    <main>
        <p>Hello World!</p>
    </main>
<footer class="body-footer"> <span>example.com © 2019</span> </footer> </body> </html>

Stage 9: All unused [[markers]] are removed and all [[marker||default]] are resolved to the default

<!DOCTYPE html>
<html class="homepage standard" lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
    <link rel="manifest" href="/site.webmanifest">
    <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
    <meta name="msapplication-TileColor" content="#2d89ef">
    <meta name="theme-color" content="#ffffff">
    <link rel="stylesheet" type="text/css" href="/css/normalize.css">
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <script type="text/javascript" src="/js/main.js"></script>
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/contact">Contact</a>    
        <a href="/about">About</a>
        <a href="/blog">Blog</a>
    </nav>
    <main>
        <p>Hello World!</p>
    </main>
    <footer class="body-footer">
        <span>example.com © 2019</span>    
    </footer>
</body>
</html>

stage 1 2 3 4 5 6 7 8 9

Templates

You can chose from a variety of templating engines to create content for your site.

mustache, handlebars, underscore, art, ejs, dot and pug templating engines are currently supported.

To use a templating engine to create content for a component, simply define which engine you want to use and the location of the template and data. For example.

{
    "template-1": {
        "html": "base",
        "htmlClasses": "[PH1] standard",
        "head": "head",
        "favicons": "head/favicons",
        "body": "body",
        "header": "body/header",
        "footer": "body/footer",
        "main": {
            "template": "templates/body/main.mustache",
            "engine": "mustache",
            "data": "data/body/main/[PH1].json"
        }
    }
}

You can also specify an object from within the specified json. For example.

"main": {
    "template": "templates/body/main.mustache",
    "engine": "mustache",
    "data": "data.json",
    "object": "main.[PH1]"
}

External Resources

You can also use external resources to create components. For example.

"footer": "https://example.com/pattern-library/footer.txt",
"main": {
    "template": "https://example.com/path/to/template.mustache",
    "engine": "mustache",
    "data": "https://example.com/some/endpoint/data.json"
}

Project Structure

All html/template files should be placed inside the "content" directory. Other than that, statik-site maintains a pretty standard project structure.

src
  content
    body
    data
    head
    templates
    base.html
    body.html
    head.html
  css
  images
  js
  sass/scss  (optional)
  less       (optional)
contentmap.json
sitemap.json

CSS, SASS/SCSS, LESS and JavaScript

CSS will be minified and auto-prefixed.

SASS/SCSS and LESS (if you chose to use them) will be compiled to CSS, then minified and auto-prefixed.

source/less/header.less will be compiled to public/css/header.css, same for sass/scss.

All JavaScript will be transformed to ES2015 and minified + uglified.

Images

Any images placed into the src/images directory will be optimized and resized copies will be made.

Resized copies will not be upscaled, so for example src/images/santa.jpg (if santa.jpg was 1000 × 400px) would result in

public/images/santa.jpg
public/images/40/santa.jpg
public/images/400/santa.jpg
public/images/800/santa.jpg

Images in the 40/ directory are 40px wide and purposfully low quality (usually around ~700 bytes) to act as potential placeholders if/when using a lazyload image replacement script.

Images will be resized to the following widths: 400, 800, 1200, 1600 and 2000, providing the original is greater than 2000px wide.

Images in sub-directories will maintain their directory structure, for example src/images/christmas/banners/santa.jpg will be copied/resized to the following directories

public/images/christmas/banners/santa.jpg
public/images/40/christmas/banners/santa.jpg
public/images/400/christmas/banners/santa.jpg
public/images/800/christmas/banners/santa.jpg

Wordpress

statik-site comes with a script that helps build sites using the wordpress rest API

This script will generate json's for pages, posts (with comments), users, tags and categories. So that you can generate urls for them.
It will also overwrite the sitemap.json with new entries.

You'll need to specify the location of the site's base url and wordpress rest API endpoint in the .env file located at the root of your project (see .env file section beneath)

npm run wordpress
npm start

.env file

To enable https over localhost, paths for the cert and key will be needed in the .env file at the root of your project. More info on how to enable https for localhost (mac)

This file can also be used to specify different names for the "src", "content" and "public" directories, if you so wish. (defaults shown)

If you are using statik-site to create a static site from the wordpress rest API, you will need to provide your site's base url and the rest API endpoint

# needed for https://localhost
SSL_CRT_PATH = /.ssl/localhost.crt
SSL_KEY_PATH = /.ssl/localhost.key

# alternative names for project directories
PUBLIC_DIR_NAME = public
SOURCE_DIR_NAME = src
CONTENT_DIR_NAME = content
WORDPRESS_JSON_DIR = data/wp-json

# needed for using wordpress rest API as source
SITE_NAME = https://example.com
WORDPRESS_API_ENDPOINT = wp-json/wp/v2

Purge

running this command will delete the contents of the "public" directory and reset the .buildStamp file.

npm run purge

npm run audit

Running the command npm run audit will print to the command line a list of all the urls and a breakdown of which templates each page uses. As well as listing unused templates in the contentmap.json

PAGES
=====

https://example.com/404
https://example.com
https://example.com/blog
https://example.com/blog/cars
https://example.com/blog/cars/audi
https://example.com/blog/cars/ford
https://example.com/blog/cars/volvo
https://example.com/blog/cars/volvo/S80
https://example.com/blog/cars/volvo/S70
https://example.com/blog/cars/volvo/V60
https://example.com/blog/cars/volvo/V70
https://example.com/about
https://example.com/contact
https://example.com/pricing

Total pages: 14

TEMPLATES USED
==============

blog-template
==========

https://example.com/blog
https://example.com/blog/cars
https://example.com/blog/cars/audi
https://example.com/blog/cars/ford
https://example.com/blog/cars/volvo
https://example.com/blog/cars/volvo/S80
https://example.com/blog/cars/volvo/S70
https://example.com/blog/cars/volvo/V60
https://example.com/blog/cars/volvo/V70

Total pages: 9

standard-template
==========

https://example.com/404
https://example.com
https://example.com/about
https://example.com/contact
https://example.com/pricing

Total pages: 5

TEMPLATES UNUSED
================

christmas-template
special-offer-template