If you are around the PHP and Open Source community, you have probably at least heard of the utility-based CSS framework: Tailwind. The ability for developers with varying degrees of frontend chops to build custom user interfaces with little to no CSS is essentially unparalleled. In the off-chance you haven't, Tailwind describes themselves as:
Tailwind CSS is a highly customizable, low-level CSS framework that gives you all of the building blocks you need to build bespoke designs without any annoying opinionated styles you have to fight to override.
...
Instead of opinionated predesigned components, Tailwind provides low-level utility classes that let you build completely custom designs without ever leaving your HTML.
Being an application developer myself, you can probably understand why I am enamored with it. However, I will admit that it does have a bit of a learning curve. A good portion of it has to do with the initial setup and the recommended use of PurgeCSS; because of the extremely beefy (2380.4kB) base CSS file that Tailwind ships with. So again, it is highly recommended that you use a post-css tool like PurgeCSS to remove unused classes and utilities from your builds.
Selecting a build tool
Despite all of my experience in the web/application/mobile development scenes, I will be the first to admit that I am NOT a Webpack expert. I know just enough to be effective but I do not know all of the ins and outs. Just like Tailwind, it can take a bit of work to get it to behave the way you want. So naturally I began looking for another option.
In case you didn't know, I am a Laravel application developer by trade. I love just about everything about the Laravel ecosystem. Yep, call me a fan boy:
One of the items that I absolutely love is Laravel Mix. This Node module is essentially a Webpack wrapper that makes Webpack far more accessible and cleaner with an optimized structure/API. As it turns out, you can use Laravel's front end build tool, Mix, in other non-Laravel environments. Golden.
Building a website for "techy" people
The whole inspiration for this post came from the need for a co-worker and I to build a simple marketing landing page for an application that we have been working on. Since this was intended to be a single page, we didn't need a fully baked CMS, but we also wanted to have the ability to update some content/images/etc without code changes.
My recommendation was to use Grav. This CMS, in my opinion, is one of the better lightweight and flat file CMS' out there. It does not require a lot of server resources (namely a database) to run and can be saved via version control. With all of that said, it can have a bit of learning curve and may not be super easy to use for people who do not have a lot of CMS experience. That's why I do not heavily recommend this CMS to all my clients. Still, there is a ton that you can do with it. This is because it relies pretty heavily on YAML and Markdown; making Grav a perfect solution for "technologically inclined" people.
The build
So we decided to use Grav and to build a theme for it, using Tailwind. The Grav documentation is pretty good, but they do not really include a bunch of information how to use SCSS or any other type of pre/post processing in the building of your theme. So what you see below is the result of my trial and error.
1. Set up Grav
There are a couple ways to install Grav. I will send you over to their docs so you can follow them. No sense in duplicate content.
2. Create theme
First things first, we need to install the Grav devtools. This can be used via the Grav Package Manager (GPM). Run this command within your Grav directory:
bin/gpm install devtools
Note: This does not need to be install globally. The GPM is part of any installation.
Next lets generate the theme:
bin/plugin devtools new-theme
This process will ask you a few questions that are required to create the new theme and will compile them into your theme's YAML configuration file. Activate the new theme in the system configuration and we are good to go
3. Mix and other dependencies
Now that the theme has been created, let's start installing some stuff. Within your new theme directory, create a package.json
file in the theme's root directory with the following content:
Next in the same location create a webpack.mix.js
file with:
4. Setting up Tailwind
Im sure you noticed in the mention of tailwind via tailwindcss('tailwind.config.js')
. Until now we haven't created it yet. Let's do that now. In the same directory as the package.json
file, create tailwind.config.js
with the following content:
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
purge: [],
theme: {
extend: {},
},
variants: {},
plugins: [],
}
I won't go into much detail about how to configure Tailwind as it is pretty well spelled out in their documentation. This is all we need to get started at least.
5. Modifying the templates
Up until now we have been creating the necessary files and workflows to generate our CSS to render in our theme, but we haven't actually done anything with our theme yet. When you created the new theme, a ./templates/partials/base.html.twig
file should have been generated. You should see something like the following within the <head>
tag:
{% set theme_config = attribute(config.themes, config.system.pages.theme) %}
<!DOCTYPE html>
<html lang="{{ grav.language.getActive ?: grav.config.site.default_lang }}">
<head>
{% block head %}
<meta charset="utf-8" />
<title>{% if header.title %}{{ header.title|e('html') }} | {% endif %}{{ site.title|e('html') }}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{% include 'partials/metadata.html.twig' %}
<link rel="icon" type="image/png" href="{{ url('theme://images/logo.png') }}" />
<link rel="canonical" href="{{ page.url(true, true) }}" />
{% endblock head %}
{% block stylesheets %}
{% do assets.addCss('https://unpkg.com/purecss@1.0.0/build/pure-min.css', 100) %}
{% do assets.addCss('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', 99) %}
{% endblock %}
{% block javascripts %}
{% do assets.addJs('jquery', 100) %}
{% endblock %}
{% block assets deferred %}
{{ assets.css()|raw }}
{{ assets.js()|raw }}
{% endblock %}
</head>
I want to direct your attention to the {% block stylesheets %}
tag. Within there are a few references to some css files. The numbers referenced, 100 and 99 respectively, are the order in which these files will be minified during run time. Since we will be using a custom built stylesheet utilizing Tailwind and PurgeCSS, we can now update the {% block stylesheets %}
tag to show the following:
{% block stylesheets %}
{% do assets.addCss('theme://css/custom.css', 100) %}
{% endblock %}
6. Compiling Tailwind
All that is left to do is build our CSS. If we use npm run dev
or yarn dev
, you will see a relatively large file being output to css/custom.css
. That is because PurgeCSS will only run when Webpack is in production mode. If you use npm run prod
or yarn prod
, you will notice that the CSS file is exponentially smaller. That is because PurgeCSS will comb through all of your project's files and look for the use of Tailwind's CSS. If it is not being used, it will be purged; effectively making your website's assets much lighter weight.
That's it
Hopefully you found some of this enlightening. Tailwind has revolutionized how I develop and code; regardless if it is an application or website. Hopefully it will become useful for you as well.