2016 web boilerplate

I was about to start a new side project, when I realized the crazy amount of setup I'd have to do to get up and running. I wanted to use my favorite latest things, but I had nowhere to start. So I started grabbing from prior projects and some open source libs, to create my latest starter framework. I'm optimistically calling it my 2016 web boilerplate.

It includes, in no specific order:

  • Webpack
  • JSCS
  • ESLint
  • Karma
  • Mocha, Chai, Sinon
  • PhantomJS 2
  • React
  • PostCSS
  • ES2015+ via Babel
  • Hot module reloading

github.com/imcnally/web-boilerplate-2016

😅

Now get our there, and start building cool things! Happy new year!

Migrating a legacy node project to Babel

I’m working on a node project that has a mix of legacy and new code. The new code is written in ES2015 (a.k.a. ES6). The legacy code is your standard ES5, but with some unfortunate global variable leaks, oddly placed commas and semicolons, and remiss of unit tests.

We are using Babel’s require hook to transpile our code on the fly, using the ES2015 preset. This means it runs on both new and legacy code.

By default, one of the plugins that comprises the preset applies strict mode to every file. It’s for module loading, and it makes modules ES6 spec compliant. This causes trouble for our legacy code. It’s non-strict mode compliant (a.k.a. loose), which causes runtime exceptions.

So, we were at a crossroads. We needed to either refactor the legacy code, or attempt to disable strict mode. In the ideal world, we’d do the former. In reality, a colleague had already tried that, but had to abandon it due to time constraints, and a lack of confidence in introducing large changes to an untested code base. So I headed to Babel’s Slack room where I got the tip I was looking for: how to (temporarily, I swear!) disable strict mode on the module plugin.

The solution involved removing the ES2015 preset and manually including all the plugins. For the troublesome modules plugin, I was able to pass a parameter setting strict mode to false. My .babelrc became:

{
  "plugins": [
    "check-es2015-constants",
    "transform-es2015-arrow-functions",
    "transform-es2015-block-scoped-functions",
    "transform-es2015-block-scoping",
    "transform-es2015-classes",
    "transform-es2015-computed-properties",
    "transform-es2015-destructuring",
    "transform-es2015-for-of",
    "transform-es2015-function-name",
    "transform-es2015-literals",
    "transform-es2015-object-super",
    "transform-es2015-parameters",
    "transform-es2015-shorthand-properties",
    "transform-es2015-spread",
    "transform-es2015-sticky-regex",
    "transform-es2015-template-literals",
    "transform-es2015-typeof-symbol",
    "transform-es2015-unicode-regex",
    "transform-regenerator",
    ["transform-es2015-modules-commonjs", {"strict": false}]
  ]
}

(Note the last line, with the object in an array: ["transform-es2015-modules-commonjs", {"strict": false}])

And my package.json ballooned by about 20 lines:

{
  “dependencies”: {
    "babel-plugin-check-es2015-constants": "^6.2.0",
    "babel-plugin-transform-es2015-arrow-functions": "^6.1.18",
    "babel-plugin-transform-es2015-block-scoped-functions": "^6.1.18",
    "babel-plugin-transform-es2015-block-scoping": "^6.1.18",
    "babel-plugin-transform-es2015-classes": "^6.2.2",
    "babel-plugin-transform-es2015-computed-properties": "^6.1.18",
    "babel-plugin-transform-es2015-destructuring": "^6.1.18",
    "babel-plugin-transform-es2015-for-of": "^6.1.18",
    "babel-plugin-transform-es2015-function-name": "^6.1.18",
    "babel-plugin-transform-es2015-literals": "^6.1.18",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.2.0",
    "babel-plugin-transform-es2015-object-super": "^6.1.18",
    "babel-plugin-transform-es2015-parameters": "^6.1.18",
    "babel-plugin-transform-es2015-shorthand-properties": "^6.1.18",
    "babel-plugin-transform-es2015-spread": "^6.1.18",
    "babel-plugin-transform-es2015-sticky-regex": "^6.1.18",
    "babel-plugin-transform-es2015-template-literals": "^6.1.18",
    "babel-plugin-transform-es2015-typeof-symbol": "^6.1.18",
    "babel-plugin-transform-es2015-unicode-regex": "^6.1.18",
    "babel-plugin-transform-regenerator": "^6.2.0",
  }
}

Now my code’s running smoothly, and I have a migration path set for my code base. Hooray!

 Victory dance!

Victory dance!

Friend with aspergers getting into tech

About five years ago, I made the switch from music to software. I was fortunate enough to land a great opportunity, which allowed me to learn on the job and work my way up. I couldn’t have done it without great mentors. I also had the privilege of a good education, a job, and social skills.

I’ve been mentoring a friend with aspergers, who just graduated college and wants to get into tech. He’s finally found his calling in software, but he’s having a tough time starting out. His application to a bootcamp was rejected for not being “creative enough”. 

Anyone have advice for my friend?

Karma tests running twice on change

My current project's been plagued with duplicate test runs on a single file change. We're using webpack and karma, and it's a documented problem. Someone pointed me to a solution that worked for browserify + karma setup, and it turned out to work for my situation too!

Since our karma-webpack config was processing any .js, .es6 or .jsx file, a change in a spec file was triggering a change there, on top of karma triggering a change on the files it was serving to the browser. A quick patch to the list of files karma handles disabled watching of the spec files, while continuing to serve them:

// in karma.conf.js
files: [
    // ... other files paths
    { pattern: './path/to/tests/**/*.js', watched: false, included: true, served: true }
 ]

And the rest was history.

My es lint configuration

I started using ESLint on a project recently. It took me some time to get over JSHint, but I'm really enjoying ESLint's plugins, especially for linting React and JSX.

I spent some time creating my own .eslintrc file, and if you want to save yourself some precious time, here's it is (also on github):

{
    "rules": {
        "indent": [
            2, 2
        ],
        "quotes": [
            2,
            "single"
        ],
        "linebreak-style": [
            2,
            "unix"
        ],
        "semi": [
            2,
            "never"
        ],
        "func-style": [2, "expression"],
        "new-parens": 2,
        "no-array-constructor": 2,
        "no-mixed-spaces-and-tabs": 2,
        "no-multiple-empty-lines": 2,
        "no-var": 2,
        "no-var": 2,
        "prefer-template": 2,
        "constructor-super": 2,
        "no-this-before-super": 2,
        "object-shorthand": 2,
        "prefer-arrow-callback": 2,
        "prefer-const": 2,
        "prefer-spread": 2,
        "prefer-reflect": 2,
        "no-console": 2,
        "no-constant-condition": 2,
        "no-debugger": 2,
        "no-dupe-args": 2,
        "no-dupe-keys": 2,
        "no-duplicate-case": 2,
        "no-empty-character-class": 2,
        "no-empty": 2,
        "no-ex-assign": 2,
        "no-extra-boolean-cast": 2,
        "no-extra-semi": 2,
        "no-func-assign": 2,
        "no-inner-declarations": 2,
        "no-invalid-regexp": 2,
        "no-irregular-whitespace": 2,
        "no-negated-in-lhs": 2,
        "no-obj-calls": 2,
        "no-regex-spaces": 2,
        "no-sparse-arrays": 2,
        "no-unreachable": 2,
        "use-isnan": 2,
        "valid-typeof": 2,
        "dot-notation": 2,
        "eqeqeq": 2,
        "no-alert": 2,
        "no-caller": 2,
        "no-else-return": 2,
        "no-eval": 2,
        "no-extend-native": 2,
        "no-extra-bind": 2,
        "no-fallthrough": 2,
        "no-floating-decimal": 2,
        "no-implicit-coercion": 2,
        "no-implied-eval": 2,
        "no-invalid-this": 2,
        "no-iterator": 2,
        "no-labels": 2,
        "no-lone-blocks": 2,
        "no-loop-func": 2,
        "no-multi-spaces": 2,
        "no-native-reassign": 2,
        "no-new-wrappers": 2,
        "no-param-reassign": 2,
        "no-proto": 2,
        "no-redeclare": 2,
        "no-return-assign": 2,
        "no-script-url": 2,
        "no-self-compare": 2,
        "no-sequences": 2,
        "no-useless-call": 2,
        "no-void": 2,
        "no-warning-comments": 2,
        "no-with": 2,
        "vars-on-top": 2,
        "wrap-iife": 2,
        "yoda": [2, "never"],
        "no-undef": 2,
        "no-delete-var": 2,
        "no-unused-vars": 2,
        "arrow-parens": [2, "always"],
        "arrow-spacing": 2
    },
    "env": {
        "es6": true,
        "browser": true,
        "node": true,
        "mocha": true
    },
    "globals": {
        "chai": true,
        "expect": true,
        "sinon": true
    },
    "extends": "eslint:recommended",
    "ecmaFeatures": {
        "jsx": true,
        "experimentalObjectRestSpread": true,
        "modules": true,
        "blockBindings": true
    },
    "plugins": [
        "react"
    ]
}

Happy linting!

Event pooling in React

I've been writing a lookahead/autocomplete component in React, with a debounced onChange. I started to notice that my value changes would be out of sync with the debounced function, but work fine if there was no debounce. As of three days ago, React finally adding documentation on how they pool events. Read on.

The long and short? It's there for performance. If you need to access the event asynchronously, call event.persist().

Autocomplete in React

I was looking over some autocomplete/lookahead solutions, and I couldn't find anything that could fit well into a React project.

First off, HTML5 has <datalist>, but it's not well supported. Most libraries and polyfills rely on jQuery. I also took a look at some pre-existing React libraries, but they were labeled "Not production ready" and couldn't handle dynamic options.

So, without further ado, here's my cross-browser compatible demo, dynamically updatable autocomplete demo in React:

See the Pen Autocomplete in React by Ian McNally (@imcnally) on CodePen.

Stopping force pushes to master with a git hook

Today, my team ran into an issue where someone accidentally force pushed their git branch to master. There's no easy configuration change to make sure no one does this, so I ended up writing a pre-push hook.

A hook is a script called at one of several points in git's lifecycle, and a user has to simply supply their own hook file to run. So, for pre push I created a prepush.sh file. It runs after someone types "git push" but before the push actually happens. If the script exits with a failure, the push in cancelled. Here's the script:

prepush.sh

#!/bin/sh

protectedBranch='master'
currentBranch=$(git rev-parse --abbrev-ref HEAD)

lastCommand=$(ps -ocommand= -p $PPID)
disallowedCommand='force|\-f'

if [[ $lastCommand =~ $disallowedCommand ]] && [ $currentBranch = $protectedBranch ]; then
  echo "Force pushing to $protectedBranch is not allowed. Your push is rejected."
  exit 1
fi

exit 0

Then, I created a symlink to the git hooks directory from the shell file:

setup-git-hooks.sh

#!/bin/sh

# the shell scripts path is relative to the .git/hooks directory
ln -s -f ../../prepush.sh .git/hooks/pre-push

Lastly, to automate the symlinking of the shell script (which ensures it runs on every developers machine), I added it to our npm scripts. This way, before each developer install node dependencies, the symlink (and therefore, the hook) will be installed.

package.json

{
  "scripts": {
    "preinstall": "./setup-git-hooks.sh",
  }
  // ...
}

React component change testing works!

Since I've been using React, there's been a bug in TestUtils.Simulate.change. I don't want to drag you down with the specifics of the bug, but I'm happy to announce it's been fixed! So, when I want to test that a user can input and change the value, I can write:

// Input.jsx
class Input extends React.Component {
    onEmailChange(event) {
        this.setState({ email: event.target.value });
    }
    
    render() {
      return (
            <input ref="email" type="email" value={this.state.email} onChange={(event) => this.onEmailChange(event))} />
      );
    }
}
// InputSpec.js
it('sets its value on input change', () => {
    const newEmail = 'abc123@gmail.com';
    const input = component.refs.email;
    
    expect(input.props.value).not.to.equal(newEmail);

    Simulate.change(input, { target: { value: newEmail } });

    expect(input.props.value).to.equal(newEmail);
});

Yey for bug squashing and succinctness!

Input validity in the HTML spec

Last night, while staving off insomnia, I started working on an enhancement to react-currency-masked-input.

I wanted an empty input value (i.e., when a user deletes all text from the input) to be replaced (a.k.a masked) as null, but invalid input (in this case, any non-digits were invalid) to replaced as 0.00. The solution sounds simple: check the input value before it's replaced. But it's not that easy! Both empty input and invalid input (input that doesn't match the pattern attribute's expression) get passed as an empty string.

To illustrate that, both events look like:

// the event when input cleared OR when bad input
event = {
  // the target is our input
  target: {
    value: ''
  }
}

But, in swooped the HTML spec that saved me. Enter HTML ValidityState.

The <element>.validity is an object with many different states of validation, including valid, tooLong, tooShort, and the most important for me: badInput.

// an example element's ValidityState object, i.e., 
// console.log(element.validity);
{
  badInput: false
  customError: false,
  patternMismatch: false,
  rangeOverflow: false,
  rangeUnderflow: false,
  stepMismatch: false,
  tooLong: false,
  tooShort: false,
  typeMismatch: false,
  valid: false,
  valueMissing: true
}

As the key suggests, badInput is set to true when the input does not match the pattern expression, so when I enter 'abc' into this input:

<input type="number" pattern="\d*" />

The elements validity state includes:

// the event fired on bad input on the element
event =  {
  target: {
    value: '',
    validity: {
      badInput: true // tada!
      // ...
    }
  }
}

In contrast, when I delete all my text from the above input, validity.badInput is false (and validity.valueMissing is true).

Putting it all together, if I want to return null for an empty input, but return zero for bad input, my masking function includes:

// var input = document.getElementsByTagName('input')[0]
input.addEventListener('change', function(event) {
  var replacedValue;
  if (!event.target.value) {
    replacedValue =  (event.target.validity.badInput) ? '0' : null;
  }
  // ... do stuff with the replaced value
});

Thanks HTML spec!

Front end best practices

I recently did an Tech Talk with Stride on Front End Best Practices. This interview originally appeared Stride's blog.

When a new technology comes out, it often takes time and an active community to create standards. It happened with Angular and is now starting with React. How do you handle best practices for emerging technologies?

First, I’d see how the creators and early adopters are writing for it. Seeing their code will give you some insight into how they’re thinking about the project, and what proper usage looks like. Similarly, keep up to date on changes, and don’t be afraid of changing your mind, and your code, accordingly.

It’s also important not to throw out all the knowledge you’ve accumulated in other projects. Let your experience inform how you approach your new project, and guide you through the less established parts of the new technology.

Ultimately, though, you’ll have to stick to something. Make sure you and your team feel good about the choices you’ve made.

 

What is the most important thing a team can do for their website that they may not be doing now?

Page load times and rendering performance are two areas that I think we, as an industry, need to spend more time and effort on. As more people access our sites on mobile devices, with varying hardware, data speeds, and data caps, keeping asset footprints small is paramount. Even after the assets download, getting something visible on the screen in a short amount of time is crucial.

Also, I think it’s about time we make accessibility a priority. Designing and building sites for the widest range of users is so important. I recommend checking out The Accessibility Project’s website.

 

What are some ways to uphold front end best practices on a project?

Right off the bat, start automating everything you can. That means code linters, coverage analysis and style checkers. Standardizing and enforcing those things will remove the nit-picky parts of code review, and will work towards a sense of coherence and conformity (the good kind).

Another aspect of establishing best practices is spreading that knowledge across the team. Pair programming and community-style code reviews both go a long way. It gives everyone a chance to both learn and teach, and can instill a sense of shared pride and ownership on everyone involved. Another effective form of knowledge sharing is lunch and learns. They are great at getting everyone together and focused on an issue, as well as showing others what’s possible.

 

As a project grows, it becomes more important to write maintainable code. This can be especially hard for CSS. What’s the best way to approach writing stylesheets?

There’s been plenty of attention paid to this issue recently, and some great ideas have come from it. Several approaches, like BEM and Smacss, are systems of class naming that increase consistency, readability and selector uniqueness. Alternatively, you can use a CSS pre-processor to allow for rule nesting, where you put classes under a single class blocks that essentially namespaces your styles. That’s not to say you can’t use BEM, Smacss, or the like, with a pre-processors. They can be quite complementary.

Other general advice would be: write good class names, use classes over tags (lookup is faster and classes allow for you to change the underlying implementation), don’t style IDs (by their nature, they’re not reusable), and be careful of excessive nesting (no more than three levels deep is a good rule of thumb).

 

How can a team pick which front end framework to use? 

Start with some research. Take a few options, and really dig into them. Find out their strengths and weaknesses, look at how strong the community and documentation around them are, and think about how each could fit into your project.

After that, one or two should rise to the top. At this point, I’d recommend trying them out. Take the framework(s) for a test drive on a small piece of work. If you like it, you can continue on with it. If you don’t, you won’t have invested too much time in it.

Remember, besides the myriad of technical considerations, you and your team should enjoy writing in the new framework, and it should make people’s lives easier. If it does, you’ve got a winner on your hands.

Choosing a javascript framework

I gave a talk recently on why a client might want to adopt a javascript framework. They were writing their own presentation layer, and were debating adding either Angular or React. Here are the notes for my presentation.

Note: Excuse the contrived "datas" examples everywhere. I modified it to keep the company secret.

Benefits of using a widely-adopted framework

  • Less time spent teaching new hires
  • Do more, write less
  • Maintainability & knowledge sharing
  • Community support for questions
  • Plugins
  • Testing
  • 3rd party tools are well vetted for bugs, speed
  • reduce AJAX calls, reduce number of trips, potential failure
    • share data between views
    • dynamic templates
    • faster page transitions
  • would make transitioning to single-page app easy (if/when)

What Angular does well

  • Dependency injection
  • Highly testable
  • Separation of concerns
  • Component/module pattern; app is a composition of modules
  • Two-way data binding
  • Declarative HTML
  • Templates rendering to JS strings behind the scenes
  • Great ecosystem

https://angular.io/docs/js/latest/quickstart.html

What Angular doesn’t do well

  • Keep view and controller close
  • Different provider types are functions that return functions
  • Doesn’t feel like writing Javascript
  • Upgrade path to version 2.0

What React does well

  • View and controller code in one file
  • Promotes uni-directional data flow
  • Follows existing javascript patterns
  • Component-based
  • Can be easily dropped into any existing project

https://facebook.github.io/react/docs/why-react.html

What React doesn’t do well

  • Unstable ecosystem
  • Being the “V” in MVC is limiting

Other JS frameworks

  • Polymer & web components
  • Ember (testing is hard!)
  • Backbone

Meh.

Plain JS page

$.get(/api/datas’)
.done(function(response){
       var ul = $(<ul class=“datas”>);
  $.each(response.datas, function(data){
    ul.append($(<li class=“data”>, data.name + data.cashMoney));
  });
  document.body.appendChild(ul);
});

$(.new-data-button’).click(function(event){
  event.preventDefault();
  event.stopPropagation();
  $.post(/api/datas’).done(function(response){
    $(.datas’).append($(<li class=“data”>,
    data.name + data.cashMoney);
  });
});

React version

import React from ‘react’;

class Datas extends React.Component {

  addNewData () {
    $.post(/api/datas’).done(function(response){
      this.setState({datas: response.datas});
    });
  }

  render () {
    var datas = this.state.datas.map(function(data){
      return <li className=“data”>{data.name} {data.cashMoney}</li>;
    });
    return (
      <section>
        <ul className=“datas”>
          {datas}
        </ul>
        <button onClick={addNewData}>Add new data</button>
      </section>
    )
  }
}

React.render(<Datas />, document.body);


Angular version

<body ng-app=“app”>
  <datas></datas>
</body>


<!-- directive template -->
<section>
  <ul class=“datas”>
    <li ng-repeat=“data in DatasCtrl.datas”>{{data.name}} {{data.cashMoney}}</li>
  </ul>
  <button ng-click=“DatasCtrl.addNewData(data)”>Add new data</button>
</section>
// app.js
angular.module(‘app’, [‘datas’]);

// data-module.js
angular.module(‘datas’, [])
  .directive(function() {
    return {
      templateUrl: ‘app/views/directives/datas.html’,
      restrict: ‘E’,
      replace: true,
      controller: ‘DatasController’,
      controllerAs: ‘DatasCtrl
    }
})
.controller(‘DatasController’, function(DatasResource){
  this.datas = DatasResource.get();

  this.addNewData = function(data){
    this.datas.push(data);
    new DatasResource(data).save();
  };
})
.factory(‘DatasResource’, function($resource) {
  return $resource(/api/datas’);
})

Should you adopt one?

Give it one, both, or another a try. Make the scope of the work small.

Choose one if you all enjoy writing in it, and it makes your lives easier.