Intro to webpack – Tulsa Tech Fest 2015

This is the talk notes from a talk I gave at Tulsa Tech Fest 2015

View notes on Github – View code on Github

The talk notes look better on github BTW.

How it works

What is webpack?

  • mainly a bundler
    • It can take many resources and comebine them into one, efficiently divided parts
  • module requirement standards have not been unified in JS, and differs between libraries and modules
    • competing standards are commonJS and AMD
    • some modules express themselves in both
  • webpack tries to solve the problems many other bundlers face when dealing with large applications and their requirements.
    • it has the ability to split assets up into logical chunks for more efficient loading

Getting setup

Prerequisites:

  • nodeJs and npm installed

A basic webpack configuration file

webpack.config.js

module.exports = {
    entry: "./src/entry.js",
    output: {
        path: __dirname + '/dest/',
        filename: "bundle.js"
    }
};

You could also do:

webpack ./src/entry.js ./dest/bundle.js

If webpack is installed globally

Da HTML

index.html

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <script type="text/javascript" src="dest/bundle.js" charset="utf-8"></script>
    </body>
</html>

The start of our large JS app

entry.js

document.write("I'm alive!");

| tag setting-up

Run it!

npm run build && open index.html

look magic!

You should see a webpage with I'm alive! in the body.

Wait that isn’t impressive at all…

Understanding Loaders

How can webpack know what your desires are in building your application? Many times you want to include some css along with your JS component or jQuery plugin. Howe can webpack help with this?

Loaders to the rescue! have you ever used nodeJS and had to include another module into your script? You were using a module loader. The same applies here. But what if we want to include many different types of modules ( most of which compile down to JS ).

By default webpack only includes a loader for js files.

The javascript loaders can use both requirejs and commonjs module patterns, we’ll be using the requireJS syntax because it’s easier!

List of loaders

Let’s test it out.

utilities.js

document.write("Need input ");

entry.js

require('./utilities');
document.write("Johnny 5 is alive!");

| tag js-require

Run it!

npm run build && open index.html

Cool, notice the order our two document.write methods output in.

Let’s now share code from one module to another.

utilities.js

module.exports = {
  needs_input: function(){
    return true;  
  }
}

entry.js

var utilities = require('./utilities');
var program = ["Johnny 5 is alive!"];
if (utilities.needs_input()) {
  program.push("Needs input!");
}
document.write(program.join(" "));

| tag ‘exports’

Adding our css loaders

First We need to install the loaders with NPM.

npm install css-loader style-loader --save

style.css

body {
  background-color: black;
  color: white;
  font-size: 20px;
  text-align: center;
}

entry.js

require('!style!css!./style.css');
var utilities = require('./utilities');
var program = ["Johnny 5 is alive!"];
if (utilities.needs_input()) {
  program.push("Needs input!");
}
document.write(program.join(" "));

Run it!

npm run build && open index.html

This is called binding loaders, we’ve specifically specified them when including a module.

| tag styles

Now let’s update the config. It’s quite silly to have to always specify what loaders to use in your requirements. ( binding )

webpack.config.js

module.exports = {
    entry: "./src/entry.js",
    output: {
        path: __dirname + '/dest/',
        filename: "bundle.js"
    },
    module: {
        loaders: [
            { test: /.css$/, loader: "style!css" }
        ]
    }
};

entry.js

require('./style.css');
var utilities = require('./utilities');
var program = ["Johnny 5 is alive!"];
if (utilities.needs_input()) {
  program.push("Needs input!");
}
document.write(program.join(" "));

Run it!

npm run build && open index.html

Ah yes, much better and the same result.

Source maps!

Man all that combined JS just isn’t jiving with me, what am I to do?

Well use source maps of course.

webpack.config.js

module.exports = {
  entry: "./src/entry.js",
  output: {
    path: __dirname + '/dest/',
    filename: "bundle.js"
  },
  module: {
    loaders: [
      { test: /.css$/, loader: "style!css" }
    ]
  },
  devtool: "source-map"
};

| tag source-maps

Adding hot reloading to our project with webpack-dev-server

That’s all find and dandy, but how about something that helps me never have to refresh a webpage while developing ever again? That’s what I’m really after.

Well you’re in luck today. For the low price of FREE, we’ve got what you need.

npm install webpack webpack-dev-server --save

webpack.config.hot.js

var base = require('./webpack.config.js');

module.exports = {
  entry: [
    "webpack/hot/only-dev-server",
    "./src/entry.js"
  ],
  output: {
    filename: "dest/bundle.js"
  },
  module: base.module,
  devtool: "source-map"
};

package.json

"scripts": {
  "build": "webpack",
  "server-hot": "webpack-dev-server --config webpack.config.hot.js --hot --progress --colors --port 2992 --inline",
  "hot": "npm run server-hot"
},
"bin": {
  "webpack": "node_modules/webpack/bin/webpack.js",
  "webpack-dev-server": "node_modules/webpack-dev-server/bin/webpack-dev-server.js"
},

Now run the dev server

npm run hot

Then open up http://127.0.0.1:2992 in your browser

| tag hot

Extending our javascript loader with pre processors

https://babeljs.io/

npm install babel-loader --save
npm install babel-runtime --save

utilities.js

export default class Robot{
  constructor(name) {
    this.name = name;
    this.alive = false;
    this.program = [];
  }
  needs_input() {
    return true;
  }
  is_alive() {
    if (this.is_alive) {
      this.add_to_program(this.name + " is" + (this.alive ? "" : " not") + " alive!");
    }
  }
  add_to_program(input) {
    this.program.push(input);
  }
  run_program() {
    document.write(this.program.join(" "));
  }
}

entry.js

require('./style.css');

import Robot from "./utilities"

var robot = new Robot("Johnny 5");
robot.is_alive();
robot.alive = true;
robot.is_alive();
robot.add_to_program("Needs input!");
robot.run_program();

| tag babel

Understanding the plugin process

Plugins are most often other npm modules that add capabilities to the buils process or webpack.

Some examples of plugins:

  • minifiy our code
  • gather stats about files that are built
  • split out our build modules into seperate files
  • library specific transformers and minifiers
  • fetch required remote resources for insertion into the build
  • pull local binary resources like images into the build
  • adding dynamic module headers for release builds
  • a lot more

List of plugins

Using the Dedupe and UglifyJs plugins to minify our code

Adding our plugins

webpack.config.js

var webpack = require("webpack");

module.exports = {
  ...
  "plugins": [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({ output: {comments: false} })
  ]
};

Run it!

npm run build && open index.html

Also check out the bundled up JS file!

Let’s separate out our CSS into another file as well.

npm install extract-text-webpack-plugin --save

webpack.config.js

...
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  ...
  "module": {
    "loaders": {
      ...
      {
        test: /.css$/,
        loader: ExtractTextPlugin.extract("style-loader", "css-loader")
      }
    }
  }
  ...
  "plugins": [
    ...
    new ExtractTextPlugin('[name].css', {allChunks: true})
  ]
};

webpack.config.hot.js

module: {
  loaders: [
    {
      test: /.css$/,
      loader: "style!css"
    },
    {
      test: /.js$/,
      exclude: /node_modules/,
      loader: 'babel',
      query: {
        optional: ['runtime'],
        stage: 0
      }
    }
  ],
},

Now let’s add the css to the head of our html.

index.html

<link rel="stylesheet" href="dest/main.css">
npm run build && open index.html

Look at the source code with the inspector. You should see our CSS included.
Look at the dist/bundle.js file, It’s a lot smaller isn’t it? We don’t need any more of that support code for inserting the CSS into the page.

We had to make our hot loader config less modular as the loaders became more specific as the hot reloader doesn’t need to know about our final build process css separation step.

| tag ext-css

Let’s at some CSS pre-processors

We have a very picky designer who wants to use stylus, how can we support them in our build process?
Let’s add a new loader that supports this very awesome css pre-processor.

npm install stylus-loader --save

webpack.config.js

      {
        test: /.styl$/,
        loader: ExtractTextPlugin.extract("style-loader", "css-loader!stylus-loader")
      },

Look how we continue to use the ExtractTextPlugin to make sure it’s aware of our stylus loader.

webpack.config.hot.js

...
{
  test: /.styl$/,
  loader: "style!css!stylus"
},
...

picky-designer.styl

$robot-name-color = blue

.robot-name
  color $robot-name-color

entry.js

require('./style.css');
require('./picky-designer.styl')
...

utilities.js

is_alive() {
  if (this.is_alive) {
    this.add_to_program("<span class="robot-name">" + this.name + "</span>" + " is" + (this.alive ? "" : " not") + " alive!");
  }
}

|tag preproc

Test out your build and hot reload scripts. Try modifying the stylus file with the hot reload build!

That’s all folks, any questions?

On 3D printable quad copters

Recently I became interested in building my own multirotor UAV, often called Drones and other stigmatized names. Specifically I wanted to build my own quadcopter from the ground up, the type with 4 upward facing propellers atop high powered brushless motors.

Design of the UAV took place in Solidworks, which enabled me to size everything correctly and check clearances and such.

Before starting the design phase I looked around at a  few existing 3D printable designs and chose one to base the initial design.

Some of the specs

  • ArduFlyer 2.5.2 to be used with APM flight planner for real time telemetry w/ GPS module
  • 2200kv motors
  • Afro 30A ESCs
  • 2x 2200mah 3s lipo packs

V1

The quad came together pretty quickly after I had finalized the design, 3D printed the body+arms, and received all my parts from different sources online.

Then I took it on it’s maiden flight: and this was the result.

IMG_0712About 1 second after liftoff two of the motors ripped themselves free taking part of the arms with them. Obviously the arms weren’t strong enough to combat vibrations from the motor and props as well as lift forces generated by the props nearby the motor.  I also realized the motor/ESC combo I purchased was quite a bit more powerful then I realized and would need to beef up the rigidity of the frame accordingly.

V2

After the first flight and ensuing catastrophic failure was witnessed by my engineer friend Drew, he took measurements from my previous design CAD files and created a new arm design that he felt would be able to take the motor’s vibrations and torsional forces.

I took that arm design and modified it to use lofts a little more smoothly around the motor mount area and added mounting points for the arm to the body. The body was designed by me to be able to fit most of the electronics inside with the controller and reciever plus other control hardware  on the top. The body splits in two for easy access to the power electronics. The arms are attached to the upepr and lower parts of the body via small aluminum mounting tabs I made out of 4x5mm aluminum bar stock.

final cad

The arms were printed with very low infill as it was designed to distribute most of the forces around the outside surface. After printing, holes were drilled on either side of the arm for the motors wires and ESCs to fit through.

Assembly took a quite bit longer than the first version as feeding the ESCs through the arms to get the motor leeds out the other side for connecting the motor proved quite troublesome and tedious. Mounting the arms and making sure clearance was good between multiple 3D printed parts required a little bit of sanding and forcing certain parts together.

Can you guess what happened when I flew it for the first time?

maiden flight damage.

Conclusions

3D printed sturdy quadcopter and multirotors are possible, there are tons of working designs out there, you just need to print them thick enough.

My V2 design may have been more successful if I took advice from nature and filled the arms with foam after running the motor wires.

Design, crash, learn, repeat I guess.

V3

It’s in the works.

It’s going to be made out of aluminum square tubes.

And when I crash it, It will probably be able to fly shortly after.