Skip to content

Instantly share code, notes, and snippets.

@IgorMinar
Last active March 30, 2017 11:55
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IgorMinar/09eadcb221a8253162078210639a344d to your computer and use it in GitHub Desktop.
Save IgorMinar/09eadcb221a8253162078210639a344d to your computer and use it in GitHub Desktop.
purify.js with cli and webpack plugin - simple and super-hackish Uglify pre-optimizer

This is a super-hacky tool that processes JavaScript bundless before they are fed to Uglify.

Purify adds @__PURE__ annotation in front of all IIFE's that represent ES classes downleveled by TypeScript.

This annotation then enables Uglify 2.8+ to safely recognize if the class is not used and remove it.

You can use it webpack-plugin or cli.

Angular developers will need the bundle to be also processed by alxhub/ngo before the full effect can be seen.

The goal of this tool is to estimate the impact of this optimization. It's not really meant for production use, but primarily for research. That's why I didn't publish it on npm or as a github repo.

The proper solution is going to be implemented via AST transformations rather than unreliable regular expression substitution.

Follow angular/tsickle/#452 and Microsoft/TypeScript#13721.

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const fs = require('fs');
const pureReplace = require('./purify');
const inputFile = process.argv[2];
const inputFileBody = fs.readFileSync(inputFile).toString();
console.log(pureReplace(inputFileBody));
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const purify= require('./purify');
function PurifyPlugin(options) {
console.log('purify plugin init');
}
PurifyPlugin.prototype.apply = function(compiler) {
compiler.plugin('compilation', function(compilation) {
compilation.plugin('optimize-chunk-assets', function(chunks, callback) {
chunks.forEach(function(chunk) {
chunk.files.filter((fileName) => fileName.endsWith('.bundle.js')).forEach((fileName) => {
console.log(`purifying ${fileName}`);
const purifiedSource = purify(compilation.assets[fileName].source());
compilation.assets[fileName]._cachedSource = purifiedSource;
compilation.assets[fileName]._source.source = () => purifiedSource;
});
});
callback();
});
});
};
module.exports = PurifyPlugin;
// install by adding this into "plugins" array, in node_modules/\@angular/cli/models/webpack-configs/production.js
// requires ngo loader to be effective
// new (require("../../../../../purify-webpack-plugin.js"))(),
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
module.exports = function(fileBody) {
return fileBody
/* prefix downleveled classes w/ the @__PURE__ annotation */
.replace(
/^(var (\S+) = )(\(function \(\) \{\n(?: (?:\/\*\*| \*|\*\/|\/\/)[^\n]*\n)* function \2\([^\)]*\) \{\n)/mg,
'$1/*@__PURE__*/$3'
)
/* prefix downleveled classes that extend another class w/ the @__PURE__ annotation */
.replace(
/^(var (\S+) = )(\(function \(_super\) \{\n __extends\(\2, _super\);\n)/mg,
'$1/*@__PURE__*/$3'
)
/* all of the following helper stripping relies on
* https://github.com/Microsoft/tslib/blob/6be26c8c0772d9931c7c4a0b981160e164782e53/tslib.js loaded before
* the bundle is evaluated by the browser
*/
/* strip __extends helper */
.replace(
/^var __extends = \(.*\n( .*\n)*\};\n/mg,
'\n\n\n\n\n'
)
/* strip __decorate helper */
.replace(
/^var __decorate = \(.*\n( .*\n)*\};\n/mg,
'\n\n\n\n\n\n'
)
/* strip __metadata helper */
.replace(
/^var __metadata = \(.*\n( .*\n)*\};\n/mg,
'\n\n\n\n\n\n'
)
/* strip __param helper */
.replace(
/^var __param = \(.*\n( .*\n)*\};\n/mg,
'\n\n\n'
)
/* strip all license headers / comments */
.replace(
/^\/\*\*\n \* @license.*\n( \*[^/].*\n)* \*\//mg,
'\n'
)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment