We talk about JavaScript. Each month in Warsaw, Poland.
Library | Version | Description |
---|---|---|
@angular | 4.1.3 | core, compiler, router |
Rxjs | 5.0.3 | Observable, timer, map |
lodash | 4.17.4 | _.repeat |
Webpack | 2.6.1 | Bundler |
source: Akamai 10For10, KissMetrics
source: Amazon, Walmart, KissMetrics
source: StatCounter (2.5mln sites)
App bundle
3.9MB => 10min @ 3G
new webpack.optimize.UglifyJsPlugin({
beautify: false,
output: { comments: false },
compress: {
unused: true,
dead_code: true
}
})
App bundle + UglifyJs
1.3MB => 3:25min @ 3G* UglifyJS is more than enough on a daily basis
function square(x) { return x * x };
function cube(x) { return x * x * x};
let x = 5;
if (x % 2 === 0) {
console.log(square(x));
} else {
console.log(cube(x));
}
After optimisation
console.log(125);
Don't believe? Try it yourself :)
// webpack.config.js
const path = require('path');
module.exports = = {
entry: './src/main.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js'
}
};
module.exports = {
entry: {
app: './src/main.ts',
vendor: './src/vendor.ts'
},
plugins: {
new webpack.optimize.CommonsChunkPlugin({
name: ['app', 'vendor']
}),
}
};
module.exports = {
entry: {
app: './src/main.ts'
},
plugins: {
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
chunks: ['app'],
minChunks: module => /node_modules/.test(module.resource)
}),
}
};
// maths.js
export function square(x) { return x * x; }
export function cube(x) { return x * x * x; }
// main.js
import { cube } from './maths.js';
console.log(cube(5)); // 125
/***/ (function(module, exports, __webpack_require__) {
"use strict";
exports.__esModule = true;
exports.square = square;
exports.cube = cube;
function square(x) {
return x * x;
}
function cube(x) {
return x * x * x;
}
/***/ }),
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[ 'es2015', { modules: false } ] // default CommonJS
]
}
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* unused harmony export square */
/* harmony export (immutable) */ __webpack_exports__["a"] = cube;
function square(x) {
return x * x;
}
function cube(x) {
return x * x * x;
}
/***/ }),
function(module, __webpack_exports__, __webpack_require__) {
"use strict";
function cube(x) {
return x * x * x;
}
__webpack_exports__.a = cube;
}
App bundle + UglifyJs + Tree Shaking
1.1MB => 2:54min @ 3G
<h1>Hello World!</h1>
// Compiles into
...
const parentRenderNode:any = this.renderer.createViewRoot(this.parentElement);
this._el_0 = import3.createRenderElement(this.renderer,parentRenderNode,'h1',import3.EMPTY_INLINE_ARRAY,(null as any));
this._text_1 = this.renderer.createText(this._el_0,'Hello World!',(null as any));
this._text_2 = this.renderer.createText(parentRenderNode,'\n',(null as any));
...
let AotPlugin = require('@ngtools/webpack').AotPlugin;
module.exports = {
rules: [{ test: /\.ts/, use: '@ngtools/webpack' }]
plugins: [
new AotPlugin({
tsConfigPath: path.resolve('tsconfig.json'),
entryModule: path.resolve('app.module#AppModule')
})
]
}
Angular + UglifyJs + Tree Shaking + AoT
792KB => 2:02min @ 3G
const routes: Routes = [
{ path: '', component: Component },
{
path: 'lazy',
loadChildren: './+lazy/lazy.module#LazyModule'
}
];
import {
RouterModule, PreloadAllModules
} from '@angular/router';
...
imports: [
RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
})
],
.selector { /* ... */ }
.selector .child-selector { /* ... */ }
bootstrap.min.css | 118KB |
bootstrap.min.css.gz | 19KB |
Difference | 83,9% |
---|
new CompressionPlugin({
regExp: /\.css$|\.html$|\.js$$/,
threshold: 2 * 1024
})
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
Angular + UglifyJs + Tree Shaking + AoT + GZip
134KB => 0:20sec @ 3G