"Post" is the New "Pre"

Using Postprocessors to
Revolutionize Your Workflow

Aaron Ladage / aladage@degdigital.com / @aladage

headshot

Aaron Ladage

  • UI Engineer
  • DEG, Kansas City

http://bit.ly/1MPmzRw

“Sooner or later,
everything old
is new again.”

– Stephen King, "The Colorado Kid"

The web has a funny way
of getting back to its roots.

1
2
3
4
5
6
7

Technological expansion and contraction

A natural reaction to:

  • Current browser limitations
  • Pace of new feature adoption

Flash was a necessity.

Seriously. No really, I mean it.

Yes, Flash sucked.

(Somebody thought this was a good idea.)

But it also gave us:

  • Streaming video before HTML5 video
  • Animation before CSS3 transitions and animations
  • Rich interactive experiences before robust JavaScript

Flash bridged a functionality gap,
and ultimately, it encouraged web standards to catch up.

"Responsive Web Design"

– Ethan Marcotte, 2010

Three tenets of responsive:

  • Fluid grids
  • Media queries
  • Flexible images

There was one big problem with responsive images:

The groups that make web standards didn't see the problem.

A (very) distilled history:

  • Developers (including Marcotte) saw shortcomings in current <img> capabilities.
  • W3C and WHATWG showed little interest and suggested they create a community group (aka, the devs got blown off). Responsive Images Working Group was formed.
  • RIWG and other dev groups propose two solutions: <picture> and srcset. They're rejected again by WHATWG.
  • During this time, a polyfill emerges. Developers begin using the proposed solution and polyfill in the wild.
  • Eventually, a combined picture/srcset standard is created, with browser support appearing in late 2014.

In the case of responsive images, developers and innovation drove the standards, not the other way around.

Call me crazy,
but I believe…

Front-end development is on
the verge of another great
re-evaluation and contraction.

Developers have been filling in the gaps in CSS and JavaScript for years.

"CSS is not a real programming language"

"JavaScript is a toy language"

Problems with CSS

  • Cross-browser compatibility issues
  • Vendor prefixes
  • No variables
  • No inline importing
  • No nested selectors
  • No functions/mixins
  • No color manipulation
  • No basic arithmetic

Problems with JavaScript

In the browser:

  • Messy syntax
  • Cross-brower compatibility issues
  • Difficult DOM traversal
  • Difficulty with effects/animation

Problems with JavaScript

Within the language itself:

  • No module-loading system
  • Quirky type coercion
  • No interpolation/template strings
  • No fat arrows
  • No default function arguments
  • No classes
  • No constants
  • No destructuring

Preprocessors became the solution.

…and a pretty good one at the time, too.

CSS:

JavaScript:

(If this slide doesn't piss off everyone in the room, nothing will.)

Typical Preprocessor Workflow:

1

Typical Preprocessor Workflow:

2

Typical Preprocessor Workflow:

3

Typical Preprocessor Workflow:

4

Typical Preprocessor Workflow:

5

Coffeescript:

This:

for num in [1..10]  
  if num % 2 == 0
    console.log "#{num} is even"
  else
    console.log "#{num} is odd"

Compiles to this:

var num, _i;

for (num = _i = 1; _i <= 10; num = ++_i) {  
  if (num % 2 === 0) {
    console.log("" + num + " is even");
  } else {
    console.log("" + num + " is odd");
  }
}

On the JavaScript library front:

Querying the DOM for an element in vanilla JS…

var el = document.getElementById("myContainer");

…became this with jQuery:

var el = $("#myContainer");

But preprocessors
perpetuate a problem.

(Say that five times fast.)

We're putting more and more layers of
abstraction between the code we write
and the code the browser can read.

Preprocessors are their own programming languages

  • Not "real" code
  • Proprietary syntax
  • Often written in "non-web" languages
  • Potentially buggy
  • Not as easily extensible
  • Must be compiled, today and forever
  • Browsers are catching up
  • Compile times can be slowwwwwww
slowww

JavaScript frameworks are
also becoming irrelevant

Why dump jQuery?

  • DOM traversal isn't that hard with vanilla JS. No, really.
  • IE10/11 have eliminated most cross-browser compatibility issues.
  • CSS3 is better suited for transitions and animations.
  • Dependencies suck.
  • Impress your friends with your library-less street cred!

There's got to be a better way!

better way

Goodbye, preprocessors

Hello, postprocessors

Before you ask…

Technically, postprocessors are still preprocessors.

liar!

"Transpiler" might be more accurate.

That's the preferred term on the JavaScript side.

Postprocessors and transpilers get us
back to writing code in the languages we
fell in love with in the first place.

I love you!!!

CSS Postprocessor:

PostCSS

JS Transpilers:

Transpilers

Our preprocessor process:

5

Our new postprocessor process:

1

Our new postprocessor process:

2

Our new postprocessor process:

3

Our new postprocessor process:

4

Our new postprocessor process:

5

So, how do you get started?

It's possible you already have.

Autoprefixer

Autoprefixer

Autoprefixer

  • A popular replacement for Compass's vendor prefix mixins.
  • Automatically adds vendor prefixes to CSS3 properties.
  • You define which browsers should be supported via a config file.
  • Cross-references the always-current caniuse.com database.
  • No need to memorize special function names; just write CSS and let it do its work in the background.

Part of the much larger
PostCSS ecosystem:

PostCSS Universe

Unlike Sass, PostCSS is modular.

Sass gives you everything,
whether you want it or not.

buffet

PostCSS empowers you
to make your own choices.

chipotle

PostCSS advantages:

  • Write your CSS using CSS (what a concept!).
  • Use CSS3 with reckless abandon.
  • Hell, use CSS4. Who cares if that's not actually a thing yet?
  • Works with your existing task runners
  • Built on Node!
    • No more Ruby dependencies!
    • Easier to debug
    • Can't find a plugin that does what you want? Write your own in nothing but JavaScript.
    • Faster compile times (40x faster than Ruby Sass / 4x faster than LibSass…allegedly).
  • Countless plugins

Don't. Freak. Out.

freakout

Believe it or not, there is life after Sass.

If you can do it with Sass, you
can probably do it with PostCSS.

Partials/Globbing

Globbing

Partials/Globbing

Nested Selectors

Nested

Nested Selectors

Variables

postcss-custom-properties: a great opportunity to start following the (HIDEOUS) proposed CSS custom properties syntax:

:root {
    --color-blue: #0082c2;
}

.myContainer {
    background-color: var(--color-blue);
}

Variables

  • Yes, it's ugly.
  • But, it will someday be the standard, and allow for component-scoped variables.
  • If that grosses you out, use postcss-simple-vars for Sass-style variables instead.

Color

  • Like variables, you can follow the proposed CSS color module spec…and it's also ugly.
  • Work in RGBA, hex, HSL, HSV or HWB.
  • Use postcss-color.

Color

This also takes some getting used to:

.myContainer {
  background: color(red a(90%));
}

Combined with a variable:

.myContainer {
  background: color(var(--color-red) a(90%));
}

Mixins/Extends

  • Sass wins this one.
  • Lots of plugins for this. I like postcss-mixins. For basic arithmetic, I also use postcss-calc.
  • Ask yourself: how complex are your mixins? Is that a good thing?

What about JavaScript?

Well, in case you haven't heard by now…

EcmaScript 6 has been approved!!!

Remember this list?

  • No module-loading system
  • Quirky type coercion
  • No interpolation/template strings
  • No fat arrows
  • No default function arguments
  • No classes
  • No constants
  • No destructuring

ES6 fixes pretty much all these issues.

But we won't be able to use ES6
code in production for years, right?

Wrong.

Transpilers

Write ES6 code like this:

import widgetBuilder from "modules/widgetBuilder";

const DEFAULT_TEXT = "This is some default text that won't change.";

let exampleFn = function() {
  
  let tmplStr = `This is amazing!
    it's a multiline string!
    Our default text is ${DEFAULT_TEXT}`
  
};

export default exampleFn;

Babel transpiles your code into this:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

var _modulesWidgetBuilder = require("modules/widgetBuilder");

var _modulesWidgetBuilder2 = _interopRequireDefault(_modulesWidgetBuilder);

var DEFAULT_TEXT = "This is some default text that won't change.";

var exampleFn = function exampleFn() {

  var tmplStr = "This is amazing!\n    it's a multiline string!\n    Our default text is " + DEFAULT_TEXT;
};

exports["default"] = exampleFn;
module.exports = exports["default"];

Works with all major JS loaders:

loaders

Common, AMD, System, UMD

Someday, we may even be able to
turn off our transpilers, and our
next-gen code will "just work."

…but let's not kid ourselves.

There is no reason not to start
writing ES6 code today.

Front-end development
is at a crossroads.

  • We're not that far away from next-gen CSS and JS being adopted into standards and supported natively in all modern browsers.
  • Until that happens, it's a wonderful time to get as close to "real" code as you can in your development process.
  • The benefits of switching to postprocessed CSS are debatable, but do you get you closer to writing CSS again.
  • Switching to transpiled JS is a no-brainer. Do it now.

As developers, we have the power and the responsibility to drive innovation and set the standards with how we write our code.

The people who make
the standards are
paying attention.

Thanks for listening.

colbert