How To Build A JAMstack Website With TakeShape
Tags: design, tutorial, learning, webdev
Published: 2018-10-24 21:17:26

---
title: How To Build A JAMstack Website With TakeShape
published: true
description: Learn how to build a JAMstack design portfolio with TakeShape. Part 2 of a 4 part series on getting started with TakeShape.
tags: design, tutorial, learning, webdev 
canonical_url: https://www.takeshape.io/articles/how-to-build-a-jamstack-website-with-takeshape/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/0mkjtds4cyrx6ubq1s0b.jpg
---

## In part 2 of this 4 part series, you'll learn how to use a headless cms to build a static site.

This is part 2 of the 4 part series. Check out part 1 to get an introduction to [TakeShape](https://www.takeshape.io/) and learn content modeling and content creation. In part 3 (coming soon) you’ll learn how to deploy your static site to Netlify. In part 4 (coming soon) you’ll extend your skills even further and learn how to use TakeShape with Gatsby.js.

![A screenshot of the JAMstack site you’ll be building.](https://thepracticaldev.s3.amazonaws.com/i/4g8kx0b0z5qt62u86cw5.png)

In part 1 you learned how to model and create content and making it available through TakeShape’s GraphQL API. Now you’ll learn how to use TakeShape’s static site generator in combination with that API to quickly create a JAMstack website. You’ll create and configure a TakeShape static site on your local machine, write GraphQL query files and use data returned from those queries in HTML templates.

If you want to skip setting up your static site from scratch, you can grab the “[Shape Portfolio](https://shape-portfolio.takeshapesampleproject.com/)” sample template as a starting point. Simply run the command `git clone https://github.com/takeshape/takeshape-samples.git && cd takeshape-samples/shape-portfolio`. This will download a static site [repo](https://github.com/takeshape/takeshape-samples) that’s pre-configured to work with the “Shape Portfolio” template in TakeShape. This repo has a more complex, styled, and scripted version of what we just built together. It might give you some inspiration and guidance on where to take your portfolio next.

If you decided to stay, we’ll be building that same `shape-portfolio` static site from scratch so you can learn how it works. Ready, set, go!

### Hello Portfolio

You’re going to start by cloning the `blank-project` template from Github, this will provide you with a [bare-bones TakeShape setup](https://github.com/takeshape/takeshape-samples.git). First, clone the repository to your computer, then copy the blank-project out into a new folder, and finally remove the cloned repo since you don’t need anything else from it. In your terminal, it looks like this:

```
> git clone https://github.com/takeshape/takeshape-samples.git
> cp -r takeshape-samples/blank-project/ shape-portfolio
> rm -rf takeshape-samples
```

Then you’ll enter the newly copied project folder, install the required software needed to run the project with npm, and initialize it with the TakeShape configuration:

```
> cd shape-portfolio
> npm install
> npm run init
```

Running `init` will establish the connection between your local development environment and the TakeShape service. You’ll be prompted to make several sections to configure your environment. The first prompt will be for your TakeShape credentials. Input your TakeShape account email and password, then use the arrow keys to select your portfolio project. You’ll get a reminder about not having any sites set up yet (don’t worry, we’ll get to that in Part 3).

The initialization creates two files, `.tsgrc` and `graphql.config.json`. These are already in your project’s `.gitignore` file because you started with the blank-project template.

You can now test that everything’s been set up correctly by running `npm start`. If everything goes as expected, your default browser will open to `localhost:5000` and display the blank-template page. Hooray! You’ve just run TakeShape from your local machine. Now it’s time to start hacking on your portfolio 🤓. If you get an error or aren’t able to load the site read any error messages that are output to the terminal to debug the problem.

### Project Structure

By cloning the `blank-project` template, you’ve been provided with some of the basic files and folders that TakeShape expects. We’ll explain a bit more about each of them now.

#### Configuration

At the root of your project is a file called `tsg.yml`. It holds the configuration for your project and it’s the best place to start. Here’s what’s in `tsg.yml`:

```
templatePath: src/templates
staticPath: static
buildPath: build

routes:
  homepage:
    path: /
    template: pages/index.html
```

* At the top is the `templatePath` variable, which tells TakeShape where to look for template files when building your project.
* Next is the `staticPath` variable, which tells TakeShape where to look for files like stylesheets, scripts, and static images like favicons.
* After that is the `buildPath` variable, which is where TakeShape will place your project after it’s been built.
* Finally, there’s the `routes` variable. Each child of this variables configures the routing rules of your project. Right now we only have the `homepage` route, which specifies the routing path (the index path, in this case) and what template file the route should use. Templates are all relative to the `templatePath` set at the top of the file.

There are more complex ways to build routes, including dynamic variables that comes from the content you’ve created in TakeShape. We’ll get to this in a moment. First, let’s take a look at the templates you’re going to use.

### Template Files

By default, TakeShape uses the [Nunjucks](https://mozilla.github.io/nunjucks/) templating system.

The `src/templates` folder contains three starter subdirectories: `data`, `layouts`, `pages`. `data` contains GraphQL query files that retrieve content from the TakeShape API. `pages` contains individual unique page templates. `layouts` contains a base template that other templates extend. Inside `layouts` is a starter layout template called `default.html`, which looks like this:

```
<!doctype html>

<html>
<head>
  <title>Blank Project - TakeShape</title>

  <meta charset="utf-8">

  <link rel="stylesheet" href="/stylesheets/main.css"/>
  <link rel="author" href="humans.txt"/>
</head>

<body>

<div class="main">
  {% block content %}{% endblock %}
</div>

<script src="/javascripts/main.js"></script>
</body>
</html>
```

As you can see, this provides the basis for other pages to wrap themselves in the layout by using Nunjuck’s extend functionality. Extending is accomplished by using the using `{% extends "layouts/default.html" %}` and `{% block %}` tags.

In `pages/index.html` you can see how this template extends the default layout:

```
{% extends "layouts/default.html" %}

{% block content %}
  <h1>Blank Project Template For TakeShape</h1>
{% endblock %}
```

With these basic foundations, you can build plenty of pages with minimal repetition.

#### Static Files

Finally, we’ll take a quick look at static files like stylesheets and scripts. The starting `default.html` template above already links to the files `/stylesheets/main.css` and `/javascripts/main.js`. You’ll find these files in the top-level `static` directory.

### Building your portfolio

#### Homepage

Now that you know how everything fits together, you can start customizing your homepage to create an amazing portfolio!

First, you’ll want to display your projects on your homepage. To do this, you’ll need to add some data to the homepage route, write a query, and then render the data on the homepage. To add data to the route, you’ll update your homepage route configuration in `tag.yml` to look like this:

```
routes:
  homepage:
    path: /
    template: pages/index.html
    context: data/projects.graphql
```

Then create a `projects.graphql` file in the `src/templates/data` directory. In this file, you’re going to craft the query for your project data that’s sent to the TakeShape API.  As long as you set up your Project content type following the pattern in Part 1, your file should look like this:

```
query {
 projects: getProjectList {
   items {
     name
     coverImage {
       path
     }
   }
 }
}
```

Now, you can use `projects` as a variable in our homepage template in order to render a list of all projects on the homepage. In `pages/index.html` you’ll update it to look like this:

```
{% extends "layouts/default.html" %}

{% block content %}
<ul>
  {% for project in projects.items %}
  <li>
      <img src="{{project.coverImage.path|image({h: 200, w: 300, fit: 'crop'})}}">
      <p><strong>{{project.name}}</strong></p>
  </li>
  {% endfor %}
</ul>
{% endblock %}
```

For the cover image, note the `image` filter being applied to the image’s path. TakeShape users get to host their images on [imgix](https://www.imgix.com/), an amazing and powerful image CDN, for free! The `image` filter is a [special TakeShape filter](https://www.takeshape.io/docs/template-tags/) that accepts IMGIX filter parameters and returns the imgix URL for the image. We’ve set a custom height and width on the image and we’ve told imgix to crop the image to fit these dimensions. All the potential options are listed on [imgix’s comprehensive API documentation](https://docs.imgix.com/apis/url).

#### Standalone project pages

Next, you’ll want to create standalone pages for your projects so that you can provide more detail about each one and link to projects directly.

To get started, update your `tsg.yml` configuration with a new route for project pages:

```
  project:
    path: /projects/:name/
    template: pages/project.html
    paginate:
      data: data/projects.graphql
      itemName: project
```

This is a little more complex than our last route, so let’s break it down:

* The `path` uses the variable `:name` in order to render a unique URL for each project page. This variable comes right from the query we’re using in the `paginate` variable.
* `paginate` tells TakeShape how to split up the data from the `projects.graphql` query we created earlier into individual pages. In this case, each `item` in the query will get its own page. `itemName` sets the variable that refers to each paginated item. In this case, we’ll access data from a variable named `project`.


Next, you’ll want to add a few more fields to the `projects.graphql` query so that you can present more information about each project on its standalone page. Update your query to look like this:

```
query {
  projects: getProjectList {
    items {
      name
      startDate
      endDate
      coverImage {
        path
      }
      descriptionHtml
      client {
        name
        url
      }
    }
  }
}
```

Pretty straightforward! Think you’re getting the hang of building a site in TakeShape? Remember, you can explore the API for your entire project in TakeShape’s web interface. It’s really handy when writing queries yourself.

Now, you can create the `pages/project.html` template to render out the project data into HTML. Here’s what that will look like:

```
{% extends "layouts/default.html" %}

{% block content %}
<article class="project">
  <header>
	<img class="project__cover-image" src="{{project.coverImage.path|image({h: 600, w: 1200, fit: 'crop'})}}">
	<h1>{{project.name}}</h1>
	<div class="project__metadata">
  	<p>{{project.startDate|date('YYYY')}}{% if project.endDate %} – {{project.endDate|date('YYYY')}}{% endif %}</p>
  	{% if project.client %}
  	<p><a href="{{project.client.url}}">{{project.client.name}}</a></p>
  	{% endif %}
	</div>
  </header>
  <div class="project__description">{{project.descriptionHtml|safe}}</div>
</article>
{% endblock %}
```

This is pretty straightforward, too! Notice how the built-in TakeShape `date` filter is being used to format the start and end dates of your project so only the year is displayed. Also, notice that the `safe` filter must be applied to the project description. This is because it’s output from the TakeShape API as raw HTML.

Now that each of your projects has a page, you want to be able to link to individual projects from your homepage. On the homepage template, wrap each project list item with an anchor tag `<a href="{{project|route('project')}}">`. It should look like this:

```
{% extends "layouts/default.html" %}

{% block content %}
<ul>
  {% for project in projects.items %}
  <li>
	<a href="{{project|route('project')}}" title="{{project.name}}">
  	<img src="{{project.coverImage.path|image({h: 200, w: 300, fit: 'crop'})}}">
  	<p><strong>{{project.name}}</strong></p>
	</a>
  </li>
  {% endfor %}
</ul>
{% endblock %}
```

`route` is another special TakeShape filter. If you have a route defined for an object, like the one that defined a dynamic path for the project pages, then the `route` filter will return the route for that item. It’s pretty handy! Just refer to the name of the route as it appears in your `tsg.yml` and you’ll be good to go!

Now, if you run `npm start` in your terminal, the website should build successfully. You will see a homepage with a list of your projects and you should be able to click through to each one.

For a next step, you can try creating an About page using your biography, or a page that lists all of your clients. Make sure to check out TakeShape’s documentation if you get stuck writing your configuration or templates.

## Next Steps

In part 3 we’ll take the static site you just created and deploy it to Netlify! In just a few steps, you’ll be able to deploy your site to Netlify’s CDN and host your page on a secure HTTPS connection. How cool is that?

Until then, keep hacking!

## Interested in JAMstack CMS?

JavaScript, APIs, and Markup, are the JAMStack. [TakeShape](https://www.takeshape.io/) is a headless GraphQL CMS and static site generator for building JAMstack websites. At TakeShape we're committed to building the best CMS tools possible for the most creative designers and developers. With our project templates, it's easy to get started. Plus, pricing is flexible and affordable. [Sign up for a free account](https://app.takeshape.io/signup) and spend more time being creative!