Modern Web Development

Art Chaidarun
2016-06-16

2003

HTML

CSS

JavaScript

Problem

Pages, not apps

2011

Backbone

Mustache

jQuery

Sass / Less

Problems

Global CSS

Manual UI updates

No modules

No build process

2016

ES6

Webpack

React

Redux

CSS Modules

ES6

Block-scoped variables

ES5
console.log(square); // "undefined"?!?
for (var i = 0; i < 5; ++i) {
  var square = i * i;
  console.log(square);
}
ES6
console.log(square); // ReferenceError
for (let i = 0; i < 5; ++i) {
  const square = i * i;
  console.log(square);
  square = 5; // TypeError
}

String interpolation

ES5
var a = 2;
console.log(a + ' fast ' + Math.sqrt(4) + ' furious');
ES6
const a = 2;
console.log(`${a} fast ${Math.sqrt(4)} furious`);

Lexical this

ES5
var self = this;
var foo = function() {
  self.bar();
};
ES6
const foo = () => {
  this.bar();
};

Lambda expressions

ES5
var add = function(a, b) {
  return a + b;
};
ES6
const add = (a, b) => a + b; // lambda a, b: a + b
const add = (a, b) => {
  return a + b;
};

Modules

ES5 + CommonJS
var foo = require('foo.js');
module.exports = { bar: foo(5) };
ES6
import foo from 'foo.js';
export const bar = foo(5);

Webpack

  • Module bundler
  • Build system
  • Development server

Module bundler

webpack.config.js
{
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
}

Running Webpack

$ webpack

Build system

Loaders

loaders: [
  { test: /\.scss$/, loader: 'style!css!sass' }
]
output = style(css(sass(input)))

Plugins
plugins: [
  new webpack.optimize.UglifyJsPlugin(),
  new RemoveEmptyCSSRulesPlugin()
]

In the web rewrite, Webpack…


  1. Lints ES6
  2. Transpiles JS from ES6 to ES5
  3. Combines and minifies JS
  4. Runs Sass
  5. Combines and minifies CSS
  6. Autoprefixes CSS
  7. Hot-reloads the dev server at localhost:9000


…on every file save, in under 2 seconds.

React

Replaces Mustache, jQuery, and most of Backbone

Open-sourced by Facebook in 2013

Used by Twitter, Dropbox, Netflix, Instagram, Asana...

Backbone vs. React

index.html
<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

Hello Backbone

app.js
var AppView = Backbone.View.extend({
  el: $('#root'),
  render: function() {
    this.$el.html(this.template({ name: 'World' }));
    return this;
  },
  template: require('app.tmpl')
});
new AppView().render();
app.tmpl

Hello {{ name }}!

Hello React

app.jsx
const App = props => 

Hello {props.name}!

; const mountNode = document.getElementById('root'); ReactDOM.render(<App name='World' />, mountNode);

Redux

App as state machine

Single source of truth

Update state by dispatching actions

Counter app

Initializing the state machine

import { createStore } from 'redux';

const initialState = 0;
const reducer = (state, action) => state + action;
const store = createStore(reducer, initialState);

State transitioning

store.getState(); // Returns 0
store.dispatch(4);
store.dispatch(-1);
store.dispatch(2);
store.getState(); // Returns 5

Connecting components to a store

const Counter = props => (
  <div>
    <h2>{props.owner}'s Counter</h2>
    <p>Current value is {props.currentValue}</p>
    <button onClick={props.handleClick}>Add 1</button>
  </div>
);
import { connect } from 'react-redux';
const CounterContainer = connect(
  state => ({ currentValue: state }),
  dispatch => ({ handleClick: () => dispatch(1) })
)(Counter);
<CounterContainer owner='Art' />

CSS Modules

What's wrong with CSS?

Global scope
.home-page .sidebar button { color: red }
Specificity
button         { color: red }
#mutton        { color: yellow }
button.glutton { color: green }
.glutton       { color: blue }
<button id="mutton" class="glutton">Click me</button>
Class list boilerplate
<button class="btn btn-blue btn-solid">Click me</button>

The solution

Only use single class names as CSS rule selectors

.HomePage--practice-button { ... }
.SkillPage--test-out-button { ... }
.SkillPage--practice-button { ... }
.SessionPage--next-button { ... }
.button--solid { ... }
.button--medium { ... }

Automatic class list generation

<button class="HomePage--practice-button button--solid
  button--medium button--blue">Practice</button>

Webpack in CSS Module mode

HomePage.css
.practice {
  composes: solid from 'button.css';
  width: 100%;
}
.HomePage--practice { width: 100% }
HomePage.jsx
import styles from 'HomePage.css';
// { practice: 'HomePage--practice button--solid' }
const HomePage = props => (
  <button className={styles.practice}>Practice</button>
);

CSS Modules in production

Demo

Questions?