Getting Started
To start a new project simply
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
sitemap.json
The sitemap.json is responsible for 3 things:
- page urls and structure of the entire site
- defines which template in contentmap.json each page uses
- 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
- index
- 404
- blog/page-1
- blog/page-2
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 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 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