From 5d2e82e03fb89678fe38669034ac83a324b2d47c Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 5 Dec 2016 14:26:46 -0800 Subject: [PATCH 1/2] perf(install time): Remove dependency to zopfli. This was necessary for the CompressionPlugin, but we never use it, so I re-implemented the copression plugin in typescript in our repo. --- package.json | 1 - .../lib/webpack/compression-plugin.ts | 112 ++++++++++++++++++ .../models/webpack-build-production.ts | 6 +- packages/angular-cli/package.json | 1 - 4 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 packages/angular-cli/lib/webpack/compression-plugin.ts diff --git a/package.json b/package.json index b0efdadbd18b..0d037c9768de 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "autoprefixer": "^6.5.3", "chalk": "^1.1.3", "common-tags": "^1.3.1", - "compression-webpack-plugin": "^0.3.2", "configstore": "^2.0.0", "core-js": "^2.4.0", "css-loader": "^0.23.1", diff --git a/packages/angular-cli/lib/webpack/compression-plugin.ts b/packages/angular-cli/lib/webpack/compression-plugin.ts new file mode 100644 index 000000000000..32c627f17f58 --- /dev/null +++ b/packages/angular-cli/lib/webpack/compression-plugin.ts @@ -0,0 +1,112 @@ +/** Forked from https://github.com/webpack/compression-webpack-plugin. */ +const async = require('async'); +const url = require('url'); + +const RawSource = require('webpack-sources/lib/RawSource'); + + +export interface CompressionPluginOptions { + algorithm?: string; + asset?: string; + level?: number; + flush?: boolean; + chunkSize?: number; + test?: RegExp | RegExp[]; + windowBits?: number; + memLevel?: number; + strategy?: number; + dictionary?: any; + threshold?: number; + minRatio?: number; +} + + +export class CompressionPlugin { + private asset = '[path].gz[query]'; + private algorithm: Function; + private compressionOptions: any = {}; + private test: RegExp[]; + private threshold: number = 0; + private minRatio: number = 0.8; + + constructor(options: CompressionPluginOptions = {}) { + if (options.hasOwnProperty('asset')) { + this.asset = options.asset; + } + + const algorithm = options.hasOwnProperty('algorithm') ? options.algorithm : 'gzip'; + + const zlib = require('zlib'); + + this.compressionOptions = {}; + this.algorithm = zlib[algorithm]; + if (!this.algorithm) { + throw new Error(`Algorithm not found in zlib: "${algorithm}".`); + } + + this.compressionOptions = { + level: options.level || 9, + flush: options.flush, + chunkSize: options.chunkSize, + windowBits: options.windowBits, + memLevel: options.memLevel, + strategy: options.strategy, + dictionary: options.dictionary + }; + + if (options.hasOwnProperty('test')) { + if (Array.isArray(options.test)) { + this.test = options.test as RegExp[]; + } else { + this.test = [options.test as RegExp]; + } + } + if (options.hasOwnProperty('threshold')) { + this.threshold = options.threshold; + } + if (options.hasOwnProperty('minRatio')) { + this.minRatio = options.minRatio; + } + } + + apply(compiler: any) { + compiler.plugin('this-compilation', (compilation: any) => { + compilation.plugin('optimize-assets', (assets: any, callback: Function) => { + async.forEach(Object.keys(assets), (file: string, callback: Function) => { + if (this.test.every((t) => !t.test(file))) { + return callback(); + } + + const asset = assets[file]; + let content = asset.source(); + if (!Buffer.isBuffer(content)) { + content = new Buffer(content, 'utf-8'); + } + + const originalSize = content.length; + if (originalSize < this.threshold) { + return callback(); + } + + this.algorithm(content, this.compressionOptions, (err: Error, result: string) => { + if (err) { + return callback(err); + } + if (result.length / originalSize > this.minRatio) { + return callback(); + } + + const parse = url.parse(file); + const newFile = this.asset + .replace(/\[file]/g, file) + .replace(/\[path]/g, parse.pathname) + .replace(/\[query]/g, parse.query || ''); + + assets[newFile] = new RawSource(result); + callback(); + }); + }, callback); + }); + }); + } +} diff --git a/packages/angular-cli/models/webpack-build-production.ts b/packages/angular-cli/models/webpack-build-production.ts index ad54db5c65cc..caf2fc58f3e0 100644 --- a/packages/angular-cli/models/webpack-build-production.ts +++ b/packages/angular-cli/models/webpack-build-production.ts @@ -1,6 +1,7 @@ import * as path from 'path'; +import {CompressionPlugin} from '../lib/webpack/compression-plugin'; + const WebpackMd5Hash = require('webpack-md5-hash'); -const CompressionPlugin = require('compression-webpack-plugin'); import * as webpack from 'webpack'; const ExtractTextPlugin = require('extract-text-webpack-plugin'); @@ -67,8 +68,7 @@ export const getWebpackProdConfigPartial = function(projectRoot: string, asset: '[path].gz[query]', algorithm: 'gzip', test: /\.js$|\.html$|\.css$/, - threshold: 10240, - minRatio: 0.8 + threshold: 10240 }), new webpack.LoaderOptionsPlugin({ options: { diff --git a/packages/angular-cli/package.json b/packages/angular-cli/package.json index cbcac1da3c8f..fd1114d93c58 100644 --- a/packages/angular-cli/package.json +++ b/packages/angular-cli/package.json @@ -34,7 +34,6 @@ "angular2-template-loader": "^0.5.0", "chalk": "^1.1.3", "common-tags": "^1.3.1", - "compression-webpack-plugin": "^0.3.2", "configstore": "^2.0.0", "core-js": "^2.4.0", "css-loader": "^0.23.1", From fc0baabda23f0a208822ac52d2bf069f64d0a3e4 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 5 Dec 2016 17:46:14 -0800 Subject: [PATCH 2/2] adding async dependency --- package.json | 1 + packages/angular-cli/package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/package.json b/package.json index 0d037c9768de..baa958496dd2 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@angular/core": "2.2.3", "@angular/tsc-wrapped": "0.4.0", "angular2-template-loader": "^0.5.0", + "async": "^2.1.4", "autoprefixer": "^6.5.3", "chalk": "^1.1.3", "common-tags": "^1.3.1", diff --git a/packages/angular-cli/package.json b/packages/angular-cli/package.json index fd1114d93c58..bc0d76ec0e5d 100644 --- a/packages/angular-cli/package.json +++ b/packages/angular-cli/package.json @@ -32,6 +32,7 @@ "@angular/core": "2.2.3", "@ngtools/webpack": "^1.0.0", "angular2-template-loader": "^0.5.0", + "async": "^2.1.4", "chalk": "^1.1.3", "common-tags": "^1.3.1", "configstore": "^2.0.0",