Create A Static Site Using 11ty & Deploy to Neocities
Kia ora, I’m hoping that this guide is going to provide a great starting point for those of you who have been happily constructing your homepages and hosting them on Neocities but want to take it to the next level.
This guide aims to help you create a homepage using the static site generator (SSG) 11ty, commit the code to Github and using a Github action, deploy it to Neocities.
The homepage that we are creating will take advantage of the Nunjucks templating language, allowing us to create a shared header, navigation and footer across all the pages on our homepage.
We will be creating an about, links, contact pages before diving in and creating the ability to add a blog and a list of all blog posts on the blog page!
We will structure and style the page with a standard HTML5 boilerplate and some basic CSS styles that should allow you to add in your unique flavour that we all know that you love to do.
Create a new project
First off, from a terminal, confirm that you have Node and NPM instlled:
node -v && npm -v
v17.4.0
8.3.0
Create a new directory and cd into it:
mkdir 11ty-neocities && cd 11ty-neocities
Initiate a new project:
npm init -y
Install 11ty:
npm install @11ty/eleventy
Once the 11ty installation is complete, open the project in your favourite code editor:
code .
You should now be in VSCode with the following project structure:
Open packages.json
and update the scriptions section to the following:
"scripts": {
"start": "npx @11ty/eleventy --serve",
"build": "npx @11ty/eleventy"
},
The packages.json
file should look like this:
{
"name": "11ty-neocities",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npx @11ty/eleventy --serve",
"build": "npx @11ty/eleventy"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@11ty/eleventy": "^1.0.0"
}
}
Create an 11ty config file
From the terminal (or VSCode), create a new file .eleventy.js
at the project root:
touch .eleventy.js
Open the file in VSCode and add the following and save:
module.exports = function (eleventyConfig) {
return {
dir: {
input: "src",
output: "public",
includes: "_includes",
},
};
};
.gitignore
As we’re going to be commiting our homepage code to Github, create a .gitignore
file in the project root:
touch .gitignore
Open the file in VSCode and add the following and save:
# dependencies installed by npm
node_modules
# build artefacts
public
Start building the homepage
Now comes the fun part, building our homepage. 11ty has a number of templating languages available to it, with markdown being the most popular. For this guide we’re going to use plain old <html>
as that will be most familiar to you.
Create a src
directory at the project root and cd into it:
mkdir src && cd src
Create an index.html
file in the terminal or VSCode:
touch index.html
Open the file and add some content:
<html>
<head>
<title>My New 11ty Homepage on Neocities!</title>
</head>
<body>
<h1>Hello World</h1>
<p>
Check out your cool new static site built with
<a href="https://11ty.dev">11ty</a> on
<a href="https://neocities.org/">Neocities</a>.
</p>
</body>
</html>
Now from the terminal start 11ty:
npm start
If everything has been configured right so far you should see the following:
> 11ty-neocities@1.0.0 start
> npx @11ty/eleventy --serve
[11ty] Writing public/index.html from ./src/index.html (liquid)
[11ty] Wrote 1 file in 0.03 seconds (v1.0.0)
[11ty] Watching…
[Browsersync] Access URLs:
-----------------------------------
Local: http://localhost:8080
External: http://192.168.1.119:8080
-----------------------------------
[Browsersync] Serving files from: public
Now you can open up http://localhost:8080
and check out your new 11ty homepage! It should look like this:
Amazing! But what we want to avoid is having to write out the <html>
and <head>
and <body>
tags on each and every page, and be able to include a site header, navigation and footer so we don’t have to copy and paste the changes across every page each time we update.
Let’s checkout templating a layout!
Create a base layout
Create a new directory _includes/
in the src/
directory and cd into it:
mkdir _includes && cd _includes
Create a file base.njk
in the terminal or VSCode:
touch base.njk
Open the file and add the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title }}</title>
</head>
<body>
<header>
<h1>{{ title }}</h1>
</header>
<main>{{ content | safe }}</main>
</body>
</html>
Now, head back to the index.html
file you created earlier, delete the contents and add some front matter and some content:
---
title: Hello World!
layout: base.njk
---
<p>
Check out your cool new static site built with
<a href="https://11ty.dev">11ty</a> on
<a href="https://neocities.org/">Neocities</a>.
</p>
<p>This homepage template is perfect for:</p>
<ul>
<li>Creating your own space on the web</li>
<li>Expressing yourself</li>
<li>Displaying all the gifs you've collected</li>
</ul>
<h2>Why do you want a homepage?</h2>
<p>The web was made for personal homepages, make this one yours</p>
If you’ve kept 11ty running and the broswer running it should look like this:
Amazing! Now lets create the additional pages for our homepage.
Create the following pages in the src/
directory with the terminal or VSCode:
touch about.html && touch links.html && touch contact.html
Open each of them up and add in some front matter and content:
about.html:
---
title: About Me
layout: base.njk
---
<p>Heya 👋 this is my homepage.</p>
links.html:
---
title: Links
layout: base.njk
---
<p>These are some of my favourite websites 🔗</p>
<ul>
<li><a href="https://flamedfury.com">fLaMEdFury.com</a></li>
<li><a href="https://11ty.dev">11ty</a></li>
<li><a href="https://neocities.org">Neocities</a></li>
<li><a href="https://yesterweb.org/">The Yesterweb</a></li>
</ul>
contact.html:
---
title: Contact Me
layout: base.njk
---
<p>Heya 👋 this is my contact page</p>
You should now be able to browse each of these pages if you kept 11ty running on the following urls:
http://localhost:8080/about/
http://localhost:8080/links/
http://localhost:8080/contact/
Great stuff, but that’s no use without a navigation! Let’s take a look at partials
and create a shared header
,navigation
, and footer
to bring our homepage together.
Creating our partials
In the terminal cd into _includes/
and create two partial files:
cd _includes && touch header.njk && touch navigation.njk && touch footer.njk
Open each of them up and add some front matter and content:
header.njk:
<h1>Welcome to my Homepage</h1>
navigation.njk
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/links/">Links</a>
<a href="/blog/">Blog</a>
<a href="/contact/">Contact</a>
footer.njk:
<p>This is my footer | © 2022 Me.</p>
Once our paritals are created, open base.njk
again and update to include our new elements and partials:
base.njk:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title }}</title>
</head>
<body>
<header>{% include 'header.njk' %}</header>
<nav>{% include 'navigation.njk' %}</nav>
<main>
<h1>{{ title }}</h1>
{{ content | safe }}
</main>
<footer>{% include 'footer.njk' %}</footer>
</body>
If you’ve kept 11ty running and the broswer running it should look like this:
Amazing! Now lets add the blog.
Creating the blog
Create a new directory blog
in the src
directory and cd into it:
mkdir blog && cd blog
Create the following pages in the src/blog
directory with the terminal or VSCode:
touch my-first-post.html && touch my-second-post.html && touch my-third-post.html && blog.json
Awesome, Open each of them up in VSCode and add the following:
my-first-post.html:
---
title: My First Blog Post
---
<p>This is my first blog post</p>
my-second-post.html:
---
title: My Second Blog Post
---
<p>This is my second blog post</p>
my-third-post.html
---
title: My Third Blog Post
---
<p>This is my third and final blog post</p>
blog.json
{
"layout": "blog"
}
We better create a blog layout so it renders!
Head back to the _includes
directory to create a new layout file:
cd ../_includes && touch blog.njk
Open blog.njk
up in VSCode and add the following:
blog.njk:
---
layout: base.njk
---
<article>{{ content | safe}}</article>
Check that your blog posts are loading:
- http://localhost:8080/blog/my-first-post/
- http://localhost:8080/blog/my-first-post/
- http://localhost:8080/blog/my-first-post/
Amazing right? But to make it a blog, we need a blog page that lists all of our blog posts in chronological order. We can do this with a tags
collection:
Open blogs.json
again and add a key called tags
with a value of blog
:
blog.json:
{
"layout": "blog",
"tags": "blog"
}
Now 11ty has created a collection called posts
and all we have to do ist list them.
Head back to the src/
directory create a blog.html
file:
cd .. && touch blog.html
Open it and add the following:
blog.html:
---
title: This Is My Blog
layout: base.njk
---
These are all of my amazing blog posts, enjoy!
<ul>
{% for post in collections.blog | reverse %}
<li>
<a href="">{{ post.data.title }}</a>
</li>
{% endfor %}
</ul>
If you’ve kept 11ty running and the broswer running it should look like this:
Amazing huh?
Add some styles
Great, so far we have a fully functional home page, but it doesn’t look quite right. We need a style sheet.
Create a new css
directory in src
cd into it and create styles.css
:
mkdir css && cd css && touch styles.css
Open styles.css
in VSCode and add the following:
styles.css:
/* Global variables. */
:root {
/* Set sans-serif & mono fonts */
--sans-font: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir,
"Nimbus Sans L", Roboto, Noto, "Segoe UI", Arial, Helvetica,
"Helvetica Neue", sans-serif;
--mono-font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
/* Default (light) theme */
--bg: #fff;
--accent-bg: #f5f7ff;
--text: #333;
--text-light: #585858;
--border: #d8dae1;
--accent: #0d47a1;
}
/* Dark theme */
@media (prefers-color-scheme: dark) {
:root {
--bg: #212121;
--accent-bg: #2b2b2b;
--text: #dcdcdc;
--text-light: #ababab;
--border: #666;
--accent: #ffb300;
}
}
* {
box-sizing: border-box;
}
html {
/* Set the font globally */
font-family: var(--sans-font);
scroll-behavior: smooth;
}
/* Make the body a nice central block */
body {
color: var(--text);
background: var(--bg);
font-size: 1.15rem;
line-height: 1.5;
margin: 0 auto;
max-width: 40em;
padding: 0 1em;
}
body > header {
text-align: center;
padding: 0 0.5rem 2rem 0.5rem;
box-sizing: border-box;
}
body > header h1 {
max-width: 100%;
margin: 1rem auto;
}
/* Format navigation */
nav {
border-bottom: 1px solid var(--border);
font-size: 1rem;
line-height: 2;
padding: 1rem 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding-bottom: 2rem;
}
nav a {
margin: 1rem 1rem 0 0;
color: var(--text) !important;
padding: 0.1rem 1rem;
}
nav a:hover {
color: var(--accent) !important;
}
nav a:last-child {
margin-right: 0;
}
/* Reduce nav side on mobile */
@media only screen and (max-width: 750px) {
nav a {
border: none;
padding: 0;
color: var(--accent);
text-decoration: underline;
line-height: 1;
}
}
/* Add a little padding to ensure spacing is correct between content and nav */
main {
padding-top: 1.5rem;
}
body > footer {
margin-top: 4rem;
padding: 2rem 1rem 1.5rem 1rem;
color: var(--text-light);
font-size: 0.9rem;
text-align: center;
border-top: 1px solid var(--border);
}
/* Format headers */
h1 {
font-size: 3rem;
}
h2 {
font-size: 2.6rem;
margin-top: 3rem;
}
/* Reduce header size on mobile */
@media only screen and (max-width: 720px) {
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 2.1rem;
}
}
/* Format links */
a,
a:visited {
color: var(--accent);
}
a:hover {
text-decoration: none;
}
This is a stripped down version of Simple.css. Thanks KevQ.
Now we need to include the style sheet in our base.njk
layout file. Open it up and add <link rel="stylesheet" href="/css/styles.css" />
_includes/base.njk:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/styles.css" />
<title>{{ title }}</title>
</head>
<body>
<header>{% include 'header.njk' %}</header>
<nav>{% include 'navigation.njk' %}</nav>
<main>
<h1>{{ title }}</h1>
{{ content | safe }}
</main>
<footer>{% include 'footer.njk' %}</footer>
</body>
You would have noticed that the stylesheet hasn’t been applied, we have to a couuple more things in .eleventy.js
, something called file passthrough copy.
Open .eleventy.js
in VSCode and add the following:
module.exports = function (eleventyConfig) {
eleventyConfig.addPassthroughCopy("./src/css");
return {
passthroughFileCopy: true,
dir: {
input: "src",
output: "public",
includes: "_includes",
},
};
};
Because this will come up we may as well create the directories and add in the configuration for our images, fonts and javascript files.
Create the following directories in src
:
mkdir img && mkdir fonts && mkdir js
Update .eleventy.js
again:
module.exports = function (eleventyConfig) {
eleventyConfig.addPassthroughCopy("./src/css");
eleventyConfig.addPassthroughCopy("./src/img");
eleventyConfig.addPassthroughCopy("./src/fonts");
eleventyConfig.addPassthroughCopy("./src/js");
return {
passthroughFileCopy: true,
dir: {
input: "src",
output: "public",
includes: "_includes",
},
};
};
Just make sure you put all your static files in the appropriate directory and you’ll be good.
So finally, if you’ve kept 11ty running and the broswer running it should look like this:
Amazing! Now if you’re happy with that you can take the contents of the public
directory and upload those to Neocities, however, the key thing in this is automating the rest with Github and the Neocities API - check again soon for the next parts where we will do just that.
Reference: I created this guide based heavily on the existing guides:
Without these, I wouldn’t even know how to write down what I needed to.