Table of Contents generated with DocToc
- Webpack Fundamentals
- Install
- Config
- Watch
- Dev Server
- Loaders
- Running individual tasks
- Production vs Dev builds
- Project Organization
- Working with ES6 Modules
- Sourcemaps
- Multiple Bundles
- CSS & Style Loaders
- Add images and fonts to build
- Webpack Tools
Learning Webpack with Pluralsight course
Replaces task runners such as Grunt and Gulp. And is also a module loader, replaces RequireJS and Browserify. Can load any module format such as AMD, CommonJS, ES6 modules.
Uses npm to manage all dependencies, not Bower.
Can also bundle css into the final bundle.js.
npm install -g webpack
With webpack.config.js
file in place, just need to enter webpack
at command line to run build.
Config file is a CommonJS module. Important keys are entry
and output
.
Note that entry
can contain a list of files.
To avoid manually having to re-run webpack
whenever any input file changes.
One way to enter watch mode is at command line:
webpack --watch
Or set watch
key to true
in config file.
Webpack can run a static server for development mode, with option to auto reload browser whenever any files change.
First install it:
npm install -g webpack-dev-server
Then run it:
webpack-dev-server
By default, starts a server at http://localhost:8080/webpack-dev-server/
This runs your app in an iframe controlled by the webpack-dev-server, and places a webpack status bar at the top of the page. Changes to files are automatically refreshed in browser.
If you don't want the status bar visual, run:
webpack-dev-server --inline
Then go to http://localhost:8080
To teach Webpack "new tricks". Loaders process files and can transform them into something else.
Add module... loaders
section to webpack config.
resolve
specifies what kind of files can be loaded without having to specify their extensions.
For example, using Babel for ES6 to ES5 transpiling, see lesson-03/webpack.config.js
For linting, JSHint uses a pre-loader. Preloaders run before the loaders do.
Use npm scripts. For example, in package.json
:
"scripts": {
"start": "webpack-dev-server --inline"
}
Then run npm start
.
See lesson-03 folder.
For production, want minimized code, but not dev. Might also want to strip out console logs for production.
To mimimize and uglify code, these features are already built into Webpack, just add -p
flag:
// package.json
"scripts": {
"start": "webpack-dev-server --inline --watch",
"prod": "webpack -p"
}
$ npm run prod
It's also possible to use a different config file for the production build. For example, to strip out certain kinds of code, first install:
npm install strip-loader --save-dev
Create webpack-production.config.js
. This file can extend the base config,
example.
Configure strip loader by providing a comma separated list strings to be filtered out, for example console.log
.
To use the production config:
// package.json
"scripts": {
"start": "webpack-dev-server --inline --watch",
"prod": "webpack --config webpack-production.config.js -p"
}
$ npm run prod
Now can use any web server such as http-server
or nginx etc to serve the optimized build.
Can also use the webpack dev server to serve the optimzed build as follows:
webpack-dev-server -p
See lesson-04 folder. A more realistic project organization.
Using output paths and devServer config as in this example,
bundle.js
file is not actually produced on disk, it's served up virtually by web server.
See lesson-05 folder.
To work with ES6 modules, configure Babel to process the es6 files, and convert to CommonJS syntax, so that Webpack can understand it.
See lesson-05/js/login.es6 and lesson-05/js/app.es6 for example of exporting a function from a module and using it in another.
Continuing with lesson-05 folder.
Easy to add because its built into Webpack. Just add "-d" flag:
webpack -d
Now you can debug into the es6 source files separately, even though they're all in one bundle.js file.
Can also use source maps in production build:
// package.json
"scripts": {
"start": "webpack-dev-server --inline --watch -d",
"prod": "webpack --config webpack-production.config.js -p -d"
}
See lesson-06 folder. lesson-06/webpack.config.js
Useful for lazy loading. For example, if have different html files needing different js code.
Webpack adds some code into the bundle that it needs, don't want to duplicate this for multiple bundles, pull it out to a shared file.
To extract shared common webpack code, add to config:
var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('shared.js');
module.exports = {
plugins: [commonsPlugin],
// ...
}
Make entry
an object instead of array, and output.filename
is now parameterized with [name]
:
entry: {
about: './about_page.js',
home: './home_page.js',
contact: './contact_page.js'
},
output: {
path: path.resolve('build/js/'), // directory where bundle will go
publicPath: '/public/assets/js/', // where dev server will serve bundle from
filename: '[name].js' // no longer 'bundle.js', now it varies by entry name
}
See lesson-07 folder.
CSS can be used without referencing it as a link in the html. Start by installing the loaders:
npm install css-loader stye-loader --save-dev
These two loaders work together to put the styles into the page.
The stye-loader
embeds the css in a style tag in the head section of html document.
The css-loader
is used to process it.
Configuration:
loaders: [
{
test: /\.css$/,
exclude: /node_modules/,
loader: 'style-loader!css-loader' // first run css files through css-loader, then style-loader
}
]
!
is Webpack syntax for chaining loaders. Files will be processed from right-most to left.
For bootstrap fonts, also need to install additional webpack loaders:
npm install file-loader url-loader --save-dev
Then configure loaders for the font files and urls, in the loaders
section:
// the url-loader uses DataUrls.
// the file-loader emits files.
{test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff'},
{test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream'},
{test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
{test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml'}
To actually bring in the css into the project, add a require
statement to the entrypoint js file:
require('../css/bootstrap.css');
require('../css/app.css');
Note that in the Network tab, no request for css files occur.
But looking at generated index.html, note two style tags inserted in <head>
section.
One is the bootstrap css inlined, the other is the custom app.css, again inlined.
The Webpack CSS and Style loaders create <style>
tags in the html head and embed all the style information.
When webpack is run in production mode (-p flag), the embedded css will be minified.
See lesson-08 folder.
To use SASS css pre-processor with Webpack. Start with installing the loader:
npm install sass-loader --save-dev
Add the sass loader to config file. This configuration will run .scss files through first the sass-loader, then css-loader, and finally style-loader.
{
test: /\.scss$/,
exclude: /node_modules/,
loader: 'style-loader!css-loader!sass-loader'
}
Alternatively, for source maps, specify the loader config as follows:
{
test: /\.scss$/,
loaders: ["style", "css?sourceMap", "sass?sourceMap"]
}
Then require the scss file from one of the js files, such as the main entry point, for example:
// app.js
require('../css/app.scss');
Similar to using SASS. Install loader:
npm install less-loader --save-dev
In webpack config, change sass-loader
to less-loader
, and change test regexp to look for less files.
In app entry, require the less file, require('../css/app.less')
See lesson-09 folder.
To have the css loaded as a separate file, rather than embedded as style tag in document head.
Start by installing a webpack plugin:
npm install extract-text-webpack-plugin --save-dev
In webpack config, require the plugin:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
Change output to not build everything to to build/js
:
output: {
path: path.resolve('build/'), // directory where bundle will go
publicPath: '/public/assets/', // where dev server will serve bundle from, matches index.html
filename: 'bundle.js'
}
Add plugins section, and call new
on the extract text plugin function required earlier.
This function takes one parameter, which is the name of the generated css file.
Note that plugins
section is an array:
plugins: [
new ExtractTextPlugin('styles.css')
]
Then change css and sass or less loader plugin configuration to use the plugin function instead of a string.
loaders: [
{
test: /\.css$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!sass-loader')
}
Change index.html now that path to bundle js is sipmly "assets", and add link for stylesheet:
<link rel="stylesheet" type="text/css" href="/public/assets/styles.css">
...
<script type="text/javascript" src="/public/assets/bundle.js"></script>
To also have source maps, configure loader as follows:
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap')
...
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap!sass-loader?sourceMap')
See lesson-10 folder. For this exercise, have gone back to bundling css in the js file.
Install the auto prefixer loader:
npm install autoprefixer-loader --save-dev
Then modify scss loader config to run the compiled scss results through the autoprefix loader:
{
test: /\.scss$/,
exclude: /node_modules/,
loader: "style-loader!css-loader!autoprefixer-loader!sass-loader"
}
The same loader can be used for both images and fonts.
See lesson-11 folder.
Install the url loader, which also installs the file loader module:
npm install url-loader --save-dev
Now add a loader to webpack config to load the images. Note that the url-loader accepts a parameter:
{
test: /\.(png|jpg)$/,
exclude: /node_modules/,
// 100K is actually too large, ideally would be ~10K
loader: 'url-loader?limit=100000'
}
limit
parameter means any image less than this size will be inlined as a base-64 encoded data,
thus no additional network requests needed to load it.
Any image bigger than limit will be created as a separate image and loaded as a separate request.
Copy of image is placed in the build directory when running webpack
.
See lesson-12 folder.
The css now has @font-face
declared with url's pointing to font files in the fonts
directory.
Same url loader used for loading images can also be used to load fonts, note addition of font file extension to test regex in loader config:
{
test: /\.(png|jpg|ttf)$/,
exclude: /node_modules/,
loader: 'url-loader?limit=1000'
}
Limit parameter can also be used, if font file < limit, will be inlined, otherwise, will not and will be a separate request. Font files usually fairly large so not likely to be inlined.
See lesson-13 folder.
If you need a task for which there is no existing loader, can write your own.
Example - strip comments out of json files. Assume project has a config/config.json
which is read in for configuration values, but you also want to put comments for each config key, which is not valid json.
Start with npm install json-loader --save-dev
. This is the json loader for webpack that supports loading json via require
.
npm install strip-json-comments --save-dev
is an npm module that strips comments out of json, but its not a webpack loader. Use it in loaders/strip.js
to make a webpack loader that strips comments out of json.
See lesson-14 folder.
Loaders are smaller pieces that transform files. Plugins are more like grunt tasks and can operate on the entire bundle, so they can do things not possible with loaders.
Example - create a global variable $
for jQuery. Add plugins
section to webpack.config.js
:
plugins: [
// plugin to provide global variables
// pass in an object where keys are aliases (global vars),
// and values are the value the alias points to.
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
]
Example - add banner add beginning of build to indicate where it came from and timestamp. Install from npm timestamp-webpack-plugin
.
Banner functionality is built into webpack via existing plugin, but getting timestamp when webpack last ran is an additional plugin to install.
Open generated bundle.js
to verify banner added:
plugins: [
// timestmap plugin creates a timestamp file for the last time webpack was run
// accepts object with config parameters
new TimestampWebpackPlugin({
// place file in current directory
path: __dirname,
filename: 'timestamp.json'
}),
new webpack.BannerPlugin('**********\nMy custom banner woo hoo!!!\n**********\n')
]