academy
Program Manager
Microsoft Web Platform, Developer Experience, Ecosystem
Maintainer & Advocate
Webpack
Core Team
Angular / angular-cli
Evangelist
Open Source Sustainability
Where most people think Nebraska is...
Background
Former Tech Support Rep. gone rogue turned Software Engineer / Web Developer who got tired of never being able to really help the customer he served.
Languages: Ruby, Objective-C, Swift, Javascript.
Other: Woodworker, 🐓 farmer, IoT
Sustainable Open Source Practices
JavaScript
Building Contributors, Community, and Ecosystem
ASK ME ANYTHING
http://github.com/thelarkinn/ama
Expectations
Why webpack? - History of Web Performance & JavaScript
Getting Started - Setup, Installation, Scripts, and CLI
The Core Concepts
Starting out Right
The Essentials
Putting it to practice
Triage and Debug
Introductions
Chapter 1: Why?
Origins
JavaScript - It’s just scripts!
2 ways to load
Problems
Doesn’t Scale
Too many Scripts
Too Many Scripts
Unmaintainable Scripts
Scope
Size
Readability
Fragility
Monolith Files
solution?
IIFE’S
Immediately
Invoked
Function
Expression
Revealing Module pattern
Treat each file as IIFE (Revealing Module)
Many Similar Patterns
Concatenate!
We can “safely” combine files without concern of scope collision!*
Make, Grunt, Gulp, Broccoli, Brunch, StealJS
Full Rebuilds Everytime!
Dead Code
Concat doesn’t help tie usages across files
Lots of IIFE’s
Are slow
Dynamic loading?
Birth of JavaScript Modules
CommonJS
( Modules 1.0 )
Problems
Static Analysis
Npm+Node+Modules
Mass Distribution
Problems
No Browser Support
No Live Bindings
Problems with circular references
Sync Module Reso, Loader (slow)
NO BROWSER SUPPORT
solution?
Bundlers / Linkers
Browserify (static) RequireJS (loader) SystemJS (Loader)
Problems
CommonJS
//loading module
var _ = require(‘lodash’);
//declaring module
module.exports = someValue;
No static Async / Lazy Loading (all bundles up front)
CommonJS Bloat
Too Dynamic
Not everyone was shipping CommonJS.
AMD
define(‘myAwesomeLib’, [‘lodash’, ‘someDep’],
function (_, someDep) {
return { … }
}
);
AMD + CommonJS
define( function(require, exports, module) {
var _ = require(‘lodash’);
//..do things
module.exports = someLib;
});
Problems
Too Dynamic of Lazy Loading (MomentJS)
Awkward Non Standard Syntax (no real module system)
Solution?
ESM
import {uniq, forOf, bar} from ‘lodash-es’
import * as utils from ‘utils’;
export const uniqConst = uniq([1,2,2,4]);
JavaScript Modules
Reusable
Encapsulated
Organized
Convenient
Problems
ESM for Node?
HOW DO THEY WORK IN THE BROWSER?
ESM for Browser is very very very slow
Every library is different...
Library authors use the module types that they like and choose
And this is just for JavaScript...
Each and every other filetype until now has had to have specific ways to process it.
Wouldn’t it be nice...
webpack is a module bundler
lets you write ANY module format (mixed!), compiles them for the browser
Supports Static Async Bundling
Rich, Vast, Ecosystem
The most performant way to ship JavaScript today
webpack - How to use it?
Config
(webpack.config.js) Yes, it’s a module too!!!
module.exports = {
entry: {
vendor: './src/vendors.ts',
main: './src/main.browser.ts'
},
output: {
path: 'dist/',
filename: '[name].bundle.js'
}
}
webpack - How to use it?
Webpack CLI
$> webpack <entry.js> <result.js> --colors --progress
$> webpack-dev-server --port=9000
webpack - How to use it?
Node API
var webpack = require("webpack");�� // returns a Compiler instance� webpack({� // configuration object here!� }, function(err, stats) {� // …
// compilerCallback
console.error(err);� });
Questions?
Break!
Chapter 2 - From Scratch
github.com/thelarkinn/webpack-workshop-2018
The Core Concepts
Entry
some.component.js
bootstrap.js
app.component.ts
external.lib.js
some.component.ts
external.lib.dep.js
external.lib.dep.css
some.component.sass
The first javascript file to load to “kick-off” your app.
webpack uses this as the starting point
The Core Concepts: Entry
ENTRY_FILE.js
app.js
ng2-material.lib.js
some.component.js
ng-core.class.js
browser.main.ts
app.component.ts
external.lib.js
some.component.ts
external.lib.dep.js
external.lib.dep.css
some.component.sass
The Core Concepts: Entry
//webpack.config.js
module.exports = {
entry: ‘./browser.main.ts’,
//...
}
//browser.main.ts
import {
Component
} from ‘@angular/core’;
import {
App
} from ‘./app.component’;
bootstrap(App,[]);
//app.component.ts
@Component({...})
export class App {};
app.js
ng2-material.lib.js
some.component.js
ng-core.class.js
browser.main.ts
app.component.ts
external.lib.js
some.component.ts
external.lib.dep.js
external.lib.dep.css
some.component.sass
The Core Concepts: Entry
//webpack.config.js
module.exports = {
entry: ‘./browser.main.ts’,
//...
}
//browser.main.ts
import {Component} from ‘@angular/core’;
import {App} from ‘./app.component’;
bootstrap(App,[]);
//app.component.ts
@Component({...})
export class App {};
The Core Concepts
Entry
Tells webpack WHAT (files) to load for the browser; Compliments the Output property.
Output
browser.main.ts
app.component.ts
external.lib.js
some.component.ts
external.lib.dep.js
external.lib.dep.css
some.component.sass
The Core Concepts: Output
//webpack.config.js
module.exports = {
entry: ‘./browser.main.ts’,
output: {
path: ‘./dist’,
filename: ‘./bundle.js’,
},
//...
}
//Generates bundle.js
./dist/
bundle.js
The Core Concepts
Entry
Output
Tells Webpack WHERE and HOW to distribute bundles (compilations). Works with Entry.
Loaders & Rules
module: {
rules: [
{test: /\.ts$/, use: ‘ts-loader’},
{test: /\.js$/, use: ‘babel-loader’},
{test: /\.css$/, use: ‘css-loader’}
],
}
app.component.ts
Tells webpack how to modify files before its added to dependency graph
Loaders are also javascript modules (functions) that takes the source file, and returns it in a [modified] state.
The Core Concepts: Loaders
entry.js
external.lib.js
external.es6.dep.js
external.lib.dep.css
module: {
rules: [
{
test: regex,
use: (Array|String|Function)
include: RegExp[],
exclude: RegExp[],
issuer: (RegExp|String)[],
enforce: “pre”|”post”
},
],
}
The Core Concepts: Loaders
test
A regular expression that instructs the compiler which files to run the loader against.
use
An array/string/function that returns loader objects.
enforce
Can be “pre” or “post”, tells webpack to run this rule before or after all other rules
module: {
rules: [
{
test: /\.ts$/,
use: [
‘awesome-typescript-loader’,
‘ng2-asset-loader`
],
include: /some_dir_name/,
exclude: [/\.(spec|e2e)\.ts$/],
},
],
}
The Core Concepts: Loaders
include
An array of regular expression that instruct the compiler which folders/files to include. Will only search paths provided with the include.
exclude
An array of regular expression that instructs the compiler which folders/files to ignore.
inlineStyleInBrowser.js
*.js
style.css
style.less
The Core Concepts: Loaders
Chaining Loaders
less-loader
css-loader
style-loader
rules: [
{
test: /\.less$/,
use:[’style-loader’,’css-loader’,’less-loader’]
}
]
The Core Concepts: Loaders
json, hson, raw, val, to-string, imports, exports, expose, script, apply, callback, ifdef-loader, source-map, sourceMappingURL, checksum, cowsay, dsv, glsl, glsl-template, render-placement, xml, svg-react, svg-url, svg-as-symbol, symbol, base64, ng-annotate, node, required, icons, markup-inline, block-loader, bundler-configuration, console, solc, .sol, web3, includes, combine, regexp-replace, file, url, extract, worker, shared-worker, serviceworker, bundle, require.ensure, promise, async-module, bundle, require.ensure, react-proxy, react-hot, image, file, url, img, base64-image, responsive, srcset, svgo, svg-sprite, symbol, svg-fill, fill, line-art, baggage, polymer, uglify, html-minify, vue, tojson, zip-it, file, lzstring, modernizr, s3, path-replace, react-intl, require.ensure, font-subset, w3c-manifest, web-app-manifest, manifest-scope, coffee, coffee-jsx, coffee-redux, json5, es6, esnext, babel, regenerator, livescript, sweetjs, traceur, ts, typescript, awesome-typescript, webpack-typescript, purs, oj, elm-webpack, miel, wisp, sibilant, ion, html, dom, riot, pug, jade-html, jade-react, virtual-jade, virtual-dom, template-html, handlebars, handlebars-template-loader, dust, ractive, jsx, react-templates, em, ejs, ejs-html, mustache, yaml, yml, react-markdown, front-matter, markdown, remarkable, markdown-it, markdownattrs, ng-cache, ngtemplate, hamlc, haml, jinja, nunjucks, soy, smarty, swagger, template-string, ect, tmodjs, layout, swig, twig, mjml-, bootstrap-webpack, font-awesome-webpack, bootstrap-sass, bootstrap, bootstrap, font-awesome, style, isomorphic-style, style-loader, css, cess, less, sass, stylus, csso, rework, postcss, autoprefixer, namespace-css, fontgen, classnames, theo, bulma, css-to-string, css-loader, po, po2mo, format-message, jsxlate, angular-gettext, json, angular-gettext, webpack-angular-translate, angular-gettext-extract, .pot, gettext, preprocessor, amdi18n-loader, .json, .js, .coffee, sprockets-preloader, properties, transifex, mocha, coverjs, istanbul-instrumenter, ibrik-instrumenter, eslint, jshint, jscs, standard, inject, transform, falafel, image-size, csslint, coffeelint, tslint, parker, sjsp, amdcheck, manifest, gulp-rev, html-test, stylelint, stylefmt, scsslint, htmlhint, documentation, sassdoc, performance-loader
The Core Concepts
Entry
Output
Loaders
Tells Webpack HOW to interpret and translate files. Transformed on a per-file basis before adding to the dependency graph
Plugins
The Core Concepts: Plugins
Objects (with an `apply` property)
Allow you to hook into the entire compilation lifecycle
webpack has a variety of built in plugins
function BellOnBundlerErrorPlugin () { }��BellOnBundlerErrorPlugin.prototype.apply = function(compiler) {� if (typeof(process) !== 'undefined') {�
// Compiler events that are emitted and handled
compiler.plugin('done', function(stats) {
if (stats.hasErrors()) {
process.stderr.write('\x07');
}
});�
compiler.plugin('failed', function(err) {
process.stderr.write('\x07');
});�
}�}��module.exports = BellOnBundlerErrorPlugin;
The Core Concepts: Plugins
Basic Plugin Example
A plugin is an ES5 ‘class’ which implements an apply function.
The compiler uses it to emit events.
The Core Concepts: Plugins
// require() from node_modules or webpack or local file
var BellOnBundlerErrorPlugin = require(‘bell-on-error’);
var webpack = require(‘webpack’);
module.exports = {
//...
plugins: [
new BellOnBundlerErrorPlugin(),
// Just a few of the built in plugins
new webpack.optimize.CommonsChunkPlugin(‘vendors’),
new webpack.optimize.UglifyJsPlugin()
]
//...
}
How to use Plugins
require() plugin from node_modules into config.
add new instance of plugin to plugins key in config object.
provide additional info for arguments
The Core Concepts: Plugins
80% of webpack is made up of its own plugin system
Web Performance
The Core Concepts
Entry
Output
Loaders
Plugins
Adds additional functionality to Compilations(optimized bundled modules). More powerful w/ more access to CompilerAPI. Does everything else you’d ever want to in webpack.
wat
Exercise Time
Chapter 3 - Starting Out Right
Academy
Top 3 Web Page Load Time Causes:
Amount of JavaScript For Initial Download
Amount of CSS For Initial Download
AMount of Network Requests on Initial Download
Goals:
<=200kb (UNCOMPRESSED) Initial JavaScript [total]
<=100kb (UNCOMPRESSED) Initial CSS [total]
HTTP: <= 6 Initial Network Calls
HTTP/2: <= 20 Initial Network Calls
90% Code Coverage (only 10% code unused)
Code Splitting
Code Splitting
Code Splitting
Process of splitting pieces of your code into async chunks [at build time]
How Does it Work?
How...
Why should I care?
Why...
The future of web is mobile
The average mobile website takes 14 seconds to get interactive
load less code => interactive faster.
Two Types
Two Types
static
“dynamic”
Static
When to use:
“HEavy” JavaScript
Anything temporal
Routes
Always returns a Promise
app.js
listeners.js
modal.js
Async:
Sync:
app.js
listeners.js
modal.js
Async:
Sync:
app.js
listeners.js
modal.js
Async:
Sync:
bundle.js
0.chunk.js
“Dynamic”
Loading an async bundle based on runtime conditions
wat
Breakdown
expression
partial path
directory
resolvable
Context
Module
ContextModule!!!
0.chunk.js
1.chunk.js
2.chunk.js
3.chunk.js
4.chunk.js
“Hey webpack! Find me all modules in this partial path”
When to use:
AB Testing
Theming
Convenience
Exercise Time
NOte: Always focus on splitting before caching
Perf Scenarios
HTTP/2
Service Worker
Progressive Web Applications
Performance Hints
Building For Node?
Should you?
Building For Node?
Should you?
Building For Electron?
Should you?
Building For Libs?
Should you?
You just learned how webpack works entirely under the hood.
Chapter 6: Custom Plugins
Additional Resources: https://github.com/TheLarkInn/everything-is-a-plugin
Additional Workshop Video https://www.youtube.com/watch?v=4tQiJaFzuJ8