Svelte + Sapper + Netlify CMS
Tags: javascript, svelte, sapper, webdev
Published: 2020-05-18 13:53:56


<br>

### Introduction


Hello.

In this post, I'll be outlining how to get started with [Svelte](https://svelte.dev/), [Sapper](https://sapper.svelte.dev/) and [Netlify CMS](https://www.netlify.com/).

This article assumes some baseline knowledge of Svelte, Sapper and various configuration options specific to Netlify's CMS.

**Documentation**

- [Svelte Documentation](https://svelte.dev/docs/)
- [Sapper Documentation](https://sapper.svelte.dev/docs/)
- [Netlify CMS Documentation](https://www.netlifycms.org/docs/intro/)

You can find the repo for this project [here](https://github.com/avcohen/tutorial_svelte_sapper_netlify).

<br>

### What we'll accomplish

- Setup a Svelte / Sapper project
- Setup a Netlify Project + Netlify Authentication
- Configure Netlify to automatically build & deploy to Github
- Refactor Sapper to statically generate blog posts from Markdown

<br>

### Setting up Svelte & Sapper

The team at Sapper has setup a great starter template that we'll use to skip a lot of the tedious aspects of starting from scratch.

It's also pretty damn un-opinionated so even if you decide to grow this into a larger project, you won't be locked into anything.

We'll be opting to use the [Rollup](https://rollupjs.org/guide/en/) based bundler since at the time of this writing it is better documented for use with Sapper.

```shell
npx degit "sveltejs/sapper-template#rollup" my-app
```

`cd` into `my-app` and run

```shell
npm i && npm run dev
```

You should see your console output

```shell
> Listening on http://localhost:3001
```

Open `http://localhost:3001` in your browser and take a peek.

![Step One Setup Image](https://dev-to-uploads.s3.amazonaws.com/i/78qv4r4q1mjh99aoz7qq.jpg "Step 1")

Now that we're up and running, we can start getting things organized in our code to get everything linked up to Netlify.

<br>

### Setup Netlify + Netlify Authentication

First we'll have to create a new folder within `~/static` called `admin`. Therein we'll create two files, `config.yml` and `index.html`.

First, let's drop in a simple config for Netlify's CMS so we can outline how we'll structure our blog post entries:

```yml
# ~/static/admin/config.yml

backend:
  name: git-gateway
  branch: master # Branch to update (optional; defaults to master)

publish_mode: editorial_workflow # Allows you to save drafts before publishing them
media_folder: static/uploads # Media files will be stored in the repo under static/images/uploads
public_folder: /uploads # The src attribute for uploaded media will begin with /images/uploads

collections:
  - name: "blog" # Used in routes, e.g., /admin/collections/blog
    label: "Blog" # Used in the UI
    folder: "static/posts" # The path to the folder where our blog posts are stored
    create: true # Allow users to create new documents in this collection
    fields: # The fields for each document
      - { label: "Slug", name: "slug", widget: "string" }
      - { label: "Title", name: "title", widget: "string" }
      - { label: "Body", name: "body", widget: "markdown" }
```

Next, let's add the markup for the `/admin` route:

```html
<!-- ~/static/admin/index.html  -->

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Content Manager</title>
  </head>
  <body>
    <!-- Include the script that builds the page and powers Netlify CMS -->
    <script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script>
    <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
  </body>
</html>
```

<br>

### Refactoring for Markdown

If you're not familiar with how Sapper handles dynamic URL parameters, check out their documentation on [routing](https://sapper.svelte.dev/docs#Routing).

We'll be editing our `~/src/routes/blog/[slug].json.js` to read markdown files from the filesystem, parse the Markdown + Frontmatter, and render the data into our component.

We will also need to edit `~/src/routes/blog/index.json.js` to extract the various titles and slugs from our posts in order to display them on the `/blog` route.

For this, we'll make use of [gray-matter](https://github.com/jonschlinkert/gray-matter) to handle the Frontmatter which is in YAML and [marked](https://github.com/markedjs/marked) to parse our Markdown.

Install these two dependencies via npm:

```shell
npm i marked gray-matter
```

Let's also create a folder where our blog posts will live. Create a folder called `posts` within `~/static`. We told Netlify to save posts here with the line

```yaml
folder: "static/posts"
```

in our `config.yaml` for our blog collection.

Next, let's setup our `[slug].json.js` file to put these two libraries to use:

```javascript
// ~/src/routes/blog/[slug].json.js

import path from "path";
import fs from "fs";
import grayMatter from "gray-matter";
import marked from "marked";

const getPost = (fileName) => {
  return fs.readFileSync(
    path.resolve("static/posts/", `${fileName}.md`),
    "utf-8"
  );
};

export function get(req, res, _) {
  const { slug } = req.params;

  const post = getPost(slug);
  const renderer = new marked.Renderer();

  const { data, content } = grayMatter(post);
  const html = marked(content, { renderer });

  if (html) {
    res.writeHead(200, {
      "Content-Type": "application/json",
    });

    res.end(JSON.stringify({ html, ...data }));
  } else {
    res.writeHead(404, {
      "Content-Type": "application/json",
    });

    res.end(
      JSON.stringify({
        message: `Not found`,
      })
    );
  }
}
```

Next we'll modify our `~/src/routes/blog/index.json.js` file to read all the files within our `~/static/posts` directory and pluck out the information required to render and provide links to each article.

```javascript
// ~/src/routes/blog/index.json.js
import fs from "fs";
import path from "path";
import grayMatter from "gray-matter";

const getAllPosts = () => {
  try {
    return fs.readdirSync("static/posts/").map((fileName) => {
      const post = fs.readFileSync(
        path.resolve("static/posts", fileName),
        "utf-8"
      );
      return grayMatter(post).data;
    });
  } catch (e) {
    return [];
  }
};

export function get(_, res) {
  res.writeHead(200, {
    "Content-Type": "application/json",
  });
  const posts = getAllPosts();
  res.end(JSON.stringify(posts));
}
```

Since we're no longer using the original data source for the blog posts `~/src/routes/blog/_posts.js` we can delete that file.

Also, since we're passing our JSON data from `[slug].json.js` to `[slug].svelte` with the same structure as before, we don't need to make any changes to the latter file.

<br>

### Setting up Netlify & Git Repo

At this point, we've _nearly_ got our ducks in a row to deploy our site and start writing blog posts.

First, create a new repo and push your code to it.

Next, head on over to [Netlify](https://app.netlify.com/) and click 'New Site from Git', select your Git provider of choice, authorize the Netlify App and allow access to all or for more granularity, select the repos you want Netlify to have access to.

![Step Two Setup Image](https://dev-to-uploads.s3.amazonaws.com/i/9cienmlnxgczmteti8of.jpg "Step 2")

Make sure you specify the build command and publish directory like so and mash that 'Deploy Site' button.

![Step Three Setup Image](https://dev-to-uploads.s3.amazonaws.com/i/vm1ezpd22jyh400pmant.jpg "Step 3")

If you head back to your Netlify dashboard you should see that your site is building and as soon as it's published, you can preview a link to the site.

Last but not least, we need to enable the **Identity** and **Git Gateway** features so you can signup/login via the `/admin` path on your newly deployed site to manage posts as well as allow Netlify to publish changes to your Git repo to trigger new static builds.

**Identity**
![Step Four Setup Image](https://dev-to-uploads.s3.amazonaws.com/i/nwwoq0gy3gt2l578cvwn.jpg "Step 4")

**Git Gateway**
![Step Five Setup Image](https://dev-to-uploads.s3.amazonaws.com/i/hxcg8si8y2ftsdq1dyu0.jpg "Step 5")

### Logging into the CMS

Head on over to your live site and add the `/admin` path to your URL.

Click 'Sign Up', create an account, confirm your account via the automated email from Netlify and jump back over to `/admin` and give it a refresh.

Login with your account and get writing.

<p style="text-align: center;">###</p>

Thanks for reading. If you’d like to stay up to date with my writings and projects, please follow me on [Twitter](https://twitter.com/aaronvcohen) or consider supporting my writing by buying me a [coffee](https://ko-fi.com/avcohen).