Category Archives: ideas

Getting tailwind css to work with Roots Sage 9 theme

I’m really enjoying how easy makes Sage WordPress Theme development. It’s very different in the beginning, but it soon feels a lot more like working in Django instead of WordPress.

At the same time, I’ve also been trying to use tailwind for this project. To make it work in production, you need to configure a few more settings for purgecss that official instructions don’t cover. The trick is that you need to define a TailwindExtractor that doesn’t strip out md:underline, hover:underline and similar color prefixed CSS classes.

Notice that I also exclude a few of external packages, so that purgecss doesn’t strip their CSS rules.

// webpack.config.optimize.js

'use strict'; // eslint-disable-line

const { default: ImageminPlugin } = require('imagemin-webpack-plugin');
const imageminMozjpeg = require('imagemin-mozjpeg');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const glob = require('glob-all');
const PurgecssPlugin = require('purgecss-webpack-plugin');

const config = require('./config');

class TailwindExtractor {
  static extract(content) {
    return content.match(/[A-Za-z0-9-_:\/]+/g) || [];
  }
}

module.exports = {
  plugins: [
    new ImageminPlugin({
      optipng: { optimizationLevel: 7 },
      gifsicle: { optimizationLevel: 3 },
      pngquant: { quality: '65-90', speed: 4 },
      svgo: {
        plugins: [
          { removeUnknownsAndDefaults: false },
          { cleanupIDs: false },
          { removeViewBox: false },
        ],
      },
      plugins: [imageminMozjpeg({ quality: 75 })],
      disable: (config.enabled.watcher),
    }),
    new UglifyJsPlugin({
      uglifyOptions: {
        ecma: 5,
        compress: {
          warnings: true,
          drop_console: true,
        },
      },
    }),
    new PurgecssPlugin({
      paths: glob.sync([
        'app/**/*.php',
        'resources/views/**/*.php',
        'resources/assets/scripts/**/*.js',
        'node_modules/vex-js/dist/js/*.js',
        'node_modules/mapbox-gl/dist/*.js',
        'node_modules/slick-carousel/slick/slick.js',
      ]),
      extractors: [
        {
          extractor: TailwindExtractor,
          extensions: ["html", "js", "php"],
        },
      ],
      whitelist: [
      ],
    }),
  ],
};

Using PurgeCSS with Ember.js

After watching talks about Functional CSS at Ember Map, I started looking into starting to usetailwind for my future projects. The way tailwind works is that it generates a lot of CSS classes that you then use purgecss to remove. So I decided to try it on some of my existing Ember.js projects.

I ran it on Open Education Week and Val 202 web site. Both are built on top of Zurb Foundation. Here are results:

Open Education Week:
Before: 84.3 KB (14.91 KB gzipped)
After: 31.05 KB (7.04 KB gzipped)
A 52% reduction in gzipped size!

Val 202:
Before: 156.48 KB (24.5 KB gzipped)
After: 107.68 KB (18.45 KB gzipped)
A 24% reduction in gzipped size!

Not a bad improvement, since we get it almost for free, just by including it in the build pipeline. The only downsize is probably a few seconds longer production build time.

Using it in your Ember.js project

First install dependencies:

ember install ember-cli-postcss
yarn add --dev @fullhuman/postcss-purgecss

Then add it to your ember-cli-build.js

const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const purgecss = require('@fullhuman/postcss-purgecss');

module.exports = function (defaults) {
  const app = new EmberApp(defaults, {
    postcssOptions: {
      filter: {
        enabled: true,
        plugins: [
          {
            module: purgecss,
            options: {
              content: ['./app/**/*.hbs', './app/**/.js'],
            }
          }
        ]
      }
    }
  });
  return app.toTree();
};

Finally, open your styles/app.scss or styles/app.css and modify it so purgecss doesn’t remove any of your custom CSS. 

// import framework like Foundation or Bootstrap here

/*! purgecss start ignore */

// your css and ember-addon @imports go here

/*! purgecss end ignore */

That’s all. If this isn’t enough, you can also set additional whitelistPatterns and whitelistPatternsChildren to keep additional CSS rules in your final build.

Thanks goes to @samselikoff for pointing me in the right direction to make this work.

Logging DRF Serializer errors into Sentry

For one of my Ember.js apps, I have a bit of a too complex Form flow. While I’m working on simplifying frontend, I wanted a way to easily log validation errors that users received. In addition to debugging, this helps me improve the labels and instructions on the form itself.

Backend in this case if Django Request Framework driven with JSON API. The idea is to log all validation errors and redirect them to Sentry in Debug mode:

First we declare a custom DRF Exception handler the uses JSON API exception handler and copies the data to sentry:

// exceptions.py
from rest_framework_json_api.exceptions import exception_handler
from raven.contrib.django.raven_compat.models import client

from app.serializers import SubmissionSerializer

def custom_drf_exception_handler(exc, context):
    response = exception_handler(exc, context)

    if isinstance(context.get('view').get_serializer_class(), SubmissionSerializer):
        client.captureMessage('Form Submission Validation Error', level='debug', extra=exc.get_full_details())


    return response

And we also have to configure DRF to re-route errors through it:

// settings.py
REST_FRAMEWORK = {
	..
	'EXCEPTION_HANDLER': 'app.exceptions.custom_drf_exception_handler',
	..
}

And that’s it. The end result is that when serialization error is triggered, we now get a nice error log in Sentry:

Screenshot of validation errors from Sentry

Is it worth recording videos at Conferences and Meetups?

We’re at the most busy point of organising WebCamp Ljubljana 2016. One of the questions we had to ask ourselves is – should we record the talks? It seemed that in previous years, did it because Kiberpipa and everyone else too. As organizers, we want to question decisions made in previous years. This is why we decided to investigate our decision to record the conference.

The effort required

We have 3 concurrent tracks. That means we need 3 semi-professional cameras with tripods, external mics and all the electricity. To get all of this together, somebody has to prepare and source the equipment. The on the conference day, 3 people are recording and you usually need 1 person extra as a support. Then after everything is over, it has to be edited and published. A few more days of work.

How did we do in previous years?

I looked through the stats for the videos. I didn’t know what to expect, but our most viewed video had 650+ views and the second one over 500. Then it’s slowly dropping off but a number of videos with 50+ or 100+ is still not too bad.

The real impact

One of the questions was – isn’t all this already taught through blogs, books and other conference recordings? And I believe that this just isn’t true. We’re still recording only a small amount of tech content. In addition to that, some speakers resonate well with us, while others we just can’t stand. Numbers show that people are watching and sharing the videos and that we help speakers have longer lasting impact.

So that made it really easy to decide to invest the effort on recording this years WebCamp again.

flickr photo shared by Thomas Hawk under a Creative Commons ( BY-NC ) license

We need more mentors in our communities

Meritocracy is now a bad word. It’s increasingly used to describe communities that are built around outspoken individuals. They often don’t have clear rules and code of conduct.

Alternative to that, is mentorship or apprenticeship driven community. In this model, new members are given clear roles and are presented with the expectation and rules. They are also assigned a mentor that makes it their priority for them to succeed.

This model doesn’t necessary clash with the idea of meritocracy, but it makes it much less likely. In order to make on-boarding new members efficient, it  requires that these processes are written down. This removes a lot of power from individual members, as they can’t arbitrarily decide on what they want from new members.

I believe that such model also allows for greater diversity inside the group. Removing individuals’ discretion forces community to make it easier for more diverse group of members to participate.

Code of Conduct

I think that having a Code of Conduct is a basic building block of such a community. It doesn’t mean it’s welcoming or healthy, but it greatly increases the chances when coupled with clear on-boarding path.

Further Work

15 years ago we got the Joel Test. It presents 12 questions to ask your prospective employer. Since it came, a lot of these are given and things improved a lot.

I think we could benefit from having a similar test for online and offline communities. I sure don’t want to waste any more time with larger communities without CoC and without designed onboarding process.