Context Specific Assets with Jekyll

November 3, 2017

Jekyll is pretty cool, but I ran into a case where I needed to including images, CSS and JavaScript for specific posts, pages and collections. I wanted to have these assets organized separately from the core styles and JavaScript as well. So I put together a method of doing this using a clever trick. Create a file in Jekyll’s _includes directory called asset.html then copy and paste the following:

{%- capture type -%}
  {%- if page.layout == "post" -%}
    posts
  {%- elsif page.collection -%}
    {{ page.collection }}
  {%- else -%}
    pages
  {%- endif -%}
{%- endcapture -%}

{%- capture context -%}
  {%- if page.layout == "post" -%}
    {{ page.path | split:"/" | last | split:"." | first }}
  {%- else -%}
    {{ page.title | slugify }}
  {%- endif -%}
{%- endcapture -%}

{{ site.url }}{{ site.baseurl }}/assets/{{ type }}/{{ context }}/{{ include.file }}

Now, within our posts, pages and collections, we can include an image like so:

<img src="{% include asset.html file="filename.jpg" %}" alt="">

Using the asset include file in our header and footer we can point to context specific styles and scripts. We’ll just add a few items to our front-matter to specify which files we want included. This can be either single files or a list:

---
include:
  css: styles.css
  js:
  - library.js
  - scripts.js
---

Then in our header and footer we’ll loop through each item in the includes and link to those resources. Keep in mind that we’re using our new asset.html include to get the post or page specific path to these files.

{% if page.include.css %}
  {% for file in page.include.css %}
  <link rel="stylesheet" href="{% include asset.html file=file %}">
  {% endfor %}
{% endif %}

{% if page.include.js %}
  {% for file in page.include.js %}
  <script src="{% include asset.html file=file %}"></script>
  {% endfor %}
{% endif %}

With the above example—if we added those includes from our homepage—the paths would look like this:

<link rel="stylesheet" href="http://domain.com/assets/pages/home/styles.css">

<script src="http://domain.com/assets/pages/home/library.js"></script>
<script src="http://domain.com/assets/pages/home/scripts.js"></script>

How it works

The first step is to decide how you want to organize context specific assets. I liked the idea of having a unique directory for posts, pages and then any collections I’ve added. Of course you can organize this any way you’d like, but here’s what I settled with:

assets/
  pages/
    home/
    work/
    follow/
    ...
  posts/
    2017-10-12-post-title-here/
    2017-11-15-post-title-here/
    2017-12-22-post-title-here/
    ...
  collection-1/
    item-1/
    item-2/
    item-3/
    ...
  collection-2/
    ...

For the base directory we want to capture the appropriate string based on a few checks to determine wether it’s a post, page or collection. The first check is if the item is a post by checking if we’re using the post layout. Then we check if it’s part of a collection and we use the name of the collection if it is. If all of these cases fail, then that means it’s a page.

{%- capture type -%}
  {%- if page.layout == "post" -%}
    posts
  {%- elsif page.collection -%}
    {{ page.collection }}
  {%- else -%}
    pages
  {%- endif -%}
{%- endcapture -%}

Next we grab the title specific directory. This is done by using the current page’s title or the page.path variable if it’s a post.

{%- capture context -%}
  {%- if page.layout == "post" -%}
    {{ page.path | split:"/" | last | split:"." | first }}
  {%- else -%}
    {{ page.title | slugify }}
  {%- endif -%}
{%- endcapture -%}

Now we combine all these elements together with the file name parameter that’s passed through our include to get our context specific path that matches our organization structure.

{{ site.url }}{{ site.baseurl }}/assets/{{ type }}/{{ context }}/{{ include.file }}

Putting all this together in _includes/asset.html and our include is now ready to use.

{% include asset.html file="filename.ext" %}

I hope you found this Jekyll code helpful. You can grab the code from this gist of asset.html.