Clint Brown Front-end developer based in Sydney, Australia

Getting started with front end development tools

I weep for new front end developers starting out today. The number and complexity of tools being used has skyrocketed, showing no signs of slowing down. This is a short guide for beginners getting started with front end dev tools today.

When getting started…

  • Don’t try to build the mystical ‘perfect workflow’ at the beginning of your project - expect it to grow and evolve as your project goes on. Avoid wasting time adding tools that you’ll never use or will later prove a bad match for your needs.
  • Start small - learn one tool at a time. You’ll get up and running faster and gain a deeper understanding of what each tool does.
  • Add a new tool only when the need arises - it should either save you time and/or improve the quality of your work.
  • For each tool, estimate the time spent in research, setup and maintenance vs the benefit you expect to get from it.
  • When choosing between tools, consider -
    • How long has it been in development? (check its version and date)
    • Are top developers and companies using it? (check lists on the project’s site, article and Twitter mentions)
    • Is it being actively maintained? (check closed issues on Github)

Build tools

Automate all of your boring, time-consuming tasks, such as -

  • Start a local web server to preview your site
  • Combine and optimise your images, HTML, JS and CSS files
  • Convert your JS and CSS code into formats more widely supported by browsers
  • Test your JS or CSS (preprocessor) code
  • Test your website across multiple browsers, devices and operating systems
  • Analyse the performance of your site
  • Deploy your site

Build systems are often created with a JS task runner - such as Gulp or Grunt - which both run using Node.js.


Browser devtools and extensions

Debug issues with your site, simulate testing across devices & networks and check your site’s performance.

Follow Chrome (@chromedevtools), Firefox (@firefoxdevtools) and Microsoft (@msedgedevtools) for the latest updates and tips ‘n’ tricks.


Code editor plugins

Tweak your editors’ look to match your preferences and add new functionality and shortcuts to improve productivity.

Check Sublime Text’s Package Control, Atom’s Packages and Bracket’s Extension Registry.


Online code editors

These are a great way to quickly experiment with new tools without all the messy setup.

Codepen

Supports HTML (Haml, Markdown, Slim, Jade), CSS (Less, Sass, Stylus, PostCSS) and Javascript (Babel, CoffeeScript, LiveScript, TypeScript) pre-processors and CSS vendor prefixing (Autoprefixer, PrefixFree)

JS Bin

Supports HTML (Markdown, Jade), CSS (Less, Myth, Sass, Stylus) and Javascript (Babel, React (JSX), CoffeeScript, Traceur, TypeScript, LiveScript, ClojureScript) pre-processors

react.run

Supports React (JSX), ES6


Starter kits

If you want to ignore the ‘learn one tool at a time’ advice and just dive head-first into a complete development workflow, starter kits may help you. They provide a base site template (HTML, CSS, JS) and a tooling framework to begin new projects. They’re also flexible - individual tools within each can be added or removed as needed.

Web Starter Kit

This kit from Google provides a responsive design page template and up-to-the-minute tooling workflow, strongly focused on performance to ensure your pages load quickly. Among its built-in features is a local web server to preview your site during development, optimisation of your images, HTML, CSS and JS files, BrowserSync powered multi-device testing and offline support (for web hosts supporting HTTPS). Comfortability with Javascript and command line tools (Terminal, Command Prompt) is needed.

Web Starter Kit requires you to install Node.js and Gulp on your system. It includes Material Design Lite, Sass, AutoPrefixer, ESLint, Babel, BrowserSync integration, Material Design and Service Worker.

React Starter Kit

A comprehensive starter kit for React to create isomorphic apps which run on both the client and server.

React Starter Kit requires you to install Node.js. It includes React.js, Express, Flux, Babel, ESLint, PostCSS, AutoPrefixer, Webpack and BrowserSync integration.

React / Webpack / Babel Starter Kit

A lightweight starter kit for React.

It requires you to install Node.js. It includes React.js, React Hot Loader, Babel and Webpack.


Learning resources

Totally Tooling Tips

Google’s Addy Osmani and Matt Gaunt host this YouTube series with tips on browser devtools, code editors, build processes and the command line.

Sitepoint - Tools & Libraries

Articles and tutorials on the latest JS tools & libraries

Smashing Magazine - Tools

Articles and tutorials on the latest browser, JS, CSS and CMS tools

Build podcast

Screencasts on tech tools

Front-end handbook - Part III: Tools

A categorised list of resources from this free online e-book

Web Tools Weekly

Browse the archives of this (now defunct) web dev tools e-newsletter

React charts with Chartist.js

Recently, I needed to evaluate several JS charting libraries for use within a React application. I settled upon Chartist.js - it's SVG based, responsive, extensible and built with Sass. This article shows how to use Chartist.js within a React component.

Libraries used


Static data example


See the Pen React and Chartist.js - Example 1 by Clint Brown (@clintioo) on CodePen.

Chartist.js requires a data object containing two arrays - labels (x-axis) and series (y-axis). series can be a single or multi-dimensional array, depending on whether the data points should be grouped or not (in this example, there are two data groups).

In React, the top-level App component renders the ReactChart component with the Chartist.js data prop. On render, ReactChart creates an empty .chart div container, after which the componentDidMount method calls updateChart to render the chart within it.

/**
 *  Chartist.js data
 */

var data = {
  labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
  series: [
    [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8],
    [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4]
  ]
};

/**
 *  React/Chartist component
 */

var ReactChart = React.createClass({
  componentDidMount: function () {
    this.updateChart(this.props.data);
  },
  updateChart: function (data) {
    return new Chartist.Bar('.chart', data);
  },
  render: function () {
    return (
      <div className="chart"></div>
    );
  }
});

/**
 *  Top-level React component
 */

var App = React.createClass({
  render: function () {
    return (
      <ReactChart data={data} />
    );
  }
});

React.render(<App />, document.querySelector('.app'));

Dynamic data example using Reflux


See the Pen React and Chartist.js - Example 2 by Clint Brown (@clintioo) on CodePen.

In a real-world example you’ll often be dealing with dynamic data, so let’s update the previous example. I’m using the Reflux library to handle dataflow, but this could be substituted with any variation on Flux architecture.

The data object in the previous example is now within a Flux DataStore. The App component has a new Flux mixin which will automatically call render when the DataStore is updated. The ReactChart component has a new componentWillReceiveProps method which receives the updated DataStore.data prop and re-renders the chart.

On click of the button, it will call the updateData method in DataStore to update the Chartist data series (for example purposes only).

/**
 *  Reflux store - Chartist.js data
 */
var DataStore = Reflux.createStore({
  init: function () {
    this.data = {
      labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
      series: [
        [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8],
        [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4]
      ]
    };
    
    this.trigger();
  },
  // Change data - for example purposes only
  updateData: function () {
    this.data.series = [
      [2, 9, 6, 3, 4, 8, 7, 2, 6, 1, 8, 10],
      [4, 2, 5, 3, 9, 9, 2, 4, 5, 6, 6, 7]
    ];
    
    this.trigger();
  }
});

/**
 *  React/Chartist component
 */

var ReactChart = React.createClass({
  componentDidMount: function () {
    this.updateChart(this.props.data);
  },
  componentWillReceiveProps: function (nextProps) {
    this.updateChart(nextProps.data);
  },
  updateChart: function (data) {
    return new Chartist.Bar('.chart', data);
  },
  render: function () {
    return (
      <div>
        <div className="chart"></div>
        <button onClick={DataStore.updateData}>Change data</button>
      </div>
    );
  }
});

/**
 *  Top-level React component
 */

var App = React.createClass({
  mixins: [
    Reflux.connect(DataStore)
  ],
  render: function () {
    return (
      <ReactChart data={DataStore.data} />
    );
  }
});

React.render(<App />, document.querySelector('.app'));

Adding feature detection with Modernizr


See the Pen React and Chartist.js - Example 3 by Clint Brown (@clintioo) on CodePen.

I don’t want to load ReactChart in browsers unsupported by Chartist.js, so let’s finish by using Modernizr to detect SVG support. Chartist.js’s base support is -

  • IE9+
  • Chrome 35+
  • Safari 7+
  • Firefox 31+
  • iOS 6+
  • Android 4.3+

Confusingly though, some additional features such as multi-line labels (using <foreignobject>) are not supported in IE or Android 4.3 but auto-fallback to <text>. Hence, a Modernizr.svgforeignobject test would stop the component loading in the aforementioned browsers when it works perfectly fine :sadface:. I resorted to a hack Modernizr.svgfilters test which has the desired browser support -

  • IE9+ IE10+
  • Chrome 35+
  • Safari 7+
  • Firefox 31+
  • iOS 7+
  • Android 4.3+ Android 4.4+

If supported, the new enabled state in ReactChart is set to true before the component first renders in componentWillMount.

/**
 *  Reflux store - Chartist.js data
 */
var DataStore = Reflux.createStore({
  init: function () {
    this.data = {
      labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
      series: [
        [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8],
        [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4]
      ]
    };
    
    this.trigger();
  },
  // Change data - for example purposes only
  updateData: function () {
    this.data.series = [
      [2, 9, 6, 3, 4, 8, 7, 2, 6, 1, 8, 10],
      [4, 2, 5, 3, 9, 9, 2, 4, 5, 6, 6, 7]
    ];
    
    this.trigger();
  }
});

/**
 *  React/Chartist component
 */

var ReactChart = React.createClass({
  getInitialState: function () {
    return {
      enabled: false
    };
  },
  componentWillMount: function () {
    if (Modernizr.svgfilters) {
      this.setState({
        enabled: true
      });
    }
  },
  componentDidMount: function () {
    this.updateChart(this.props.data);
  },
  componentWillReceiveProps: function (nextProps) {
    this.updateChart(nextProps.data);
  },
  updateChart: function (data) {
    if (this.state.enabled) {
      return new Chartist.Bar('.chart', data);
    }
  },
  render: function () {
    if (!this.state.enabled) {
      return false;
    }
    
    return (
      <div>
        <div className="chart"></div>
        <button onClick={DataStore.updateData}>Change data</button>
      </div>
    );
  }
});

/**
 *  Top-level React component
 */

var App = React.createClass({
  mixins: [
    Reflux.connect(DataStore)
  ],
  render: function () {
    return (
      <ReactChart data={DataStore.data} />
    );
  }
});

React.render(<App />, document.querySelector('.app'));