Webpack for a better development workflow

Frontend United Ghent / #fuGent / @blakenewman

Front-end please stop!

Frameworks...
Task Runner tools...
Build tools...
All the things™...

Frontend United Ghent / #fuGent / @blakenewman

What’s currently available

One massive single file

Task Runners (Gulp/Grunt/Broccoli)

Module Bundlers (Require.js/Browserify/Webpack/JSPM)

Frontend United Ghent / #fuGent / @blakenewman

Is it good enough

Current tools have their own issues

JavaScript (ES6) Modules not yet standard

Library’s/Frameworks don’t always play nicely

Frontend United Ghent / #fuGent / @blakenewman

Why we need these tools

Frontend United Ghent / #fuGent / @blakenewman

Imperative    JavaScript

Declarative    CSS

                           HTML

Modularisation is important

Frontend United Ghent / #fuGent / @blakenewman

Maintainability is important

Frontend United Ghent / #fuGent / @blakenewman

Performance is important

Frontend United Ghent / #fuGent / @blakenewman

Scalability is important

Frontend United Ghent / #fuGent / @blakenewman

https://addyosmani.com/scalablejs/

LIFT

Locate

Identify

Flat

T-DRY (Try to Stick to DRY)

Frontend United Ghent / #fuGent / @blakenewman

Introduction to Webpack

What is Webpack?

Task Runner (ish)

Module/Asset Bundler

Asset Transformation

Frontend United Ghent / #fuGent / @blakenewman

Key features

Modules to bundles

Compress assets

Inline assets

Code splitting (Async Loading)

Dead Code Removal

Source Maps

Application Cache

Hot module replacement

Frontend United Ghent / #fuGent / @blakenewman

Comparing Webpack

Frontend United Ghent / #fuGent / @blakenewman

Grunt/Gulp/Broccoli ...

Lots of plugins
Task runner (not a module loader per se)


Glue together manually
Can become unmaintainable

Frontend United Ghent / #fuGent / @blakenewman

http://blog.keithcirkel.co.uk/why-we-should-stop-using-grunt/

Require.js

Simple and Well Established
Bundling and Async Loading
Optimizer (combining, minifying, inlining)

Optimizer (Config, Performance)
No Static Assets
AMD format is outdated and can be quite messy

Frontend United Ghent / #fuGent / @blakenewman

Browserify

Webpack-like and similar concepts
Simple configuration


Can be quite slow
No Static Assets
Inferior Bundle Splitting
Limited in flexibility

Frontend United Ghent / #fuGent / @blakenewman

JSPM

Package registry with dependency management
ES6 Compliant

Immature
Little support for preprocessors
Requires partner tool for precompilation

Frontend United Ghent / #fuGent / @blakenewman

Webpack

Modules, Loaders, Bundles & Splits
Many Plugins for special
requirements
Plays nicely with other tools

Performance
Extremely flexible


Docs are a bit messy

Frontend United Ghent / #fuGent / @blakenewman

How it works

Frontend United Ghent / #fuGent / @blakenewman

Bundling and entries

Consistency with deployment environments

Clear bundling strategies

Common bundles

Multiple entry points for Multi Page applications

 

Brilliant for Single Page Applications

Frontend United Ghent / #fuGent / @blakenewman

Outputs

Output versioning

Content hashing

Output names flexible to deployment strategies

 

bundle.sd2dds34.js
bundle.js?sd2dds34

Frontend United Ghent / #fuGent / @blakenewman

Loaders

Webpack works with vanilla Javascript

Loaders extend that functionality

They are transformations applied on files

Frontend United Ghent / #fuGent / @blakenewman

json: Loads file as JSON

hson: Loads HanSON file (JSON for Humans) as JSON object

raw: Loads raw content of a file (as utf-8)

val: Executes code as module and consider exports as JavaScript code

to-string: Executes code as a module, casts output to a string and exports it

imports: Imports stuff to the module

exports: Exports stuff from the module

expose: Expose exports from a module to the global context

script: Executes a JavaScript file once in global context (like in script tag), requires are not parsed.

apply: Executes a exported JavaScript function, optionally with arguments, and exports its return value.

callback: Parses your JS, calls specified functions (which you implement in webpack context) and replaces them with the results

if-loader: This is a preprocesser for the webpack module bundler. It support the if directive,similar to C #ifdef .

source-map: Extract sourceMappingURL comments from modules and offer it to webpack

checksum: Computes the checksum of a file

null: Emits an empty module.

cowsay: Emits a module with a cowsay header.

dsv: Loads csv/tsv files.

glsl: Loads glsl files and support glsl-chunks.

render-placement: Adds React.render to your component for you (not very practical in most cases)

xml: Loads XML as JSON.

svg-react: Load SVG files as JSX-ified React.createClass declarations.

base64: Loads file content as base64 string

ng-annotate: A loader to annotate dependency injections in Angular.js applications.

node: Loads .node files that are produced using node-gyp.

required: Require a whole directory of trees in bulk. Require JS, Import CSS and imports stuff in it.

icons Generates iconfont from .svg files (uses gulp-iconfont)

block-loader Generic loader for rewriting only parts of files, based on content start/end delimiters.

file: Emits the file into the output folder and returns the (relative) url.

url: The url loader works like the file loader, but can return a Data Url if the file is smaller than a limit.

worker: The worker loader creates a WebWorker for the provided file. The bundling of dependencies of the Worker is transparent.

shared-worker: Like the worker loader, but for Shared Workers.

serviceworker: Like the worker loader, but designed for Service Workers.

bundle: Wraps request in a require.ensure block (callback)

promise: Wraps request in a require.ensure block (promise)

async-module: Same as bundle, but provides a way to handle script loading errors. Wraps request in a require.ensure block (callback, errback)

react-proxy: Code Splitting for react components.

react-hot: Allows to live-edit React components while keeping them mounted and preserving their state.

image: Compresses your images. Ideal to use together with file or url.

img: Load and compress images with imagemin.

responsive: Create multiple resized images for use with srcset and CSS media queries

svgo: Compresses SVG images using svgo library

svg-sprite: Like style-loader but for SVG: it creates a single SVG sprite from a set of images, appends it to DOM and returns relative symbol url to be used with svg’s <use>.

line-art: Inlines SVG files, converting all of its nodes to paths. Useful for line art animations in React components.

baggage: Automatically require any resources related to the required one

polymer: Process HTML & CSS with preprocessor of choice and require() Web Components like first-class modules.

uglify: Uglify contents of a module. Unlike uglify plugin you can minify with mangling only your application files and not the libraries

html-minify: Minifies HTML using minimize

vue: Load single-file Vue.js components as modules, with loader-support for preprocessors.

tojson Serialize module exports as JSON. Cache generated static data as JSON at build time.

zip-it Convert files and directories to zip. Great with file.

lzstring Compresses large strings inline using lz-string, and decompresses them at runtime

modernizr Get your modernizr build bundled with webpack

coffee: Loads coffee-script like JavaScript

coffee-jsx: Loads coffee-script with JSX like JavaScript

coffee-redux: Loads coffee-script like JavaScript

json5: Like json, but not so strict.

es6: Loads ES6 modules. (old)

esnext: Transpile ES6 code using esnext.

babel: Turn ES6 code into vanilla ES5 using Babel.

regenerator: Use ES6 generators via Facebook’s Regenerator module.

livescript: Loads LiveScript like JavaScript

sweetjs: Use sweetjs macros.

traceur: Use future JavaScript features with Traceur.

ts: Loads TypeScript like JavaScript.

typescript: Loads TypeScript like JavaScript.

awesome-typescript: Loads TypeScript like JavaScript with watching support. Works with TypeScript 1.5-alfa

webpack-typescript: Loads TypeScript like JavaScript. Supports watch mode and source maps. Works with TypeScript 1.5, 1.6, and nightly builds of TypeScript 1.7 and 1.8.

purs: Loads PureScript like JavaScript.

oj: Loads OJ (an Objective-C like language) files and compiles them to plain JavaScript.

elm-webpack: Loads Elm files and compiles them to plain JavaScript.

miel: Loads Miel syntax and compiles to JavaScript.

wisp: Loads Wisp modules and compiles them to JavaScript.

sibilant: Loads Sibilant files and compiles them to JavaScript.

html: Exports HTML as string, require references to static resources.

dom: Exports HTML in a DOM element container.

riot: Load RiotJS tags and convert them to javascript.

jade: Loads jade template and returns a function

jade-html: Loads jade template and returns generated HTML

jade-react: Uses jade templates for React rendering instead of JSX

template-html: Loads any template with consolidate.js and returns generated HTML

handlebars: Loads handlebars template and returns a function

handlebars-template-loader: Loads handlebars template and returns a function (alternative)

dust: Loads dust template and returns a function

ractive: Pre-compiles Ractive templates for interactive DOM manipulation

jsx: Transform jsx code for React to js code.

react-templates: Loads react-template and returns a function

em: Compiles Emblem to Handlebars.js

ejs: Loads EJS (underscore( templating engine) template and returns a pre-compiled function

mustache: Pre-compiles Mustache templates with Hogan.js and returns a function

yaml: Converts YAML to JSON

front-matter: Extracts YAML frontmatter

markdown: Compiles Markdown to HTML

remarkable: Compiles Markdown to HTML using the Remarkable parser

markdown-it: Compiles Markdown to HTML using the markdown-it parser

ng-cache: Puts HTML partials in the Angular’s $templateCache

ngtemplate: Bundles your AngularJS templates and Pre-loads the template cache.

hamlc: Compiles haml-coffee templates (.hamlc) and returns a function.

haml: Renders haml-coffee templates (.html.hamlc) and returns a string.

jinja: Precompiles nunjucks and jinja2 templates

nunjucks: Precompiles nunjucks templates

soy: Compiles Google Closure templates and returns the namespace with render functions

smarty: Pre-compiles php smarty templates and returns a function

template-string: Use ES6 template strings for html templates

ect: Compile ectjs templates

tmodjs: Load art-template , a template-engine that is widely used in China.

layout: You can use require directly in html now!

swig: Webpack Swig loader

twig: Webpack Twig.js loader

bootstrap-webpack: Loads a configuration file for Twitter Bootstrap integration using Less. Allows complete customisation via Less.

font-awesome-webpack: Loads a configuration file for Font Awesome integration using Less. Allows complete customisation via Less.

bootstrap-sass: Loads a configuration file for Twitter Bootstrap integration using Sass. Allows complete customization via Sass.

style: Add exports of a module as style to DOM

css: Loads css file with resolved imports and returns css code

less: Loads and compiles a less file

sass: Loads and compiles a scss file

stylus: Loads and compiles a stylus file

rework: Post-process CSS with Rework and returns CSS code

postcss: Post-process CSS with Autoprefixer and other PostCSS plugins

autoprefixer: Add vendor prefixes to CSS rules using values from Can I Use

namespace-css: Namespace your css with a given selector (for encapsulating all rules in one subset of your site)

fontgen: Create your own webfont with proper CSS on-the-fly and include it into WebPack.

classnames: Automatically bind css-modules to classnames.

modernizr: Get your modernizr build bundled with webpack

po: Loads a PO gettext file and returns JSON

format-message: Compiles translations to ICU Message Format strings in formatMessage calls

jsxlate: Transform React source code for use with jsxlate

angular-gettext Compiles .po files as Angular.js module or json to be used with angular-gettext.

webpack-angular-translate: Extracts angular-translate translation id’s and default text’s

angular-gettext-extract Extracts strings for translation into a nominated .pot file.

gettext: Compiles a Gettext PO file from code source.

preprocessor: The preprocessor-loader provides the ability to preprocess source files through user defined regular expressions, macros, and callback routines. All user defined logic can be applied to line scope or source scope.

mocha: do tests with mocha in browser or node.js

coverjs: PostLoader to code coverage with CoverJs

istanbul-instrumenter: Istanbul postLoader to code coverage with karma-webpack and karma-coverage

isparta-instrumenter: Isparta preLoader to code coverage with karma-webpack and douglasduteil/karma-coverage#next

ibrik-instrumenter: Ibrik preLoader to CoffeeScript code coverage with karma-webpack and douglasduteil/karma-coverage

eslint: PreLoader for linting code using ESLint.

jshint: PreLoader for linting code.

jscs: PreLoader for style checking.

standard: Conform to standard code style.

inject: A Webpack loader for injecting code into modules via their dependencies

injectable: Allow to inject dependencies into modules

transform: Use browserify transforms as loader.

falafel: Use falafel AST transforms as a loader.

image-size: Loads an image and returns its dimensions and type

csslint: PreLoader for linting code using CSSLint

coffeelint: PreLoader for linting CoffeeScript.

tslint: PreLoader for linting TypeScript using TSLint

parker: Output a stylesheet analysis report using parker.

sjsp: Inject some codes for profiling using node-sjsp.

amdcheck: Uses AST to find and remove unused dependencies in AMD modules using amdextract.

manifest: A loader to generate JSON asset manifests to pass to preloading systems.

gulp-rev: Use in tandem with gulp-rev to replace assets from rev-manifest.

html-test Test your html templates (for example) for analytics.

stylelint Preloader for linting SASS and SCSS with stylelint

Plugins

Frontend United Ghent / #fuGent / @blakenewman

Code splitting

Initialisation performance

Designate entry points

Asynchronous code

Fixes: “Monolithic bundle” and “Unmaintainable manual imports”

Frontend United Ghent / #fuGent / @blakenewman


require.ensure([ './basket.vue' ], (require) => {
    require([ './basket.vue' ], resolve);
}, 'basket');

HMR (Hot Module Replacement)

Webpack tracks the modules dependency tree, which enables:

Patch part of dependency tree with the new code

Changes appear live without page reloading
 

Frontend United Ghent / #fuGent / @blakenewman

Compiler

HMR Server

Bundle Server

Compile

Change

code

HMR runtime

bundle

    Putting it all together

Frontend United Ghent / #fuGent / @blakenewman

Base config

Frontend United Ghent / #fuGent / @blakenewman

const path = require('path');
const ROOT_PATH = path.resolve(__dirname, '../');

module.exports = {
  
  entry: {
    app: './src/main.js'
  },

  output: {
    path: `${ROOT_PATH}/dist`,
    publicPath: '/',
    filename: '[name].js'
  },

  module: {
    loaders: [

      /* ... */

    ]
  }
}

Adding loaders to base config

Frontend United Ghent / #fuGent / @blakenewman

const path = require('path');
const ROOT_PATH = path.resolve(__dirname, '../');

module.exports = {
  
  /* ... */

  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel',
        exclude: /node_modules/
      },

      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  }
};

Extending base config

Frontend United Ghent / #fuGent / @blakenewman

const path = require('path');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.conf');

module.exports = merge(baseConfig, {

  /* ... */

});

Creating dev config

Frontend United Ghent / #fuGent / @blakenewman

const path = require('path');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.conf');
const webpack = require('webpack');

module.exports = merge(baseConfig, {

  debug: true,

  devtool: '#eval-source-map',

  devServer: {
    historyApiFallback: true,
    noInfo: true
  }

});

Creating production config

Frontend United Ghent / #fuGent / @blakenewman

const webpack = require('webpack');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.conf');

module.exports = merge(baseConfig, {

  devtool: '#source-map',

  output: {
    filename: 'js/[name].[chunkhash].js',
    chunkFilename: 'js/[name].[chunkhash].js'
  },

  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.optimize.OccurenceOrderPlugin()
  ]
};

Example package.json scripts

Frontend United Ghent / #fuGent / @blakenewman

{

  ...

  "scripts": {
    "dev": "webpack-dev-server --inline --hot --config ./build/webpack.dev.config.js",
    "build": "webpack --progress --hide-modules --config ./build/webpack.prod.config.js"
  },

  ...

}

express and webpack-dev-middleware

Custom implementations
Assets in-memory
Proxy tables
Static asset hosting
Actionable events
Flexible

Frontend United Ghent / #fuGent / @blakenewman

Hot module replacement in action

Frontend United Ghent / #fuGent / @blakenewman

Too much?

Frontend United Ghent / #fuGent / @blakenewman

Thanks

Frontend United Ghent / #fuGent / @blakenewman

Webpack for a better development workflow

By Blake Newman

Webpack for a better development workflow

Front-end United Ghent 2016

  • 5,742