whateverthing.com

Whateverthing, now with a taste of Tailwind

The new Whateverthing is here!

I've redesigned the site in TailwindCSS and I'm very happy with how it came out. The previous design, based on Foundation 3, was alright, but it's been increasingly hard to find docs for Foundation 3 since it was becoming so ancient.

What is Tailwind?

Tailwind is a utility-first CSS library from Adam Wathan. Where other CSS frameworks aim to provide intent-based abstractions of CSS styles, Tailwind essentially maps 1:1 to actual CSS directives. You can use this approach to build complex interfaces with simple, clear implementations of your design's components.

"If you're sick of fighting the framework, overriding unwanted styles, and battling specificity wars, Tailwind was made for you."

Read more at the Tailwind website.

What Came Before

Here are a couple of screenshots of what the site used to look like in Foundation 3:

Desktop view of previous design: Mobile view of previous design:

The First Hurdle

The upgrade started out well. I went in and stripped out a whole bunch of Foundation-esque classes and divs, making room for being able to put in Tailwind-style utility classes.

Toward the end of the project, I hit a hurdle that I thought I had already solved. In fact, it was a hurdle that has vexed me many times before: Footers!

I wanted a page footer that would always be at the bottom, even if there was only a half-screen worth of information on the page. And, I wanted it so that the bottom-anchored footer wouldn't stick to the bottom of the viewport on mobile.

I had thought my implementation was working, but when I tested on an actual iPhone I found out that Firefox's "responsive mode" couldn't fully replicate the quirks of Mobile Safari rendering.

After a lot of searching, I asked my friend JF Godin for advice. He pointed me to a page of Flexbox resources, and from that I was able to find the exact solution I needed.

That solution turned out to be setting the body to flex flex-col min-h-screen, and then setting my main section of content to flex-1. This turned the page into a series of vertically-arranged blocks & made the middle one expand to the full screen height.

For a dedicated explanation of it, check out this helpful blog post from Philip Walton.

The Second Hurdle

After I got everything working nicely, I wanted to ensure that Webpack Encore's prod mode would work within Sculpin. Sculpin is the static site generator I use for rendering the Whateverthing site. I use Webpack with the Encore add-on to generate the CSS and JS assets for the new design.

In prod mode, Encore generates hashed filenames which allow for better cache-busting. They look something like /build/js/app.d49bfcca.js. Unfortunately, because they aren't guessable, I can't hard code them into my Twig templates.

Luckily, part of the Encore output is a manifest.json file that can map the dev mode name (such as build/js/app.js) to the hashed version.

I created my own Twig extension to read in the manifest.json file and allow my CSS and JS to be included properly from Sculpin.

Creating a Twig extension in Sculpin isn't as easy as I would like it to be. I'll need to update the Sculpin docs to explain what I did so other folks can do it as well, but I'll write up a rough draft here.

Create a Class

In app/src/EncoreHelper.php, I created a PHP class that acts as a Twig extension using the Twig GlobalsInterface. It looked like this:

<?php

namespace Beryllium\Whateverthing;

use Twig\Extension\AbstractExtension;
use Twig\Extension\GlobalsInterface;

class EncoreHelper extends AbstractExtension implements GlobalsInterface
{
    protected $sourceDir;
    protected $manifest;

    public function __construct(string $sourceDir, string $manifest) {
        $this->sourceDir = $sourceDir;
        $this->manifest = $manifest;
    }

    public function getGlobals()
    {
        $manifestContents = file_get_contents($this->sourceDir . DIRECTORY_SEPARATOR . $this->manifest);

        if (!$manifestContents) {
            throw new \RuntimeException('Webpack Encore manifest file was not found');
        }

        $manifest = json_decode($manifestContents, JSON_OBJECT_AS_ARRAY);

        return [
            'webpack_manifest' => $manifest,
        ];
    }
}

This class sets a Twig global called webpack_manifest that contains the contents of manifest.json as an array.

Load the Class

For loading the class in a way that Sculpin could see it, I modified my composer.json to declare a PSR-4 autoloader for classes in app/src/. If you want to bypass this part, you can probably get away with adding this line to the app/SculpinKernel.php file:

require_once __DIR__ . '/src/EncoreHelper.php';

If you want to do the full Composer autoloader, you can add these lines & run composer update:

  "autoload": {
    "psr-4": {
      "Beryllium\\Whateverthing\\": "app/src/"
    }
  }

Configure the Extension

In your app/config/sculpin_kernel.yml file, you can configure Symfony services and tag them for the Symfony event dispatcher, which Sculpin uses as a backbone for static site generation.

Configuring a service looks like this:

services:
  custom.encore:
    class: Beryllium\Whateverthing\EncoreHelper
    arguments:
      $sourceDir: '%sculpin.source_dir%'
      $manifest: 'build/manifest.json'
    tags:
      - { name: twig.extension }

The arguments probably don't need to have the variable as the name, but I like to keep them there for clarity.

Anyway, at this point the extension should be registered and the webpack_manifest global should be accessible by all of your Twig templates.

Using the Extension

When I updated my <link> and <script> tags to support this extension, I ended up with this:


<link rel="stylesheet"
      href="{{ webpack_manifest['build/css/app.css'] }}"
/>

<script type="text/javascript"
        src="{{ webpack_manifest['build/js/app.js'] }}"
></script>

Using the key of build/css/app.css, Twig looks into the webpack_manifest array and comes out with the path to the generated assets. When in production mode, this will look something like /build/css/app.d49bfcca.css.

Thanks!

Thanks for reading!

Please subscribe to the RSS feed to keep up to date, and definitely subscribe to my YouTube channel if you're interested in that sort of thing.

Published: March 7, 2020

Categories: news

Tags: dev, development, news, sculpin, twig, design, tailwind