Kaj Białas
Daniel Capeletti
Artur Kudeł
Michał Przyszczypkowski
01.12.2016
What is Webpack?
How it works?
Options
Loaders (how it works?, how to write my own, common loaders)
Plugins (how it works?, how to write my own, common loaders)
Common scenarios (code splitting, multiple entry points, source maps ...? )
An ES2015 import statement
A JavaScript require() statement
An AMD define and require statement
An @import statement inside of a css/sass/less file.
An image url in a stylesheet (url(...)) or html (<img src=...>) file.
http://webpack.github.io/analyse
--profile --json >> stats.json/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(2);
__webpack_require__(3);
alert('main');
/***/ },
/* 2 */
/***/ function(module, exports) {
alert('coins');
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(2);
alert('helpers');
/***/ }
/******/ ]);Differences:
For big web apps it’s not efficient to put all code into a single file
Deduplication
Minimize
Chunks
npm install -g webpack
webpack ./entry.js bundle.jsmodule.exports = {
entry: "./entry.js",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
}
};webpack config file
Pure CLI
webpack <entry> <output>Development shortcut -d
Equals to --debug --devtool source-map --output-pathinfo
Production shortcut -p
Equals to --optimize-minimize --optimize-occurence-order
Watch mode --watch
Watches all dependencies and recompile on change.
Entry
entry: './src/index.js'entry: ['./src/index.js', './src/googeAnalytics.js']Entry
entry: {
'main': './src/index.js',
'unsupported': './src/unsupported.js'
}Output
output: {
path: __dirname + '/dist'
}Output
output: {
filename: 'main.js'
}output: {
filename: '[name]_bundle.js'
}For multiple bundles:
entry: {
'main': './src/index.js',
'unsupported': './src/unsupported.js'
}Results in 2 files: main_bundle.js & unsupported_bundle.js
Output
output: {
publicPath: 'http://myCdn.com/'
}.image {
background-image: url('./test.jpg');
}.image {
background-image: url('http://myCdn.com//test.jpg');
}Loaders
module: {
loaders: [{
<loader configuration here>
}]
}Plugins
plugins: [
new MyPlugin({options: 'some option'}),
...
]Resolve
resolve: {
...
modules: [
"node_modules",
path.resolve(__dirname, "app")
]
}resolve: {
...
extensions: [".js", ".json", ".jsx", ".css"],
}npm i webpack-dev-serverInstallation
Running
webpack-dev-server --content-base /build{
devServer: {
proxy: {
'/api': {
target: 'https://other-server.example.com',
secure: false
}
}
}
}What's this?
How to install new loaders?
via NPM
npm install --save-dev babel-loaderHow to include loaders?
loaders: [{ test: /\.js$/, loader: 'babel-loader' }]Include loaders by config.
module.exports = {
entry: './main.js',
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader' }
]
}
};Include loaders by require.
require("babel-loader!./main.js");require("!style!css!less!bootstrap/less/bootstrap.less");Loaders examples.
Loaders examples.
More loaders.
https://webpack.github.io/docs/list-of-loaders.html
Loaders and preloaders.
Loaders and preloaders.
module.exports = {
entry: './main.js',
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader' }
],
preLoaders: [
{ test: /\.js$/, loader: 'babel-hint-loader' }
]
}
};Queue for loaders and preloaders.
Other parameters
exclude, query
exclude, query
module: {
preLoaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'jshint-loader'
}
],
loaders: [
{
exclude: /node_modules/,
loader: 'babel-loader',
query: {
cacheDirectory: true,
presets: ['react', 'es2015']
}
}
]
}Can I create my the best custom loader?
Yes!
var _ = require('lodash');
var utils = require('loader-utils');
function processQuery(source, query) {
if (!_.isUndefined(query.search) && !_.isUndefined(query.replace)) {
if (!_.isUndefined(query.flags)) {
query.search = new RegExp(query.search, query.flags);
}
source = source.replace(query.search, query.replace);
}
return source;
}
module.exports = function (source) {
this.cacheable();
var query = utils.parseQuery(this.query);
if (_.isArray(query.multiple)) {
query.multiple.forEach(function (subquery) {
source = processQuery(source, subquery);
});
} else {
source = processQuery(source, query);
}
return source;
};What is it?
Third party code that have access to Webpack chunks
Are they any good?
Some plugins - You’ve probably used one of them before
But watch out for outdated plugins!
How to use a plugin
First require your plugin
var SpritesmithPlugin = require('webpack-spritesmith');Then add it to plugins array
// ...
plugins: [
new SpritesmithPlugin({
src: {
cwd: path.resolve(__dirname, 'src/ico'),
glob: '*.png'
},
target: {
image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl')
},
apiOptions: {
cssImageRef: "~sprite.png"
}
})
]
// ...Can I write my own plugins?
Important things
function HelloWorldPlugin(options) {
// Setup the plugin instance with options...
}
HelloWorldPlugin.prototype.apply = function(compiler) {
compiler.plugin('done', function() {
console.log('Hello World!');
});
};
module.exports = HelloWorldPlugin;Example
function MyPlugin() {}
MyPlugin.prototype.apply = function(compiler) {
compiler.plugin('emit', function(compilation, callback) {
// Explore each chunk (build output):
compilation.chunks.forEach(function(chunk) {
// Explore each module within the chunk (built inputs):
chunk.modules.forEach(function(module) {
// Explore each source file path that was included into the module:
module.fileDependencies.forEach(function(filepath) {
// we have learned a lot about the source structure now...
});
});
// Explore each asset filename generated by the chunk:
chunk.files.forEach(function(filename) {
// Get the asset source for each file generated by the chunk:
var source = compilation.assets[filename].source();
});
});
callback();
});
};
module.exports = MyPlugin;example
new webpack.optimize.UglifyJsPlugin({
compress: true,
mangle: true,
comments: false
})var ExtractTextPlugin = require("extract-text-webpack-plugin");
...
module: {
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract({
loader: "css-loader"
}) }
]
},
plugins: [
new ExtractTextPlugin("styles.css")
]resolve: {
alias: { config: "/absolute/path/to/config.js" }
}require("config"); -> /absolute/path/to/config.js
resolve: {
alias: { config: "/some/dir" }
}require("config/file.js") -> /some/dir/file.jsnew webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
ENABLE_LOGGING: JSON.stringify(true)
})
if (ENABLE_LOGGING) {
console.log('Log some info here.')
}plugins: [
new CommonsChunkPlugin("common.js")
]plugins: [
new CommonsChunkPlugin({
filename: "common.js",
minSize: 50000 // bytes,
minChunks: 3
})
]