Menu

Using tomorrow’s CSS with Aurelia (typescript) and PostCSS

Aurelia is a fantastic framework to write tomorrow's JavaScript code for modern browsers. Using Aurelia together with SASS works excellent, but what if we could just write modern JavaScript and modern CSS?

In this blog post, I will use a generated project created with the Aurelia-CLI and extend it to support future CSS syntax and CSS modules/ BEM styled class names. I use TypeScript as transpiler, but this can just as good be done with Babel and ES2015.

What is PostCSS

PostCSS is a small and fast JavaScript library developed by the author of autoprefixer for processing and/ or transforming style sheets. It's not by definition a replacement for pre-processors like LESS and SASS, because it can even be used together with LESS and SASS for pre-processing files. You can use it as pre-processor or post-processor (transform css live in the browser).

How fast is it? Very quickly, as can be seen in the benchmark stats below:

You might not like this, but this is how W3C defined variables to work :-)

Adding the CSSNext plug-in to PostCSS

Install CSSNext by performing the following command:

npm i postcss-cssnext --save-dev

Open up the file aurelia_project\tasks\process-css.ts to add CSSNext as PostCSS plugin.

Add the following below the other import statements

import * as cssnext from 'postcss-cssnext';

and remove

import * as autoprefixer from 'autoprefixer';

then modify

let processors = [
autoprefixer({browsers: ['last 1 version']})
];

to match

let processors = [
cssnext({ browsers: ['last 1 version'] })
];

The autoprefixer plugin is included in CSSNext, so it can be removed/ won't have to run twice. This plug-in will add all the vendor specific things, so you will never need to worry about those anymore.

What's different now?

You should now be able to add a CSS file called app.css to your src folder and insert the following content:

CSS Modules

Using CSS modules is also possible by using the plugin called aurelia-binding-loader, see the description there on how this works. In this article i will use pre-processing, because I didn't like the performance, it took < 1 sec to transform the CSS, but still showed the page without it's styles for less then a second.

Enable transforming to BEM like class names

To enable CSS modules, we will install a PostCSS plugin called postcss-modules by performing the following command:

That's it, we've setup our project to use CSS module names. I've used a custom generateScopedName and removed the hash from it, looks nicer and don't expect to have equal names.

If you want the hash in there, just remove this line.
If you want your class names to be different, modify it or check the docs :-)

If we run au build now and open up the generated bundle file scripts\app-bundle.js we can now see it modified the class name to .app__header.

We can now modify our HTML class to match app_headeror we can make it even easier:.

As you can see during the build, a file (src\app.css.json) was generated in your source folder. This file contains the changed class names as JSON object, which we could use to update our HTML files.

There is a plugin to do this named posthtml-css-modules, but I didn't want to move from the class attribute to the css-module attribute and had some issues with getting this to work properly.

Custom logic to replace class names with BEM variant

So we are going to write some custom logic, to replace the names in our HTML files using the generated JSON.

First, we need to change the build to run the processCSS and processMarkup tasks sequential. We can do this by opening up the file aurelia_project\tasks\build.ts and amend the tasks to [processCSS, processMarkup].

Secondly we need to install two more npm packages:

npm i gulp-each cheerio --save-dev

The gulp-each package allows us to walk over each file and cheerio is a easy to use HTML parser.

Open up the file aurelia_project\tasks\process-markup.ts and add the following import statements:

import * as each from 'gulp-each';
import * as cheerio from 'cheerio';

Next add the following between the 2 pipe statements (above .pipe(build.bundle()); if there are more)

This will get the HTML file path src/app.html and with that figure out the CSS JSON spec and load that src/app.css.json. Next it will get all the elements that contain class and replace the class names with there CSS module class name.

So if you look at your app bundle, this time at the define('text!app.html' line, you will see it now looks like this: