Kais DevBlog

More or less structred thoughts

Using TailwindCSS in a Structr Project
Posted in Structr by Kai on Feb 24, 2021

Maybe Tailwind is the best thing since sliced bread, maybe it's just the newest hype. But one thing I can say for sure is that even a design-illiterate like me can create things that look (kind of) good. So naturally I'm interested to integrate it into my workflow with Structr.

The basics are explained quite well in the basic installation guide but it took me quite a while to get it production-ready which is why I'm writing this short tutorial.


Setup & Development Build

For our development system with stock TailwindCSS everything is done in a few simple steps. The build customized for production takes a bit more effort but is also quite easy. Let's start with the dev build.

Step 1: Create a directory structure for our project

mkdir tailwind-structr
cd tailwind-structr
mkdir src
mkdir dist

Step 2: Initialize an npm project with the default configuration file

npm init -y

Step 3: Install TailwindCSS with its dependencies

npm install -D tailwindcss@latest postcss@latest postcss-cli@latest autoprefixer@latest

Step 4: Init TailwindCSS with PurgeCSS and create default configuration files tailwind.config.js and postcss.config.js

npx tailwindcss init -p

Step 5: Create default main.css. This is where we could add custom classes to our build later.

@tailwind base;
@tailwind components;
@tailwind utilities;

Step 6: Add the development build script to package.json

  ...
"scripts": {
"build:dev": "postcss main.css -o ./dist/tailwind.css"
},
...

Now we have everything set up to get started. Without any customizations we build our development version of TailwindCSS using the default configuration.

npm run build:dev

This yields the complete TailwindCSS file with all classes.

kai@Kais-iMac ~/Documents/tailwind-structr $ ll dist/
total 7672
-rw-r--r-- 1 kai staff 3924381 23 Feb 20:13 tailwind.css

We can add this to our Structr development system and start developing with the full feature set of TailwindCSS.


Optional: Forms & Typography

To make things a bit more interesting, we want to use TailwindCSS to style forms and render user-generated content in our project. TailwindCSS offers a forms plugin that provides a basic reset for form styles and also offers a tyography plugin which adds typographic defaults to any vanilla HTML. We also want to be able to style some properties and the mouse cursor on disabled elements.

npm install -D @tailwindcss/forms @tailwindcss/typography

We add the plugins to our tailwind.config.js, add our extensions to the variants …

module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {
cursor: ['disabled'],
opacity: ['disabled'],
backgroundColor: ['disabled'],
},
  },
  plugins: [
    require('@tailwindcss/forms'),
  require('@tailwindcss/typography')
  ]
}

… and build again.

npm run build:dev
kai@Kais-iMac ~/Documents/tailwind-structr $ ll dist/
total 7944
-rw-r--r-- 1 kai staff 4064568 23 Feb 20:18 tailwind.css

Production Build

After our first development cycle we want to deploy our application to a production environment but the default TailwindCSS file size of almost 4 MB is a bit heavy, so we want to purge the unused classes. To do this we need to export our Structr app to the tailwind-structr/src/webapp folder. (For example's sake the REST call is used - it is a lot easier using the Dashboard section in Structr itself)

let config = {
"mode": "export",
"target": "/Users/kai/Documents/tailwind-structr/src/webapp"
};

fetch("http://localhost:8082/structr/rest/maintenance/deploy", {
  "headers": {
    "x-user": "admin",
    "x-password": "admin"
  },
"body": JSON.stringify(config),
  "method": "POST"
});

Then we add the purge configuration to tailwind.config.js to purge all unused classes (see the documentation about purgeable HTML).

module.exports = {
  purge: {
    enabled: (process.env.NODE_ENV === 'production'),
    content: ['./src/webapp/**/*.html']
  },
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {
cursor: ['disabled'],
opacity: ['disabled'],
backgroundColor: ['disabled'],
},
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography')
  ]
}

This tells PurgeCSS to scan all HTML files in all subdirectories of ./src/webapp and look for used classes. All unused classes will be removed from the CSS file. We only want this to run in production builds, which is why we add a build:prod script to our package.json

  ...
"scripts": {
"build:dev": "postcss main.css -o ./dist/tailwind.css",
  "build:prod": "postcss main.css -o ./dist/tailwind.min.css --env production"
},
...

Then we run our production build script …

npm run build:prod

… which leaves us with a significantly smaller file size (around 40 KB with this project).

kai@Kais-iMac ~/Documents/tailwind-structr  $ ll dist/
total 8016
-rw-r--r--  1 kai  staff  4064568 23 Feb 20:18 tailwind.css
-rw-r--r--  1 kai  staff    36461 23 Feb 20:27 tailwind.min.css

But we still want more - we want the file to be minified! For this we install cssnano

npm install -D cssnano

… and customize postcss.config.js to only enable minification in production builds.

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    cssnano: ((process.env.NODE_ENV === 'production') ? { preset: "default" } : false)
  },
}

We run our build script one last time…

npm run build:prod

… and get a purged and minified CSS file which is ready for production. The file size in this project went from close to 4 MB down to around 23 KB.

kai@Kais-iMac ~/Documents/tailwind-structr  $ ll dist/
total 7992
-rw-r--r--  1 kai  staff  4064568 23 Feb 20:18 tailwind.css
-rw-r--r--  1 kai  staff    23332 23 Feb 20:29 tailwind.min.css

The final version of this setup can be found in this GitHub repository. It contains everything except the Structr project. Simply run npm install to install the dependencies and try it out with your own project!