4. Why should we use build tools?
Generic reasons:
- Accelerate the development process
- Automate repeating tasks
- Optimize the application
- Package our application for deployment
5. Why should we use build tools?
Front-End specific reasons:
- JavaScript hardly scales (scope, readability, size issue)
- Browsers have a bottleneck in regards to HTTP requests
(HTTP 1.1: Chrome 6, Firefox 6, Safari 6, IE 8 simultaneous persistent
connections per server/proxy)
6. Why Webpack?
- Other tools’ main purpose is to concatenate files.
On any change, these tools perform a full rebuild.
Concatenation causes dead code.
e.g.: pulling Lodash and momentJS into a project
- Multiple IIFEs (Immediately Invoked Function Expressions) are slow.
Bundlers early on were creating lots of IIFEs.
Task runners can’t lazy load.
7. Why Webpack?
and because...
What module loaders do you regularly use, if any? - JetBrains 2018 Survey
https://www.jetbrains.com/research/devecosystem-2018/javascript/
14. Bundle up!
If Webpack is installed globally:
> webpack index.js ./bundle.js
If Webpack is installed locally:
> ./node_modules/.bin/webpack index.js ./bundle.js
Best practice: define a NPM script and use config file.
16. Webpack Loaders
Webpack Loaders are plugins.
There’s a loader for almost everything
Official list of loaders:
https://github.com/webpack/docs/wiki/list-of-loaders
20. ES6 transpile
Notes:
● Until Babel 5, all transformations were automatically transpiled.
Starting with Babel 6, everything is opt-in.
● Available transforms: react, es2015, ecmascript stages.
Add these in .babelrc if needed.
> touch .babelrc
{
"presets": ["es2015", "stage-1"]
}
24. Preprocessors and Postprocessors
We preprocess SCSS into CSS w/ sass-loader, node-sass.
We load CSS into the document’s head w/ style-loader, css-loader.
We postprocess the properties with desired vendor prefixes w/ autoprefixer-loader
We import the output styles into the file via a link tag instead of inlining w/
extract-text-webpack-plugin.
33. File watcher + Hot Module Replacement*
File watching is a built-in feature of Webpack.
In order to enable it, we add a --watch.
package.json
"scripts": {
"start": "webpack-dev-server",
"build:dev": "webpack --watch",
"build:prod": "webpack",
"clean": "rm -rf build"
},
Thus:
> npm run build:dev
> npm start
Note! Don’t forget to:
- require the master.scss file in index.js
for parsing
- include the bundles in your index.html
file
34. File watcher + Hot Module Replacement*
HMR (Hot Module replacement) allows webpack to reload only chunks of JS code, instead of
the whole code base.
It can be used with Redux or specific framework loaders for HML.
e.g.: react-hot-loader, vue-hot-loader
37. Loading assets: images and fonts
Q: Why use a Loader for images?
A: Performance
Q: How is it better performing?
A: The images are encrypted into base64 and injected into the DOM tree.
In other words less HTTP requests.
Q: Is there a downside?
A: Yes, the image source is assigned via JS. You will manage the images from outside HTML
and crawlers will not be able to reach it without prerendering.
38. Loading assets: images and fonts
> yarn add url-loader file-loader --dev
Available versions:
url-loader 1.0.1
file-loader 1.1.11
@28-05-2018
45. Vendor bundles and Code splitting
We will use CommonsChunks, a preinstalled Webpack plugin.
Possible configurations:
- Detect repeating dependencies in all entries and split into commons.bundle.js + unique
bundles
- Manually define dependencies for a vendor.bundle.js which should be included on
every page.
49. Minify JS and CSS + source maps
Source maps are a built-in feature.
Source maps establish the connection between bundles
and the original files.
They have a performance drawback. It is best practice to disable them in
production.
webpack.config.js
module.exports = {
...
devtool: 'source-map',
...
}
50.
51. Minify JS and CSS + source maps
In order to map bundled CSS with SCSS, we need to modify it’s loader
params
module: {
loaders: [
{loader: ExtractTextPlugin.extract('style',
'css-loader?sourceMap!autoprefixer?browsers=last 2 versions!sass)}
]}
52. Minify JS and CSS + source maps
We can minify (uglify) bundles with another built-in plugin: UglifyJsPlugin.
const UglifyJsPlugin = require('./node_modules/webpack/lib/optimize/UglifyJsPlugin');
module.exports = {
...
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false
}
})
]
}
56. ENV variables
Environment variables are not a Webpack feature.
We can send value through NPM scripts.
"scripts": {
"start": "NODE_ENV=production webpack-dev-server",
"build:dev": "NODE_ENV=development webpack-dev-server --watch",
"build:prod": "NODE_ENV=production webpack",
"build:debugprod": "NODE_ENV=debugproduction webpack-dev-server --watch",
"clean": "rm -rf build"
},
57. ENV variables
We can catch inside webpack.config.js the values send through NPM
scripts as follows:
/**
* ENV variables
*/
const env = process.env.NODE_ENV;
const isDev = env === 'development';
const isProd = env === 'production';
const debugProd = env === 'debugproduction';
58. ENV variables
Based on our needs, we define specific behaviour for
production and development.
e.g.:
devtool: isProd ? false : 'source-map',
(isDev || debugProd) ? module.exports.plugins.push(new BundleAnalyzerPlugin()) : '';
61. Cache invalidation with hashes
Webpack offers several placeholders.
We’ve used [name] before for passing the same filename from dev files
to bundles. We can also use [chunkhash] and [contenthash] to add a
hash within the filenames.
62. Cache invalidation with hashes
We will update our build filenames as follows:
module.exports = {
...
output: {
path: path.join(__dirname, 'build'),
filename: '[name].bundle.[chunkhash:4].js'
},
…
plugins: [
new ExtractTextPlugin('[name].min.[contenthash:4].css'),
…
]
63. Cache invalidation with hashes
Webpack can inject the bundle names (with autogenerated hashes)
dynamically with a loader.
> yarn add html-webpack-plugin --dev
65. Cache invalidation with hashes
Note:
Remove from index.html the CSS link and bundle scripts!
A new index.html file will be created within build,
with the hashed bundles injected and served in the browser.
69. Internationlization i18n*
There are all sorts of i18n loaders based on the framework that you will
use in your project.
i18n-express
react-i18next
@ngx-translate/core
74. GZip compression
Note:
Serving gzip files can be done through NGINX.
Binary files aren’t supported by all browsers.
NGINX can provide the normal file as fallback.