Andriy Mykulyak
"Webpack - what is it and how to make it work"
2016-05-11
Who am I ?
IT Expert in the Departament of Electronic Banking Applications
PKO BP,
Warsaw
Full stack developer. Likes challenges. Wants to finish in Ironman.
"Do. Or do not. There is no try" (c) Yoda
What is Webpack ?
- A module bundler (Require.js, Browserify) ? Not only
- A task runner (Grunt.js, Gulp.js) ? Rather no
- A package manager (Npm.js) ? Certainly not
- It is a BUILD SYSTEM !
Build systems are software tools designed to automate the process of
program compilation.
What can you use it for ?
- To build Web applications
- To build LARGE Web applications
Advantages
- CJS/AMD/UMD, custom module formats ? Yes it can
- Static assets ? Of course
- Dynamic module loading ? YES
- Integrates well (PHP, Java - server side, Grunt.js, Gulp.js etc.)
- Pre/post processors ? Surely
- Developer support ? Advanced (DevTools, Hot Module Replacement)
- And what about X, Y, or Z ? 95% it can be done
The IDEA
Everything is a JavaScript module.
If something is not a JavaScript module, then make it one !
Anatomy of a build
Meet our sample application
- Two pages - login.html, main.html
- Common code in a separate JS file - common.js
- We're writing in ES6
- A separate stylesheet file - screen.css
login.js, main.js
import App from './common';
require('./screen.scss');
class LoginApp extends App { ... }
import App from './common';
require('./screen.scss');
class MainApp extends App { ... }
common.js
import $ from 'some-external-lib';
class App {
...
}
webpack.config.js
{
entry: { login: './login', main: './main' },
output: { path: path.join(__dirname, 'dist/js'), filename: '[name].js' },
module: {
loaders: [
{ test: /\.js$/, loaders: [ 'babel-loader' ], query: { stage: 0 } },
{ test: /\.scss$/, loader: 'style!css!sass?outputStyle=expanded' }
]
}
}
Anatomy of a build configuration
Webpack build is driven by configuration file. Its main sections:
- entry - entry point specifications
- output - controls build output
- module - options affecting modules (loaders, contexts etc.)
- resolve - specifies how modules are resolved
- plugins - additional plugins used
Anatomy of a build configuration - development
- profile - measure build timings
- devtools - tools for debugging
Multiple configurations
Useful when multiple distributions should be built.
- Optimized for specific devices/software (mobile, desktop, legacy browsers, etc.)
- Localized application versions
- Optional (future) functionality
- Production and development builds
Multiple configurations during development
API for modules
- require(dep) - (CJS) synchronously loads dependency
- require.resolve(dep) - (CJS) synchronously returns module ID of a dependency
- require.ensure(deps, callback) - (CJS) asynchronously loads dependencies and then calls the callback
- define(name, deps, factory) - (AMD) defines a module
- define(value) - (AMD) exports value
- require(deps, callback) - (AMD) asynchronously loads dependencies, then calls the callback
Loaders
Loaders transform resources of our application, eventually transforming them into JavaScript.
- Loader is a function
- Loaders can be specified in the configuration, or in the module path
- Loaders can be chained, and be applied in a pipeline on the resource, starting with the
rightmost one.
- There is a pitching phase before transforming with the left-to-right order or execution
- Loaders can be synchronous or asynchronous.
- Loaders can accept parameters via query
- Loaders are resolved similar to modules
Loaders - execution order
- preloaders from configuration
- loaders from configuration file
- loaders in the require() call
- postLoaders from configuration
Default rules can be overwritten in require() using !, !! or -! prefixes
Existing loaders - I
- json, xml, base64 - loads files in corresponding formats
- file - emits (copies) the file into output directory
- img - loads and copresses images
- babel - loads JS and transforms it with Babel
- ts - loads TypeScript modules
- handlebar, ejs, mustache, jinja - loads template files and compiles them
- markdown - compiles Markdown to HTML
Existing loaders - II
- style - adds style tags with content from this module
- css - resolves CSS imports, then returns file content
- scss - compiles and returns SCSS file
- jshint, jslint, eslint, jscs - static code analysis
- csslint, scsslint - static analysis for CSS and SCSS
- postcss - postprocessor for CSS
- autoprefixer - add vendor prefixes to CSS rules
Loaders - the simplest synchronous loader
module.exports = function (resourceText) {
// this - loader context
// this.resolve(context, request, callback) - like require() for loaders
// this.addDependency(file) - adds given file as a dependency
return resourceText;
};
Loaders - an asynchronous loader
module.exports = function (resourceText) {
var done = this.async();
someAsyncOperation().then(function (data) {
done(null, data);
}, function (err) {
done(err);
});
};
Plugins
Plugins extend functionality of the Webpack engine. They can do practically everything with the resources, and
their dependency graph.
Useful plugins
- CommonsChunkPlugin - Moves modules which exist in all chunks, to a separate chunk
- MinChunkSizePlugin - merges small chunks into larger one
- UglifyJsPlugin - minifies code using UglifyJS
- DefinePlugin - defines free variables inside modules
- NoErrorsPlugin - prevents generation of somehow broken modules
- I18nPlugin - embeds translation data into bundles
See you next month at WarsawJS