Web development & API design

L04: Eject! Babel, Webpack, ESLint

Agenda

  1. Babel
  2. Webpack
  3. ESLint
  4. Assignment 1!
  • Previously 6to5
     
  • Modern JS (ES2017) => ES5
    • import/export
    • () => {}
    • const/let
    • const { name } = somePerson;

yarn global add babel-cli

> babel script.js

class Person {
  constructor(name) {
    this.name = name;
  }

  toString() {
    return `This person is called ${this.name}!`;
  }
}

const martin = new Person("Martin");
console.log(martin);
  1. Takes one of more files as input
     
  2. Runs through all transforms
     
  3. Outputs transformed content (concatenated if more than one file)

No transforms

Use a transform

> babel script.js --plugins=transform-es2015-block-scoping
class Person {
  constructor(name) {
    this.name = name;
  }

  toString() {
    return `This person is called ${this.name}!`;
  }
}

var martin = new Person("Martin");
console.log(martin);
  1. Takes one of more files as input
     
  2. Runs through all transforms
     
  3. Outputs transformed content (concatenated if more than one file)
> cat script.js
class Person {
  constructor(name) {
    this.name = name;
  }

  toString() {
    return `This person is called ${ this.name }!`;
  }
}

const martin = new Person("Martin");
console.log(martin);

Presets

  • Babel is plugin-based
     
  • A transform is needed to do anything (other than concatenate)
     
  • Preset = set of transformations
     
  • es2017 = full ES2017 spec
> babel script.js --presets es2015

"use strict";

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Person = function () {
  function Person(name) {
    _classCallCheck(this, Person);

    this.name = name;
  }

  _createClass(Person, [{
    key: "toString",
    value: function toString() {
      return "This person is called " + this.name + "!";
    }
  }]);

  return Person;
}();

var martin = new Person("Martin");
console.log(martin);

Configure Babel

  • Flag(s) to babel-cli
     
  • .babelrc in the repo
     
  • package.json
// package.json
{
  …,
  
  "babel": {
    "presets": [
      "react-app"
    ]
  },
  
  …
}

Webpack

Tie everything together

What does Webpack do?

  1. Loads your source files using loaders
    1. ​babel-loader for ES2015 and JSX
    2. stylus-loader for Stylus (to CSS)
       
  2. "Bundles" them together into a single file (bundle.js)
    1. … which is the only file you include in index.html
       
  3. Lets you import modules ES2015-style (import/export)
    1. (or require CommonJS or AMD-style)

Simplest possible use

// app.js

import bar from './bar';

bar();
// bar.js

export default function bar() {
 // do something
}
// webpack.config.js

module.exports = {
  entry: './app.js',
  output: {
    filename: 'bundle.js'
  }
}
//index.html

<html>
  <head>
    ...
  </head>
  <body>
    ...
    <script src="bundle.js"></script>
  </body>
</html>

Webpack loaders

const path = require('path');

const config = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  }
};

module.exports = config;
  • Transforms on the way in
     
  • babel-loader applies babel transforms before bundling
     
  • file-by-file basis

Webpack plugins

// …

  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};
  • Do stuff to bundles (and more)
     
  • Uglify all JS!

webpack-dev-server

  • Serve your HTML and bundle from memory
     
  • Automatically watch for changes & trigger build
     
  • Gives you a fast feedback loop
     
  • What lives on http://localhost:3000/ with yarn start
  • A nice linter!
     
  • Similar to Java's PMD + checkstyle
     
  • Catches formatting and potential bugs

yarn eslint .

(config from package.json)

> yarn eslint .

yarn eslint v1.0.1
$ "/Users/marlehma/Desktop/pg6300-17/f04/code/demo-ejected-app/node_modules/.bin/eslint" "."

/Users/marlehma/Desktop/pg6300-17/f04/code/demo-ejected-app/src/index.js
  7:7  warning  'a' is assigned a value but never used  no-unused-vars

✖ 1 problem (0 errors, 1 warning)

✨  Done in 1.30s.
yarn eslint . --fix

^ helps a lot

Assignment 1: Hello, world!

Made with Slides.com