Angular+Webpack<3
ng-conf 2016
About Me
UX Developer @ Mutual of Omaha
Home of the Notoriously controversial license plate DRAFT.
Where most people think Nebraska is...
Where Nebraska really is...
THATS WHERE LINCOLN, NE 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.
Written in...
Languages: Ruby, Objective-C, Swift, Javascript.
Also…
Woodworker, chicken farmer, IoT.
@TheLarkInn
“OMG! Just watched @TheLarkInn talk about #Webpack and #Angular2 at @ngconf. Going to #Webpack all things Angular!! <insert selfie with me here>”
JavaScript Modules
Qualities of JavaScript Modules:
Don’t pollute global scope
Reusable
Encapsulated
Organized
Convenient
JavaScript Modules...
How to use them?
Script Tag
Global Variable
Namespace (require/import)
JavaScript Modules...
What they look like...
CommonJS
//loading module
var _ = require(‘lodash’);
//declaring module
module.exports = someValue;
AMD
define(‘myAwesomeLib’, [‘lodash’, ‘someDep’],
function (_, someDep) {
return { … }
}
);
AMD + CommonJS
define( function(require, exports, module) {
var _ = require(‘lodash’);
//..do things
module.exports = someLib;
});
ES2015/TypeScript
import {Component} from ‘angular2/core’
@Component({
selector:’info’
})
export class InfoComponent{}
So let’s talk about web application bundling...
Every library is different...
And has their own loading requirements...
Wouldn’t it be nice...
WEBPACK
Webpack is a module bundler and not a task runner.
Analyzes dependencies among your modules (not only JS but also CSS, HTML, etc) and generates assets.
Understands multiple standards for how to define dependencies and export values: AMD, CommonJS, ES6 modules, ...
But how?
Webpack - How to use it?
webpack.config.js
Yes, its a module too!!!
module.exports = {
entry: {
vendor: './src/vendors.ts',
main: './src/main.browser.ts'
},
output: {
path: 'dist/',
filename: '[name].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].chunk.js'
},
resolve: {
extensions: ['', '.ts', '.js'],
root: root('src'),
modulesDirectories: ['node_modules']
},
module: {
preLoaders: [
{
test: /\.js$/,
loader: 'source-map-loader',
exclude: [
// these packages have problems with their sourcemaps
root('node_modules/rxjs')
]
}
],
loaders: [
{
test: /\.ts$/,
loader: 'awesome-typescript-loader',
exclude: [/\.(spec|e2e)\.ts$/]
},
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.css$/,
loader: 'raw-loader'
},
{
test: /\.html$/,
loader: 'raw-loader',
exclude: [root('src/index.html')]
}
]
},
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);� });
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 “contextual root” of your application.
The first javascript file to load to “kick-off” your app in the browser.
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 {};
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
//Entry Array Syntax
module.exports = {
entry: [
‘./browser.main.ts’,
‘./vendors.ts’,
‘./polyfills.ts’
],
//...
}
vendors.ts
polyfills.ts
app.js
ng2-material.lib.js
some.component.js
ng-core.class.js
desktop.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
//Entry Object Syntax
module.exports = {
entry: {
web: ‘./web.main.ts’,
mobile: ‘./mobile.main.ts’,
desktop: ‘./desktop.main.ts’
},
//...three non connected entrys
}
web.main.ts
mobile.main.ts
@angular/platform-browser
@angular/platform-browser-dynamic
The Core Concepts: Entry
//webpack.config.js
//Entry Object Syntax
module.exports = {
entry: {
browser: ‘./web.main.ts’,
Vendors: ‘./src/vendors.ts’
}
}
Take a moment to talk with a partner about what this entry definition does
Discuss the purpose of the entry file
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
desktop.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
//[name] === entry.nameOfKey
module.exports = {
entry: {
web: ‘./web.main.ts’,
mobile: ‘./mobile.main.ts’,
desktop: ‘./desktop.main.ts’
},
output: {
path: ‘.dist/’,
filename: ‘[name].js’,
}
//...three separate entries
//...three bundles (output)
}
web.main.ts
mobile.main.ts
@angular/platform-browser
@angular/platform-browser-dynamic
./dist/
web.js
mobile.js
desktop.js
desktop.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
//You can target modules types!
module.exports = {
entry: {
web: ‘./web.main.ts’,
mobile: ‘./mobile.main.ts’,
desktop: ‘./desktop.main.ts’
},
output: {
path: ‘.dist/’,
filename: ‘[name].umd.js’,
library: ‘[name]’,
libraryTarget: ‘umd’
}
//...three separate entries
//...three bundles (output)
}
web.main.ts
mobile.main.ts
@angular/platform-browser
@angular/platform-browser-dynamic
./dist/
web.umd.js
mobile.umd.js
desktop.umd.js
The Core Concepts: Output
module.exports = {
entry: {
browser: ‘./web.main.ts’,
Vendors: ‘./src/vendors.ts’
},
output: {
path: ‘.dist/’,
library: ‘[name]’,
libraryTarget: ‘umd’
}
//...three separate entries
//...three bundles (output)
}
Real Example!!!!!
Find a new friend, use what you learned about Entry and now Output to talk about what the result of this would look like.
Talk about how Output can interact with Entry definitions.
Talk about why Output is important.
Why would you want to use UMD?
The Core Concepts
Entry
Output
Tells Webpack WHERE and HOW to distribute bundles (compilations). Works with Entry.
Loaders
module: {
loaders: [
{test: /\.ts$/, loader: ‘ts’},
{test: /\.js$/, loader: ‘babel’},
{test: /\.css$/, loader: ‘css’}
],
}
app.component.ts
Tells webpack how to load files in your content base.
Loaders are also javascript modules (function) that takes the source file, and returns it in a ‘loaded’ [modified] state.
The Core Concepts: Loaders
entry.js
external.lib.js
external.es6.dep.js
external.lib.dep.css
module: {
preLoaders:[], //lint
loaders: [
{
test: regex,
loader: string,
loaders: Array<string>,
include: Array<regex>,
exclude: Array<regex>,
},
],
postLoaders:[] //coverage, docs, etc.
}
The Core Concepts: Loaders
test
A regular expression that instructs the compiler which files to run the loader against.
loader
A string of the loader names you want to run.
loaders
An array of strings representing the modules you want to run. If using ‘loader’,
provide a string of multiple loaders separated by ‘!’.
IE: ‘style!css!less`
module: {
preLoaders:[], //lint
loaders: [
{
test: /\.ts$/,
loader: string,
loaders: [
‘awesome-typescript-loader’,
‘ng2-asset-loader`
],
include: /some_dir_name/,
exclude: [/\.(spec|e2e)\.ts$/],
},
],
postLoaders:[] //coverage, docs, etc.
}
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
loaders: [
{ test: /\.less$/, loader:’style!css!less’ },
{ test: /\.less$/,
loaders:[‘style’, ‘css’, less’]}
]
loaders: [� {� test: /\.ts$/,� loaders:[
'awesome-typescript-loader',
'ng2-asset-loader'
],� exclude: [/\.(spec|e2e)\.ts$/]� },� {� test: /\.json$/, loader: 'json-loader'� },� {� test: /\.css$/, loader: 'raw-loader'� },� {� test: /\.html$/,� loader: 'raw-loader',� exclude: [/index\.html$/]� }�]
The Core Concepts: Loaders
Real Example!!!!!
Take a moment to read this
Discuss with the person next to you what these loaders do.
Being comfortable with reading the loader syntax will make you more comfortable using it!
The Core Concepts: Loaders
Loaders can be chained. They are applied in a pipeline to the resource. The final loader is expected to return JavaScript, the others can return arbitrary format (which is passed to the next loader)
�Loaders can be synchronous and asynchronous.
�Loaders run in node.js and can do everything that’s possible there.
�Loaders accept query parameters. This can be used to pass configuration to the loader.
Loaders can be bound to extension / RegExps in the configuration.
�Loaders can be published / installed through npm.
�Normal modules can export a loader in addition to the normal main via package.json loader.
�Loaders can access the configuration.
�Loaders can emit additional arbitrary files.
The Core Concepts
Entry
Output
Loaders
Tells Webpack HOW to interpret and translate files. They return compilations.
Plugins
The Core Concepts: Plugins
ES5 Classes
Apply functionality at the compilation level.
A compilation is a bundle of files processed by the webpack compiler. (Processed via loaders).
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
// 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()
]
//...
}
Real Example!!!!!
Find 2 people!!! Goto the list of Plugins seen below. Then take a moment to find one thats relevant to your dev stack and discuss how you would add it to your configuration.
Talk about what Plugins do!!!
The Core Concepts
Entry
Output
Loaders
Plugins
Adds additional functionality to Compilations(file globs). More powerful w/ more access to CompilerAPI.
Comparing the features...
The Future of Webpack?
Webpack 2
Native ES2015 Module Support
Tree Shaking
Faster Compilation
More Optimizations Built In
Wait, there’s more!
WEBPACK
ANGULAR2
+
Angular2 and Webpack Works
Lets look at some repositories.
angular2-webpack-lite