Trello + Sapper JAMstack (Part 3)
Tags: svelte, sapper, javascript, trello
Published: 2020-09-24 18:46:04

## Sapper setup

Setting up Sapper is very easy to install for more details check [here](https://sapper.svelte.dev/). I personally prefer Rollup.

```
# for Rollup
npx degit "sveltejs/sapper-template#rollup" my-app
# for webpack
npx degit "sveltejs/sapper-template#webpack" my-app
cd my-app

npm install
npm run dev & open http://localhost:3000
```

Once you have opened the project in your editor you will notice a confusing directory structure that may look daunting at first but it is pretty straight forward when it comes to producing your SSG part of Sapper.

```
└───routes
│   │   index.svelte
│   │   about.svelte
│   │   _layout.svelte
|   |   _error.svlete
│   └───blog
│       │   [slug].svelte
│       │   index.svelte
│       │   [slug].json.js
│       │   _posts.js
│       │   index.json.js
```

In Sapper, any file with `_` underscore at the beginning is a hidden/private file. Our logic to obtain blog posts via API from Trello happens in the `_posts.js` file which generates the right JSON files for the blog posts. `[slug].svelte` and `index.svelte` contains template responsible for list of posts and the post itself. `[slug].json.js` and `index.json.js` exports the JSON it is possible without these files and yet has SSG done but it is a major hit on the performance and is very much noticeable with my series on [headless WordPress and Sapper](https://dev.to/shriji/headless-wordpress-with-sapper-4b6j).


Snippet for `_posts.js`where we export a JSON object that has data for the blog post that could be populated on `index.svelte` and `[slug].svelte`

```js
//_posts.js

import fetch from "node-fetch";
let data = {};
let url = `https://api.trello.com/1/lists/5f538d3a842e0a3b6ce9f259/cards?key={key}&token={token}`; //this is from your previous post
let trello = async function getPosts() {
  const res = await fetch(url);
  data = await res.json();
  return (data = data.map((e) => {

    const months = ["jan", "feb", "mar","apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
    let posted_date = new Date(e.dateLastActivity)
    let formatted_date = `${posted_date.getDate()} ${months[posted_date.getMonth()]} ${posted_date.getFullYear()}`
    let tags = e.labels.map(e=>{
      return {
        name:e.name,
        color:e.color
      }
    })

    return { title: e.name, slug: e.name.toLowerCase().replace(/[^\w ]+/g,'').replace(/ +/g,'-'), desc: e.desc, image:e.cover.scaled,time:formatted_date,tags };
  }));
};

export default trello;

```
After a slight modification to `index.json.js` and `[slug].json.js` we can automatically get Trello items as blog posts.

```js

//index.json.js
import trello from "./_posts.js";

export async function get(req, res) {
  res.writeHead(200, {
    "Content-Type": "application/json",
  });
  let data = await trello();
  let posts = data;
  posts = posts.map((post) => {
    return {
      title: post.title,
      slug: post.slug,
      time: post.time,
      tags: post.tags
    };
  });
  res.end(JSON.stringify(posts));
}

```


```js
//[slug].json.js
import trello from './_posts.js';


const lookup = new Map();


export async function get(req, res, next) {
	// the `slug` parameter is available because
	// this file is called [slug].json.js
	const { slug } = req.params;
	let data = await trello()
	data.forEach(e => {
		lookup.set(e.slug, JSON.stringify(e));
	});
	if (lookup.has(slug)) {
		res.writeHead(200, {
			'Content-Type': 'application/json'
		});

		res.end(lookup.get(slug));
	} else {
		res.writeHead(404, {
			'Content-Type': 'application/json'
		});

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


}

```