From ae59d0e668d76f16824af0df7210bbcedcb9de5c Mon Sep 17 00:00:00 2001 From: mdgriffith Date: Sat, 1 Aug 2020 09:59:24 -0400 Subject: [PATCH] add terser and report file sizes --- package-lock.json | 55 ++++++++++++++++++++----------- package.json | 6 ++-- src/compile-testcases.ts | 70 ++++++++++++++++++++++++++++++++++++++-- src/generate-report.ts | 64 ++++++++++++++++++++++++++++++++++-- 4 files changed, 169 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index f0787e4..81e58e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4543,6 +4543,15 @@ } } }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -7231,15 +7240,6 @@ "type-check": "~0.3.2" } }, - "lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "requires": { - "immediate": "~3.0.5" - } - }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -9252,6 +9252,25 @@ "rollup-pluginutils": "^2.8.2", "serialize-javascript": "^2.1.2", "terser": "^4.6.2" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + } } }, "rollup-plugin-typescript2": { @@ -9470,12 +9489,6 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true - }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -10165,9 +10178,9 @@ } }, "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.0.0.tgz", + "integrity": "sha512-olH2DwGINoSuEpSGd+BsPuAQaA3OrHnHnFL/rDB2TVNc3srUbz/rq/j2BlF4zDXI+JqAvGr86bIm1R2cJgZ3FA==", "dev": true, "requires": { "commander": "^2.20.0", @@ -10690,6 +10703,12 @@ "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==", "dev": true }, + "uglify-js": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", + "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", + "dev": true + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", diff --git a/package.json b/package.json index c1c90ac..b14d2c8 100644 --- a/package.json +++ b/package.json @@ -37,12 +37,14 @@ "chromedriver": "^84.0.1", "husky": "^4.2.5", "node-elm-compiler": "^5.0.4", - "selenium-webdriver": "^4.0.0-alpha.7", "prepack": "^0.2.54", + "selenium-webdriver": "^4.0.0-alpha.7", + "terser": "^5.0.0", "ts-node": "^8.10.2", "tsdx": "^0.13.2", "tslib": "^2.0.0", - "typescript": "^3.9.7" + "typescript": "^3.9.7", + "uglify-js": "^3.10.0" }, "dependencies": { "tree-sitter": "^0.16.1", diff --git a/src/compile-testcases.ts b/src/compile-testcases.ts index 5ab68d3..761ffa7 100644 --- a/src/compile-testcases.ts +++ b/src/compile-testcases.ts @@ -13,8 +13,9 @@ import { InlineMode, createInlineListFromArrayTransformer, } from './experiments/inlineListFromArray'; - import { prepackFileSync } from 'prepack'; +import * as Terser from 'terser'; +import { execSync } from 'child_process'; import { createReplaceUtilsUpdateWithObjectSpread, @@ -101,20 +102,83 @@ export const compileAndTransform = ( fs.writeFileSync(pathInOutput('elm.opt.js'), printer.printFile(initialJs)); if (options?.prepack) { - console.log('here'); + // console.log('here'); const { code } = prepackFileSync([pathInOutput('elm.opt.transformed.js')], { debugNames: true, inlineExpressions: true, maxStackDepth: 1200, // that didn't help }); - console.log('there', code.length); + // console.log('there', code.length); fs.writeFileSync(pathInOutput('elm.opt.prepack.js'), code); } + minify(pathInOutput('elm.opt.js'), pathInOutput('elm.opt.min.js')); + gzip(pathInOutput('elm.opt.min.js')); + minify( + pathInOutput('elm.opt.transformed.js'), + pathInOutput('elm.opt.transformed.min.js') + ); + gzip(pathInOutput('elm.opt.transformed.min.js')); + return {}; }; +async function minify(inputFilename: string, outputFilename: string) { + const compress = { + toplevel: true, + mangle: false, + compress: { + pure_getters: true, + keep_fargs: false, + unsafe_comps: true, + unsafe: true, + pure_funcs: [ + 'F2', + 'F3', + 'F4', + 'F5', + 'F6', + 'F7', + 'F8', + 'F9', + 'A2', + 'A3', + 'A4', + 'A5', + 'A6', + 'A7', + 'A8', + 'A9', + ], + }, + }; + const mangle = { + mangle: true, + compress: false, + }; + const input = fs.readFileSync(inputFilename, 'utf8'); + const compressed = await Terser.minify(input, compress); + + let mangled = null; + if (compressed && compressed.code) { + mangled = await Terser.minify(compressed.code, mangle); + } else { + console.log('Error compressing with Terser'); + } + // console.log('mangled', mangled.error); + if (mangled && mangled.code) { + fs.writeFileSync(outputFilename, mangled.code); + } else { + console.log('Error mangling with Terser'); + } +} +async function gzip(file: string) { + // --keep = keep the original file + // --force = overwrite the exisign gzip file if it's there + execSync('gzip --keep --force ' + file); +} + function reportInlineTransformResult(ctx: InlineContext) { const { splits, diff --git a/src/generate-report.ts b/src/generate-report.ts index 92fb560..8f41d6d 100644 --- a/src/generate-report.ts +++ b/src/generate-report.ts @@ -9,6 +9,7 @@ import * as compile from './compile-testcases'; import * as webdriver from 'selenium-webdriver'; import * as chrome from 'selenium-webdriver/chrome'; import * as path from 'path'; +import * as fs from 'fs'; const visitBenchmark = async (tag: string | null, file: string) => { let driver = new webdriver.Builder() @@ -30,6 +31,29 @@ const visitBenchmark = async (tag: string | null, file: string) => { return { tag: tag, browser: 'chrome', results: result }; }; +export interface Stat { + name: string; + bytes: number; +} + +const assetSizeStats = (dir: string): Stat[] => { + let stats: Stat[] = []; + fs.readdir(dir, function(err, files) { + if (err) { + console.log('Error getting directory information.'); + } else { + files.forEach(function(file) { + const stat = fs.statSync(path.join(dir, file)); + stats.push({ + name: path.basename(file), + bytes: stat.size, + }); + }); + } + }); + return stats; +}; + const run = async function() { compile.compileAndTransform('testcases/simple', 'Main.elm', { prepack: true, @@ -38,13 +62,18 @@ const run = async function() { prepack: true, }); + const assets = { + bench: assetSizeStats('testcases/bench/output'), + simple: assetSizeStats('testcases/simple/output'), + }; + let results = []; results.push(await visitBenchmark(null, 'testcases/bench/standard.html')); results.push( await visitBenchmark('transformed', 'testcases/bench/transformed.html') ); - console.log(markdownNewResults(reformat(results))); + console.log(markdownNewResults(assets, reformat(results))); }; const markdownResults = (results: any): string => { @@ -78,11 +107,35 @@ const markdownResults = (results: any): string => { return buffer.join('\n'); }; -const markdownNewResults = (results: any): string => { +const markdownNewResults = ( + assets: { [key: string]: Stat[] }, + results: any +): string => { let buffer: string[] = []; buffer.push('# Benchmark results'); buffer.push(''); + + // List asset sizes + for (let key in assets) { + buffer.push('## ' + key + ' asset overview'); + buffer.push(''); + assets[key].forEach((item: Stat) => { + buffer.push( + ' ' + + item.name.padEnd(40, ' ') + + '' + + humanizeNumber( + roundToDecimal(1, item.bytes / Math.pow(2, 10)) + ).padStart(10, ' ') + + 'kb' + ); + }); + buffer.push(''); + } + buffer.push(''); + + // List benchmarks for (let key in results) { buffer.push('## ' + key); buffer.push(''); @@ -175,8 +228,13 @@ function reformat(results: any): any { } // adds commas to the number so its easier to read. -function humanizeNumber(x: string): string { +function humanizeNumber(x: number): string { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } +function roundToDecimal(level: number, num: number): number { + let factor: number = Math.pow(10, level); + return Math.round(num * factor) / factor; +} + run();