Glenn Jones

Hello 👋 Welcome to my corner of the internet. I write here about the different challenges I encounter, and the projects I work on. Find out more about me.

Building a static website with middleman and prismic.io

Lately, many have come to realize the potential and advantages of using static site generators to produce quick and effective websites. I won’t go into the specifics of all the different generators, but we use Middleman, simply because it stuck over the years.

In building static sites, there’s one thing that really sucks. It’s dealing with (client) content. As with many things in progress, many many many revisions, ranging from a complete overhaul to small corrections, are required. With static site generators, this poses a problem, since the writer passes the adjustments to the developer, who must then adjust the source files and deploys the new site.

This costs enormous amounts of time, ‘dumb time’, and so we set out to find a solution.

The solution comes in the form of Prismic.io, an API-based content management system. In short, it allows your writers to write their content and upload and adjust their images in a different place than where the developer is working. The developer has ‘read-only’ access to the content, so next time there is an adjustment, the site only has to be rebuilt and deployed. Sounds awesome and I can confirm, it’s pretty awesome.

We at Nebulae2016 are quite lazy, so we set up the site to be built automatically by CircleCI when new content is published on Prismic.io (through their webhooks). The site gets published to gh-pages, so except for prismic.io’s costs, it’s pretty much free.

So, in this article, I will outline how I integrated Prismic.io into a Middleman 4.1.7 project. I will show exactly how I set-up, connect to, query and display the Prismic data. Doing so, I also share some of my more general opinions on Prismic.

Set up

One of the things I like about prismic, is the clear distinction between writer and developer. After making a ‘repository’ on prismic - functionally a synonym for project - the area the writers can work in is immediately visible. Under ‘settings’ however, you’ll find everything you need for development. In this project we’ll touch only on custom types.

picture of blank interface of prismic

To integrate prismic into your project, you’ll have to think about the type of content you’re going to display. You have to think about the structure of that content. Why? Because prismic allows you to very precisely define the different ‘types’ that shape your content. You do this through Settings/Custom Types.

For example, one of our recent projects is a one-pager to apply to an accelerator, which has to be adjusted for different branches of the accelerator (so multiple versions of the same template, with minor differences in content and deployed to different domain names). I chose to define one custom type named ‘apply-page’ and in there, define all the fields.

Defining the types is fairly straightforward, it’s in JSON and a reference for the types can be found in the prismic documentation. Just focus on the define part.

A few nice properties of the type definitions: you can set a field type ‘image’, which allows the content creator to upload and crop images according to their own needs. You can also set StructuredText, which allows content creators to use regular yet choosable typographic styling elements (bold, italic, heading, link and more) in their text.

Another nice thing are groups, I see them as nested groups of fields, where the content creator can decide whether to add a group-item, or not. It’s nice because type definitions restrict the content quite tightly, and the groups are a way to allow more flexibility, ‘within’ set bounds.

So, when you’ve defined your types (also called ‘masks’), quickly fill-out some dummy content by going to the tab ‘Everything’ and then click ‘Write Something’ in the top right corner.

Now you’re ready to start querying that in your local environment.

Connecting to the API and Querying the data

What I’m about to tell can also (partly) be read here. Add the following to your Gemfile and bundle in the root of your project. Then proceed to your prismic.io dashboard and go to settings/Api & Security to find the link to connect to your repository.

gem 'prismic.io', '~> 1.3', '>= 1.3.3', require: 'prismic'

Now, in your config.rb, you can add:

# Prismic Settings
api = Prismic.api('https://middleman-example-repo.prismic.io/api')

# duplicate this for subsequent pages from prismic
data_apply = api.form('everything')
                .query(Prismic::Predicates::at('document.type', 'apply-page'))
                .submit(api.master_ref)
                .results.first

# Pass that data to the page
page "/index.html", locals: { results: data_apply }

What happens here is, I initiated the Prismic API object, passed some standard settings to it (only the name of your document type needs to be adjusted and yes this is the same as your ‘custom type’). In my case there’s only one document of this type, hence the .first.

With multiple documents, you can tag a document in the prismic editor, and then you can filter for document types with that tag. That’s not in the above example though.

A last step, you pass the data to your specified page through assigning it as a local variable.

Displaying the Data

Prismic has some standard helpers to get the values out of the so called ‘fragments’ that you receive back from the API. These can be found in the reference.

However, these require me to wastefully input the same api object each time I use a helper and as I’ve put all data in one custom type, this is redundant.

Combined with the fact that the ‘fragments’ are a hash containing the data I need, I wrote the following helpers. Place this in your config.rb.

helpers do
  def set_prismic_helper_settings(prismic_document_type, results)
    @page = prismic_document_type
    @result = results
  end

  def get_text_helper(attr_name)
    if @result["#{@page}.#{attr_name}"].present?
      return @result["#{@page}.#{attr_name}"].as_html()
    else
      ""
    end
  end

  def get_rich_text_helper(attr_name)
    resolver = Prismic.link_resolver('master'){ |doc_link| "http:#localhost/#{doc_link.id}" }
    return @result["#{@page}.#{attr_name}"].as_html(resolver)
  end

  def get_group_helper(group_name)
    if @result["#{@page}.#{group_name}"].present?
      return @result["#{@page}.#{group_name}"]
    else
      []
    end
  end
end

Which needs the following ‘initiator’ at the top of the view file (I use SLIM for templating).

- set_prismic_helper_settings('apply-page', results)

And then you can simply call the helper methods for text, structured text and groups (those are all the types I needed, for now).

- set_prismic_helper_settings('apply-page', results)

h1 = get_text_helper('intro-heading')
p = get_rich_text_helper('stories-body')

- events = get_group_helper('events')
- events.each do |e|
  h3 = e['name'].value + ", " + e['date'].value

Images work a bit differently, especially if you’d like to use automatically generated thumbnails. Nice part is prismic uploads these all to Amazon S3, so there’s literally nothing to worry about.

To find an image url, call the name of image from the hash of the fragment and append .main.url. To find the thumbnail url, call the name of the image from the hash and append .get_view('small').url, requiring that you’ve called a thumbnail size ‘small’.

Development Workflow

My general workflow was as follows:

  1. Adjust the JSON of the custom type
  2. Unpublish dummy content, do adjustments, republish the content.
  3. Restart middleman server (the api object is retrieved in the config.rb and everytime something needs to be refreshed there, the server needs to be restarted).
  4. Adjust view layer to correctly show the data.
  5. Repeat cycle for bugs or next fields.

For some reason, working with data from Prismic.io seems to slow me down in development. Of course, I’m pulling the data from an external source, adding complexity to the system.

Also, the strict type definitions, in the JSON, slow me down significantly. I must say, the inline debugger from prismic.io works really well. I’m very glad it’s there.

Thoughts

Prismic.io is a nice tool to use. There is however one point on which can be improved quite substantially, to my opinion. The documentation is complete but fairly scattered. I seemed to have to bounce back and forth a lot between different pages and different points of access to documentation, to figure out how to do things. Right now I only refer to one or two pages, because I know it’s possible to make sense of the whole through those two. To get there however, the get started guide was too un-inclusive and the said references was too in-detail.

That said, the set up of Prismic.io for the whole apply page took about 8-10 hours of work, including figuring out how it - thus far - works. I know there is a lot more to be discovered, with dynamic page content (slices) and such.

Already prismic has saved us good amounts of time, definitely making it worth using the tool. I’d recommend at least exploring it a little bit. If you’re a web developer or working in a studio/agency, this will for sure save you a lot of headache. It’s a joy not to lose so much time every time a client projects’ copy progresses.

Links

Next: Rails 4 has many through source with condition