Serverless Static Site Generation with Eleventy and Begin
Tags: serverless, aws, cloud
Published: 2021-01-17 02:38:03

Today, we're going to build a serverless blog using [Eleventy](https://www.11ty.dev/), storing the site's source code and static content on GitHub, then deploy for free on Begin. No credit card or AWS account needed. 

# Try out Eleventy with Begin right now! 
Hit this button to deploy an Eleventy blog to begin (no credit card required!) in 15 seconds: 

[![Deploy to Begin](https://static.begin.com/deploy-to-begin.svg)](https://begin.com/apps/create?template=https://github.com/begin-examples/node-eleventy-blog)

## Create a new Architect project
[Architect](https://arc.codes) is an open-source serverless framework hosted by the OpenJS Foundation. Architect provisions AWS resources like S3 and API Gateway using infrastructure as code. Architect will also grant least privileged IAM roles for those resources enabling better security by default. 

We'll start by installing our dependencies. 
```bash
npm i -g @architect/architect
mkdir eleventy-blog
cd eleventy-blog
npm init -y
npm install @11ty/eleventy @architect/sandbox 
```
Create an `app.arc` file in the project root. This file defines the app structure and cloud resources. Working this way gives developers deterministic deployments with declarative infrastructure that can be committed to GitHub alongside the source code. 

```
# eleventy-blog/app.arc
@app
eleventy-blog

@static
folder _site
spa false

@http

@tables 
data
  scopeID *String
  dataID **String
  ttl TTL 
```

## Using Eleventy and AWS S3
Eleventy is a lightweight static site generator that uses templating and markdown to render HTML. AWS S3 is an object storage service that can be configured to serve static assets to the public internet. This avoids the need for a dedicated web server. 

We can now create a layout template, an index page, a posts page, and some markdown files. In this example, we will use Shopify's Liquid templating language. Templates wrap your content with markup and let you iterate over data collections like individual posts. Start by creating `_includes/layout.liquid`:
```html
<!doctype html>
<html lang="en">
  <head>
    <title>The Logs of the Web</title> 
    <meta charset="utf-8">
  </head>
  <body>
    <nav>
      | <a href="/">World Wide Web Log</a> |
      <a href="/posts" title="Posts">Posts</a> |
    </nav>
    <section>
     <p> {{ content }}</p>
    </section>
  </body>
</html>
```
Create an index.html file in the root of our app

```html
---
layout: layout.liquid
pageTitle: The Index Page
---
<section>
  <h2>Cool Blog</h2>
  <article>
    <h1 >{{ pageTitle }}</h1>
    <p><em>"I think I jump around more when I'm alone."</em></p>
  </article>
</section>
```
Modify the scripts in `package.json`
```javascript
# package.json
"scripts": {
    "build": "eleventy",
    "watch": "eleventy --serve",
    "start": "run-p watch sandbox",
    "sandbox": "ARC_STATIC_SPA=false npx sandbox"
  }
```
Now you can use `npm start` and Eleventy will build your HTML into a `/_site` folder and `@architect/sandbox` will start a local development server.

Take a look at your shiny site by visiting localhost.

## Creating posts
We can organize our markdown files in a folder named `/posts`. Eleventy turns these markdown files into HTML. A `posts.json` will allow Eleventy to expose the posts as a collection to feed the template data at build time. Our first file will be `/posts/hello-world.md`

```html
---
pageTitle: The First Post
imgURL: "https://www.placecage.com/g/400/300"
---
# Hello World
- Nicolas Cage owned a pet octopus who helped him with his acting.
```
Create a `/posts/post.json` file.

```javascript
{ "layout": "layout.liquid", "tags": ["posts"] }
```

Let's create a `/eleventy-blog/posts.html` that will display all of our posts. 

```html
---
layout: layout.liquid
pageTitle: Caged Logs
---
{% for post in collections.posts %}
<section>
  <article>
  <h1><a href="{{ post.url }}">{{ post.data.pageTitle }}</a></h1>
  <p> {{ post.templateContent }}
  <em>{{ post.date | date: "%Y-%m-%d" }}</em>
  </p>
  <img src="{{ post.data.imgURL }}" class="db" alt="Grey Photo of Cage.">
  </article>
</section>
{% endfor %}
```
Try it out now by running `npm start` and try styling it however you like.