From d3ed6efeec6113e64a4ce265f7e18d8d7e89a1df Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Wed, 28 Sep 2016 18:07:34 -0700 Subject: [PATCH] tests pass. --- .gitignore | 1 + jsconfig.json | 20 -- lighthouse-cli/ask.ts | 49 ----- lighthouse-cli/bin.js | 2 +- lighthouse-cli/chrome-finder.ts | 130 ------------ lighthouse-cli/chrome-launcher.ts | 243 ---------------------- lighthouse-cli/decl/ask.d.ts | 3 + lighthouse-cli/decl/chrome-finder.d.ts | 4 + lighthouse-cli/decl/chrome-launcher.d.ts | 25 +++ lighthouse-cli/decl/index.d.ts | 1 + lighthouse-cli/decl/printer.d.ts | 38 ++++ lighthouse-cli/index.js | 2 +- lighthouse-cli/index.ts | 254 ----------------------- lighthouse-cli/js/ask.js | 43 ++++ lighthouse-cli/js/ask.js.map | 1 + lighthouse-cli/js/chrome-finder.js | 112 ++++++++++ lighthouse-cli/js/chrome-finder.js.map | 1 + lighthouse-cli/js/chrome-launcher.js | 197 ++++++++++++++++++ lighthouse-cli/js/chrome-launcher.js.map | 1 + lighthouse-cli/js/index.js | 220 ++++++++++++++++++++ lighthouse-cli/js/index.js.map | 1 + lighthouse-cli/js/printer.js | 184 ++++++++++++++++ lighthouse-cli/js/printer.js.map | 1 + lighthouse-cli/jsconfig.json | 18 ++ lighthouse-cli/printer.ts | 226 -------------------- lighthouse-cli/test/cli/printer-test.js | 2 +- lighthouse-cli/tsconfig.json | 21 -- 27 files changed, 854 insertions(+), 946 deletions(-) delete mode 100644 jsconfig.json delete mode 100644 lighthouse-cli/ask.ts delete mode 100644 lighthouse-cli/chrome-finder.ts delete mode 100644 lighthouse-cli/chrome-launcher.ts create mode 100644 lighthouse-cli/decl/ask.d.ts create mode 100644 lighthouse-cli/decl/chrome-finder.d.ts create mode 100644 lighthouse-cli/decl/chrome-launcher.d.ts create mode 100644 lighthouse-cli/decl/index.d.ts create mode 100644 lighthouse-cli/decl/printer.d.ts delete mode 100755 lighthouse-cli/index.ts create mode 100644 lighthouse-cli/js/ask.js create mode 100644 lighthouse-cli/js/ask.js.map create mode 100644 lighthouse-cli/js/chrome-finder.js create mode 100644 lighthouse-cli/js/chrome-finder.js.map create mode 100644 lighthouse-cli/js/chrome-launcher.js create mode 100644 lighthouse-cli/js/chrome-launcher.js.map create mode 100644 lighthouse-cli/js/index.js create mode 100644 lighthouse-cli/js/index.js.map create mode 100644 lighthouse-cli/js/printer.js create mode 100644 lighthouse-cli/js/printer.js.map create mode 100644 lighthouse-cli/jsconfig.json delete mode 100644 lighthouse-cli/printer.ts delete mode 100644 lighthouse-cli/tsconfig.json diff --git a/.gitignore b/.gitignore index 3e1a0ede2223..4ac181580954 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ closure-error.log typings lighthouse-cli/out +outagain diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index d62db7ce4c1f..000000000000 --- a/jsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "//": "to run: tsc -p ./jsconfig.json ", - - "//": "good docs here: https://github.com/Microsoft/vscode-docs/blob/vnext/docs/languages/javascript.md#javascript-projects-jsconfigjson ", - - "compilerOptions": { - "target": "ES6", - "outDir": "./dist", - "diagnostics": true - }, - "exclude": [ - "node_modules", - "lighthouse-extension", - "lighthouse-core/closure", - - "third_party", - "lighthouse-core/third_party", - "dist" - ] -} diff --git a/lighthouse-cli/ask.ts b/lighthouse-cli/ask.ts deleted file mode 100644 index 439277f8a1cb..000000000000 --- a/lighthouse-cli/ask.ts +++ /dev/null @@ -1,49 +0,0 @@ -/// - -/** - * @license - * Copyright 2016 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const readline = require('readline'); - -function ask(question: string, options: string[]): Promise { - return new Promise((resolve, reject) => { - const iface = readline.createInterface(process.stdin, process.stdout); - const optionsStr = options.map((o, i) => i + 1 + '. ' + o).join('\r\n'); - - iface.setPrompt(question + '\r\n' + optionsStr + '\r\nChoice: '); - iface.prompt(); - - iface.on('line', _answer => { - const answer = toInt(_answer); - if (answer > 0 && answer <= options.length) { - iface.close(); - resolve(options[answer - 1]); - } else { - iface.prompt(); - } - }); - }); -} - -function toInt(n: string): number { - const result = parseInt(n, 10); - return isNaN(result) ? 0 : result; -} - -export {ask}; diff --git a/lighthouse-cli/bin.js b/lighthouse-cli/bin.js index 5032b84e1930..0a2122338883 100755 --- a/lighthouse-cli/bin.js +++ b/lighthouse-cli/bin.js @@ -2,4 +2,4 @@ 'use strict'; -require('./out/index.js'); +require('./js/index.js'); diff --git a/lighthouse-cli/chrome-finder.ts b/lighthouse-cli/chrome-finder.ts deleted file mode 100644 index 1827c0a3489c..000000000000 --- a/lighthouse-cli/chrome-finder.ts +++ /dev/null @@ -1,130 +0,0 @@ -/// - -/** - * @license - * Copyright 2016 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const execSync = require('child_process').execSync; - -export function darwin() { - const suffix = '/Contents/MacOS/Google Chrome Canary'; - - const LSREGISTER = - '/System/Library/Frameworks/CoreServices.framework' + - '/Versions/A/Frameworks/LaunchServices.framework' + - '/Versions/A/Support/lsregister'; - - const installations = []; - - execSync( - `${LSREGISTER} -dump` + - ' | grep -i \'google chrome canary.app$\'' + - ' | awk \'{$1=""; print $0}\'' - ).toString() - .split(/\r?\n/) - .forEach(inst => { - const execPath = path.join(inst.trim(), suffix); - if (canAccess(execPath)) { - installations.push(execPath); - } - }); - - /* https://github.com/Microsoft/TypeScript/issues/6574 - const priorities = new Map([ - [/^\/Volumes\//, -1], - [/^\/Applications\//, 100], - [new RegExp(`^${process.env.HOME}/Applications/`), 50] - ]); - */ - const priorities: {regex: RegExp, weight: number}[] = [{ - regex: /^\/Volumes\//, - weight: -1 - }, { - regex: /^\/Applications\//, - weight: 100 - }, - { - regex: new RegExp(`^${process.env.HOME}/Applications/`), - weight: 50 - } - ]; - - return sort(installations, priorities); -} - -export function linux() { - const execPath = process.env.LIGHTHOUSE_CHROMIUM_PATH; - if (execPath && canAccess(execPath)) { - return [execPath]; - } - throw new Error( - 'The environment variable LIGHTHOUSE_CHROMIUM_PATH must be set to ' + - 'executable of a build of Chromium version 52.0 or later.' - ); -} - -export function win32() { - const installations = []; - const suffixes = [ - '\\Google\\Chrome SxS\\Application\\chrome.exe', - '\\Google\\Chrome\\Application\\chrome.exe' - ]; - let prefixes = [ - process.env.LOCALAPPDATA, - process.env.PROGRAMFILES, - process.env['PROGRAMFILES(X86)'] - ]; - prefixes.forEach(prefix => - suffixes.forEach(suffix => { - const chromePath = path.join(prefix, suffix); - if (canAccess(chromePath)) { - installations.push(chromePath); - } - }) - ); - return installations; -} - -function sort(installations, priorities) { - const defaultPriority = 10; - return installations - // assign priorities - .map(inst => { - for (let pair of priorities) { - if (pair.regex.test(inst)) { - return [inst, pair.weight]; - } - } - return [inst, defaultPriority]; - }) - // sort based on priorities - .sort((a, b) => b[1] - a[1]) - // remove priority flag - .map(pair => pair[0]); -} - -function canAccess(file: string): Boolean { - try { - fs.accessSync(file); - return true; - } catch (e) { - return false; - } -} diff --git a/lighthouse-cli/chrome-launcher.ts b/lighthouse-cli/chrome-launcher.ts deleted file mode 100644 index 9c1ce6aaf9f6..000000000000 --- a/lighthouse-cli/chrome-launcher.ts +++ /dev/null @@ -1,243 +0,0 @@ -/// - -/** - * @license - * Copyright 2016 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -import * as childProcess from 'child_process'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as chromeFinder from './chrome-finder'; -import {ask} from './ask'; - -const mkdirp = require('mkdirp'); -const net = require('net'); -const rimraf = require('rimraf'); - -const spawn = childProcess.spawn; -const execSync = childProcess.execSync; -const spawnSync = childProcess.spawnSync; - -class ChromeLauncher { - prepared: Boolean = false - pollInterval: number = 500 - autoSelectChrome: Boolean - TMP_PROFILE_DIR: string - outFile: number - errFile: number - pidFile: string - chrome: childProcess.ChildProcess - - // We can not use default args here due to support node pre 6. - constructor(opts?: {autoSelectChrome?: Boolean}) { - opts = opts || {}; - - // choose the first one (default) - this.autoSelectChrome = defaults(opts.autoSelectChrome, true); - } - - flags() { - const flags = [ - '--remote-debugging-port=9222', - '--no-first-run', - `--user-data-dir=${this.TMP_PROFILE_DIR}` - ]; - - if (process.platform === 'linux') { - flags.push('--disable-setuid-sandbox'); - } - - return flags; - } - - prepare() { - switch (process.platform) { - case 'darwin': - case 'linux': - this.TMP_PROFILE_DIR = unixTmpDir(); - break; - - case 'win32': - this.TMP_PROFILE_DIR = win32TmpDir(); - break; - - default: - throw new Error('Platform ' + process.platform + ' is not supported'); - } - - this.outFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-out.log`, 'a'); - this.errFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-err.log`, 'a'); - - // fix for Node4 - // you can't pass a fd to fs.writeFileSync - this.pidFile = `${this.TMP_PROFILE_DIR}/chrome.pid`; - - console.log(`created ${this.TMP_PROFILE_DIR}`); - - this.prepared = true; - } - - run() { - if (!this.prepared) { - this.prepare(); - } - - return Promise.resolve() - .then(() => { - const installations = chromeFinder[process.platform](); - if (installations.length < 1) { - return Promise.reject(new Error('No Chrome Installations Found')); - } else if (installations.length === 1 || this.autoSelectChrome) { - return installations[0]; - } - - return ask('Choose a Chrome installation to use with Lighthouse', installations); - }) - .then(execPath => this.spawn(execPath)); - } - - spawn(execPath: string): Promise { - return new Promise((resolve, reject) => { - const chrome = spawn( - execPath, - this.flags(), - { - detached: true, - stdio: ['ignore', this.outFile, this.errFile] - } - ); - this.chrome = chrome; - - fs.writeFileSync(this.pidFile, chrome.pid.toString()); - - console.log('Chrome running with pid =', chrome.pid); - resolve(chrome.pid); - }) - .then(pid => Promise.all([pid, this.waitUntilReady()])); - } - - cleanup(client) { - if (client) { - client.removeAllListeners(); - client.end(); - client.destroy(); - client.unref(); - } - } - - // resolves if ready, rejects otherwise - isDebuggerReady(): Promise { - return new Promise((resolve, reject) => { - const client = net.createConnection(9222); - client.once('error', err => { - this.cleanup(client); - reject(err); - }); - client.once('connect', _ => { - this.cleanup(client); - resolve(); - }); - }); - } - - // resolves when debugger is ready, rejects after 10 polls - waitUntilReady(): Promise { - const launcher = this; - - return new Promise((resolve, reject) => { - let retries = 0; - (function poll() { - const green = '\x1B[32m'; - const reset = '\x1B[0m'; - - if (retries === 0) { - process.stdout.write('Waiting for browser.'); - } - retries++; - process.stdout.write('..'); - - launcher - .isDebuggerReady() - .then(() => { - process.stdout.write(`${green}✓${reset}\n`); - resolve(); - }) - .catch(err => { - if (retries > 10) { - process.stdout.write('\n'); - return reject(err); - } - delay(launcher.pollInterval).then(poll); - }); - })(); - }); - } - - kill(): Promise { - return new Promise(resolve => { - if (this.chrome) { - this.chrome.on('close', () => { - this.destroyTmp(); - resolve(); - }); - - console.log('Killing all Chrome Instances'); - this.chrome.kill(); - - if (process.platform === 'win32') { - spawnSync(`taskkill /pid ${this.chrome.pid} /T /F`); - } - } else { - // fail silently as we did not start chrome - resolve(); - } - }); - } - - destroyTmp() { - if (this.TMP_PROFILE_DIR) { - console.log(`Removing ${this.TMP_PROFILE_DIR}`); - rimraf.sync(this.TMP_PROFILE_DIR); - } - } -}; - -function defaults(val, def) { - return typeof val === 'undefined' ? def : val; -} - -function delay(time) { - return new Promise(resolve => setTimeout(resolve, time)); -} - -function unixTmpDir() { - return execSync('mktemp -d -t lighthouse.XXXXXXX').toString().trim(); -} - -function win32TmpDir() { - const winTmpPath = process.env.TEMP || - process.env.TMP || - (process.env.SystemRoot || process.env.windir) + '\\temp'; - const randomNumber = Math.floor(Math.random() * 9e7 + 1e7); - const tmpdir = path.join(winTmpPath, 'lighthouse.' + randomNumber); - - mkdirp.sync(tmpdir); - return tmpdir; -} - -export {ChromeLauncher}; diff --git a/lighthouse-cli/decl/ask.d.ts b/lighthouse-cli/decl/ask.d.ts new file mode 100644 index 000000000000..0e939ce55bbf --- /dev/null +++ b/lighthouse-cli/decl/ask.d.ts @@ -0,0 +1,3 @@ +/// +declare function ask(question: string, options: string[]): Promise; +export { ask }; diff --git a/lighthouse-cli/decl/chrome-finder.d.ts b/lighthouse-cli/decl/chrome-finder.d.ts new file mode 100644 index 000000000000..ab8459894575 --- /dev/null +++ b/lighthouse-cli/decl/chrome-finder.d.ts @@ -0,0 +1,4 @@ +/// +export declare function darwin(): any; +export declare function linux(): any[]; +export declare function win32(): any[]; diff --git a/lighthouse-cli/decl/chrome-launcher.d.ts b/lighthouse-cli/decl/chrome-launcher.d.ts new file mode 100644 index 000000000000..81e7744f105b --- /dev/null +++ b/lighthouse-cli/decl/chrome-launcher.d.ts @@ -0,0 +1,25 @@ +/// +import * as childProcess from 'child_process'; +declare class ChromeLauncher { + prepared: Boolean; + pollInterval: number; + autoSelectChrome: Boolean; + TMP_PROFILE_DIR: string; + outFile: number; + errFile: number; + pidFile: string; + chrome: childProcess.ChildProcess; + constructor(opts?: { + autoSelectChrome?: Boolean; + }); + flags(): string[]; + prepare(): void; + run(): Promise; + spawn(execPath: string): Promise; + cleanup(client: any): void; + isDebuggerReady(): Promise; + waitUntilReady(): Promise; + kill(): Promise; + destroyTmp(): void; +} +export { ChromeLauncher }; diff --git a/lighthouse-cli/decl/index.d.ts b/lighthouse-cli/decl/index.d.ts new file mode 100644 index 000000000000..eebc2728b868 --- /dev/null +++ b/lighthouse-cli/decl/index.d.ts @@ -0,0 +1 @@ +/// diff --git a/lighthouse-cli/decl/printer.d.ts b/lighthouse-cli/decl/printer.d.ts new file mode 100644 index 000000000000..bf23408dde0b --- /dev/null +++ b/lighthouse-cli/decl/printer.d.ts @@ -0,0 +1,38 @@ +/// +export declare type Mode = 'pretty' | 'json' | 'html'; +export interface Results { + url: string; + aggregations: any[]; + audits: Object; +} +/** + * An enumeration of acceptable output modes: + *
    + *
  • 'pretty': Pretty print the results
  • + *
  • 'json': JSON formatted results
  • + *
  • 'html': An HTML report
  • + *
+ * @enum {string} + */ +declare const OUTPUT_MODE: { + pretty: string; + json: string; + html: string; +}; +/** + * Verify output mode. + */ +declare function checkOutputMode(mode: string): Mode; +/** + * Verify output path to use, either stdout or a file path. + */ +declare function checkOutputPath(path: string): string; +/** + * Creates the results output in a format based on the `mode`. + */ +declare function createOutput(results: Results, outputMode: Mode): string; +/** + * Writes the results. + */ +declare function write(results: Results, mode: Mode, path: string): Promise; +export { checkOutputMode, checkOutputPath, createOutput, write, OUTPUT_MODE }; diff --git a/lighthouse-cli/index.js b/lighthouse-cli/index.js index 5032b84e1930..0a2122338883 100755 --- a/lighthouse-cli/index.js +++ b/lighthouse-cli/index.js @@ -2,4 +2,4 @@ 'use strict'; -require('./out/index.js'); +require('./js/index.js'); diff --git a/lighthouse-cli/index.ts b/lighthouse-cli/index.ts deleted file mode 100755 index b6a93e0675d0..000000000000 --- a/lighthouse-cli/index.ts +++ /dev/null @@ -1,254 +0,0 @@ -/// - -/** - * @license - * Copyright 2016 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const environment = require('../../lighthouse-core/lib/environment.js'); -if (!environment.checkNodeCompatibility()) { - console.warn('Compatibility error', 'Lighthouse requires node 5+ or 4 with --harmony'); - process.exit(1); -} - -const path = require('path'); -const yargs = require('yargs'); -import * as Printer from './printer'; -const lighthouse = require('../../lighthouse-core'); -const assetSaver = require('../../lighthouse-core/lib/asset-saver.js'); -import {ChromeLauncher} from './chrome-launcher'; - -const perfOnlyConfig = require('../../lighthouse-core/config/perf.json'); - -const cli = yargs - .help('help') - .version(() => require('../package').version) - .showHelpOnFail(false, 'Specify --help for available options') - - .usage('$0 url') - - // List of options - .group([ - 'verbose', - 'quiet' - ], 'Logging:') - .describe({ - verbose: 'Displays verbose logging', - quiet: 'Displays no progress or debug logs' - }) - - .group([ - 'mobile', - 'save-assets', - 'save-artifacts', - 'list-all-audits', - 'list-trace-categories', - 'config-path', - 'perf' - ], 'Configuration:') - .describe({ - 'mobile': 'Emulates a Nexus 5X', - 'save-assets': 'Save the trace contents & screenshots to disk', - 'save-artifacts': 'Save all gathered artifacts to disk', - 'list-all-audits': 'Prints a list of all available audits and exits', - 'list-trace-categories': 'Prints a list of all required trace categories and exits', - 'config-path': 'The path to the config JSON.', - 'perf': 'Use a performance-test-only configuration', - 'skip-autolaunch': 'Skip autolaunch of chrome when accessing port 9222 fails', - 'select-chrome': 'Choose chrome location to use when multiple installations are found', - }) - - .group([ - 'output', - 'output-path' - ], 'Output:') - .describe({ - 'output': 'Reporter for the results', - 'output-path': `The file path to output the results -Example: --output-path=./lighthouse-results.html` - }) - - // boolean values - .boolean([ - 'save-assets', - 'save-artifacts', - 'list-all-audits', - 'list-trace-categories', - 'perf', - 'skip-autolaunch', - 'select-chrome', - 'verbose', - 'quiet', - 'help' - ]) - - .choices('output', Object.keys(Printer.OUTPUT_MODE).map(k => Printer.OUTPUT_MODE[k])) - - // default values - .default('mobile', true) - .default('output', Printer.OUTPUT_MODE.pretty) - .default('output-path', 'stdout') - .check(argv => { - // Make sure lighthouse has been passed a url, or at least one of --list-all-audits - // or --list-trace-categories. If not, stop the program and ask for a url - if (!argv.listAllAudits && !argv.listTraceCategories && argv._.length === 0) { - throw new Error('Please provide a url'); - } - - return true; - }) - .argv; - -if (cli.listAllAudits) { - const audits = lighthouse - .getAuditList() - .map(i => { - return i.replace(/\.js$/, ''); - }); - - process.stdout.write(JSON.stringify({audits})); - process.exit(0); -} - -if (cli.listTraceCategories) { - const traceCategories = lighthouse.traceCategories; - - process.stdout.write(JSON.stringify({traceCategories})); - process.exit(0); -} - -const urls = cli._; -const outputMode = cli.output; -const outputPath = cli['output-path']; -const flags = cli; - -let config = null; -if (cli.configPath) { - // Resolve the config file path relative to where cli was called. - cli.configPath = path.resolve(process.cwd(), cli.configPath); - config = require(cli.configPath); -} else if (cli.perf) { - config = perfOnlyConfig; -} - -// set logging preferences -flags.logLevel = 'info'; -if (cli.verbose) { - flags.logLevel = 'verbose'; -} else if (cli.quiet) { - flags.logLevel = 'error'; -} - -const cleanup = { - fns: [], - register(fn) { - this.fns.push(fn); - }, - doCleanup() { - return Promise.all(this.fns.map(c => c())); - } -}; - -function launchChromeAndRun(addresses) { - const launcher = new ChromeLauncher({ - autoSelectChrome: !cli.selectChrome, - }); - - cleanup.register(() => launcher.kill()); - - return launcher - .isDebuggerReady() - .catch(() => { - console.log('Launching Chrome...'); - return launcher.run(); - }) - .then(() => lighthouseRun(addresses)) - .then(() => launcher.kill()); -} - -function lighthouseRun(addresses) { - // Process URLs once at a time - const address = addresses.shift(); - if (!address) { - return; - } - - return lighthouse(address, flags, config) - .then(results => Printer.write(results, outputMode, outputPath)) - .then(results => { - if (outputMode !== 'html') { - const filename = './' + assetSaver.getFilenamePrefix({url: address}) + '.html'; - Printer.write(results, 'html', filename) - } - - return lighthouseRun(addresses); - }); -} - -function showConnectionError() { - console.error('Unable to connect to Chrome'); - console.error( - 'If you\'re using lighthouse with --skip-autolaunch, ' + - 'make sure you\'re running some other Chrome with a debugger.' - ); - process.exit(1); -} - -function showRuntimeError(err) { - console.error('Runtime error encountered:', err); - console.error(err.stack); - process.exit(1); -} - -function handleError(err) { - if (err.code === 'ECONNREFUSED') { - showConnectionError(); - } else { - showRuntimeError(err); - } -} - -function run() { - if (cli.skipAutolaunch) { - lighthouseRun(urls).catch(handleError); - } else { - // because you can't cancel a promise yet - const SIGINT = 'SIGINT'; - const isSigint = new Promise((resolve, reject) => { - process.on('SIGINT', () => reject(SIGINT)); - }); - - Promise - .race([launchChromeAndRun(urls), isSigint]) - .catch(maybeSigint => { - if (maybeSigint === SIGINT) { - return cleanup - .doCleanup() - .then(() => process.exit(130)) - .catch(err => { - console.error(err); - console.error(err.stack); - process.exit(130); - }); - } - return handleError(maybeSigint); - }); - } -} - -// kick off a lighthouse run -run(); diff --git a/lighthouse-cli/js/ask.js b/lighthouse-cli/js/ask.js new file mode 100644 index 000000000000..eceda17ccd42 --- /dev/null +++ b/lighthouse-cli/js/ask.js @@ -0,0 +1,43 @@ +/// +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; +const readline = require('readline'); +function ask(question, options) { + return new Promise((resolve, reject) => { + const iface = readline.createInterface(process.stdin, process.stdout); + const optionsStr = options.map((o, i) => i + 1 + '. ' + o).join('\r\n'); + iface.setPrompt(question + '\r\n' + optionsStr + '\r\nChoice: '); + iface.prompt(); + iface.on('line', _answer => { + const answer = toInt(_answer); + if (answer > 0 && answer <= options.length) { + iface.close(); + resolve(options[answer - 1]); + } + else { + iface.prompt(); + } + }); + }); +} +exports.ask = ask; +function toInt(n) { + const result = parseInt(n, 10); + return isNaN(result) ? 0 : result; +} +//# sourceMappingURL=ask.js.map diff --git a/lighthouse-cli/js/ask.js.map b/lighthouse-cli/js/ask.js.map new file mode 100644 index 000000000000..58616196b256 --- /dev/null +++ b/lighthouse-cli/js/ask.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ask.js","sourceRoot":"","sources":["../ask.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C;;;;;;;;;;;;;;;GAeG;AAEH,YAAY,CAAC;AAEb,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAErC,aAAa,QAAgB,EAAE,OAAiB;IAC9C,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM;QACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACtE,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAExE,KAAK,CAAC,SAAS,CAAC,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,cAAc,CAAC,CAAC;QACjE,KAAK,CAAC,MAAM,EAAE,CAAC;QAEf,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO;YACtB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;YAC9B,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC3C,KAAK,CAAC,KAAK,EAAE,CAAC;gBACd,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC;YAAC,IAAI,CAAC,CAAC;gBACN,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAOO,WAAG,OAPV;AAED,eAAe,CAAS;IACtB,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;AACpC,CAAC;AAEY"} \ No newline at end of file diff --git a/lighthouse-cli/js/chrome-finder.js b/lighthouse-cli/js/chrome-finder.js new file mode 100644 index 000000000000..bc2b7cdb05e7 --- /dev/null +++ b/lighthouse-cli/js/chrome-finder.js @@ -0,0 +1,112 @@ +/// +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; +const fs = require('fs'); +const path = require('path'); +const execSync = require('child_process').execSync; +function darwin() { + const suffix = '/Contents/MacOS/Google Chrome Canary'; + const LSREGISTER = '/System/Library/Frameworks/CoreServices.framework' + + '/Versions/A/Frameworks/LaunchServices.framework' + + '/Versions/A/Support/lsregister'; + const installations = []; + execSync(`${LSREGISTER} -dump` + + ' | grep -i \'google chrome canary.app$\'' + + ' | awk \'{$1=""; print $0}\'').toString() + .split(/\r?\n/) + .forEach(inst => { + const execPath = path.join(inst.trim(), suffix); + if (canAccess(execPath)) { + installations.push(execPath); + } + }); + /* https://github.com/Microsoft/TypeScript/issues/6574 + const priorities = new Map([ + [/^\/Volumes\//, -1], + [/^\/Applications\//, 100], + [new RegExp(`^${process.env.HOME}/Applications/`), 50] + ]); + */ + const priorities = [{ + regex: /^\/Volumes\//, + weight: -1 + }, { + regex: /^\/Applications\//, + weight: 100 + }, + { + regex: new RegExp(`^${process.env.HOME}/Applications/`), + weight: 50 + } + ]; + return sort(installations, priorities); +} +exports.darwin = darwin; +function linux() { + const execPath = process.env.LIGHTHOUSE_CHROMIUM_PATH; + if (execPath && canAccess(execPath)) { + return [execPath]; + } + throw new Error('The environment variable LIGHTHOUSE_CHROMIUM_PATH must be set to ' + + 'executable of a build of Chromium version 52.0 or later.'); +} +exports.linux = linux; +function win32() { + const installations = []; + const suffixes = [ + '\\Google\\Chrome SxS\\Application\\chrome.exe', + '\\Google\\Chrome\\Application\\chrome.exe' + ]; + let prefixes = [ + process.env.LOCALAPPDATA, + process.env.PROGRAMFILES, + process.env['PROGRAMFILES(X86)'] + ]; + prefixes.forEach(prefix => suffixes.forEach(suffix => { + const chromePath = path.join(prefix, suffix); + if (canAccess(chromePath)) { + installations.push(chromePath); + } + })); + return installations; +} +exports.win32 = win32; +function sort(installations, priorities) { + const defaultPriority = 10; + return installations + .map(inst => { + for (let pair of priorities) { + if (pair.regex.test(inst)) { + return [inst, pair.weight]; + } + } + return [inst, defaultPriority]; + }) + .sort((a, b) => b[1] - a[1]) + .map(pair => pair[0]); +} +function canAccess(file) { + try { + fs.accessSync(file); + return true; + } + catch (e) { + return false; + } +} +//# sourceMappingURL=chrome-finder.js.map diff --git a/lighthouse-cli/js/chrome-finder.js.map b/lighthouse-cli/js/chrome-finder.js.map new file mode 100644 index 000000000000..bc7b5d80909e --- /dev/null +++ b/lighthouse-cli/js/chrome-finder.js.map @@ -0,0 +1 @@ +{"version":3,"file":"chrome-finder.js","sourceRoot":"","sources":["../chrome-finder.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lighthouse-cli/js/chrome-launcher.js b/lighthouse-cli/js/chrome-launcher.js new file mode 100644 index 000000000000..56d92e6fe75a --- /dev/null +++ b/lighthouse-cli/js/chrome-launcher.js @@ -0,0 +1,197 @@ +/// +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; +const childProcess = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const chromeFinder = require('./chrome-finder'); +const ask_1 = require('./ask'); +const mkdirp = require('mkdirp'); +const net = require('net'); +const rimraf = require('rimraf'); +const spawn = childProcess.spawn; +const execSync = childProcess.execSync; +const spawnSync = childProcess.spawnSync; +class ChromeLauncher { + // We can not use default args here due to support node pre 6. + constructor(opts) { + this.prepared = false; + this.pollInterval = 500; + opts = opts || {}; + // choose the first one (default) + this.autoSelectChrome = defaults(opts.autoSelectChrome, true); + } + flags() { + const flags = [ + '--remote-debugging-port=9222', + '--no-first-run', + `--user-data-dir=${this.TMP_PROFILE_DIR}` + ]; + if (process.platform === 'linux') { + flags.push('--disable-setuid-sandbox'); + } + return flags; + } + prepare() { + switch (process.platform) { + case 'darwin': + case 'linux': + this.TMP_PROFILE_DIR = unixTmpDir(); + break; + case 'win32': + this.TMP_PROFILE_DIR = win32TmpDir(); + break; + default: + throw new Error('Platform ' + process.platform + ' is not supported'); + } + this.outFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-out.log`, 'a'); + this.errFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-err.log`, 'a'); + // fix for Node4 + // you can't pass a fd to fs.writeFileSync + this.pidFile = `${this.TMP_PROFILE_DIR}/chrome.pid`; + console.log(`created ${this.TMP_PROFILE_DIR}`); + this.prepared = true; + } + run() { + if (!this.prepared) { + this.prepare(); + } + return Promise.resolve() + .then(() => { + const installations = chromeFinder[process.platform](); + if (installations.length < 1) { + return Promise.reject(new Error('No Chrome Installations Found')); + } + else if (installations.length === 1 || this.autoSelectChrome) { + return installations[0]; + } + return ask_1.ask('Choose a Chrome installation to use with Lighthouse', installations); + }) + .then(execPath => this.spawn(execPath)); + } + spawn(execPath) { + return new Promise((resolve, reject) => { + const chrome = spawn(execPath, this.flags(), { + detached: true, + stdio: ['ignore', this.outFile, this.errFile] + }); + this.chrome = chrome; + fs.writeFileSync(this.pidFile, chrome.pid.toString()); + console.log('Chrome running with pid =', chrome.pid); + resolve(chrome.pid); + }) + .then(pid => Promise.all([pid, this.waitUntilReady()])); + } + cleanup(client) { + if (client) { + client.removeAllListeners(); + client.end(); + client.destroy(); + client.unref(); + } + } + // resolves if ready, rejects otherwise + isDebuggerReady() { + return new Promise((resolve, reject) => { + const client = net.createConnection(9222); + client.once('error', err => { + this.cleanup(client); + reject(err); + }); + client.once('connect', _ => { + this.cleanup(client); + resolve(); + }); + }); + } + // resolves when debugger is ready, rejects after 10 polls + waitUntilReady() { + const launcher = this; + return new Promise((resolve, reject) => { + let retries = 0; + (function poll() { + const green = '\x1B[32m'; + const reset = '\x1B[0m'; + if (retries === 0) { + process.stdout.write('Waiting for browser.'); + } + retries++; + process.stdout.write('..'); + launcher + .isDebuggerReady() + .then(() => { + process.stdout.write(`${green}✓${reset}\n`); + resolve(); + }) + .catch(err => { + if (retries > 10) { + process.stdout.write('\n'); + return reject(err); + } + delay(launcher.pollInterval).then(poll); + }); + })(); + }); + } + kill() { + return new Promise(resolve => { + if (this.chrome) { + this.chrome.on('close', () => { + this.destroyTmp(); + resolve(); + }); + console.log('Killing all Chrome Instances'); + this.chrome.kill(); + if (process.platform === 'win32') { + spawnSync(`taskkill /pid ${this.chrome.pid} /T /F`); + } + } + else { + // fail silently as we did not start chrome + resolve(); + } + }); + } + destroyTmp() { + if (this.TMP_PROFILE_DIR) { + console.log(`Removing ${this.TMP_PROFILE_DIR}`); + rimraf.sync(this.TMP_PROFILE_DIR); + } + } +} +exports.ChromeLauncher = ChromeLauncher; +; +function defaults(val, def) { + return typeof val === 'undefined' ? def : val; +} +function delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); +} +function unixTmpDir() { + return execSync('mktemp -d -t lighthouse.XXXXXXX').toString().trim(); +} +function win32TmpDir() { + const winTmpPath = process.env.TEMP || + process.env.TMP || + (process.env.SystemRoot || process.env.windir) + '\\temp'; + const randomNumber = Math.floor(Math.random() * 9e7 + 1e7); + const tmpdir = path.join(winTmpPath, 'lighthouse.' + randomNumber); + mkdirp.sync(tmpdir); + return tmpdir; +} +//# sourceMappingURL=chrome-launcher.js.map diff --git a/lighthouse-cli/js/chrome-launcher.js.map b/lighthouse-cli/js/chrome-launcher.js.map new file mode 100644 index 000000000000..6c3365fa0c97 --- /dev/null +++ b/lighthouse-cli/js/chrome-launcher.js.map @@ -0,0 +1 @@ +{"version":3,"file":"chrome-launcher.js","sourceRoot":"","sources":["../chrome-launcher.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lighthouse-cli/js/index.js b/lighthouse-cli/js/index.js new file mode 100644 index 000000000000..99218f98d6f7 --- /dev/null +++ b/lighthouse-cli/js/index.js @@ -0,0 +1,220 @@ +/// +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; +const environment = require('../../lighthouse-core/lib/environment.js'); +if (!environment.checkNodeCompatibility()) { + console.warn('Compatibility error', 'Lighthouse requires node 5+ or 4 with --harmony'); + process.exit(1); +} +const path = require('path'); +const yargs = require('yargs'); +const Printer = require('./printer'); +const lighthouse = require('../../lighthouse-core'); +const assetSaver = require('../../lighthouse-core/lib/asset-saver.js'); +const chrome_launcher_1 = require('./chrome-launcher'); +const perfOnlyConfig = require('../../lighthouse-core/config/perf.json'); +const cli = yargs + .help('help') + .version(() => require('../package').version) + .showHelpOnFail(false, 'Specify --help for available options') + .usage('$0 url') + .group([ + 'verbose', + 'quiet' +], 'Logging:') + .describe({ + verbose: 'Displays verbose logging', + quiet: 'Displays no progress or debug logs' +}) + .group([ + 'mobile', + 'save-assets', + 'save-artifacts', + 'list-all-audits', + 'list-trace-categories', + 'config-path', + 'perf' +], 'Configuration:') + .describe({ + 'mobile': 'Emulates a Nexus 5X', + 'save-assets': 'Save the trace contents & screenshots to disk', + 'save-artifacts': 'Save all gathered artifacts to disk', + 'list-all-audits': 'Prints a list of all available audits and exits', + 'list-trace-categories': 'Prints a list of all required trace categories and exits', + 'config-path': 'The path to the config JSON.', + 'perf': 'Use a performance-test-only configuration', + 'skip-autolaunch': 'Skip autolaunch of chrome when accessing port 9222 fails', + 'select-chrome': 'Choose chrome location to use when multiple installations are found', +}) + .group([ + 'output', + 'output-path' +], 'Output:') + .describe({ + 'output': 'Reporter for the results', + 'output-path': `The file path to output the results +Example: --output-path=./lighthouse-results.html` +}) + .boolean([ + 'save-assets', + 'save-artifacts', + 'list-all-audits', + 'list-trace-categories', + 'perf', + 'skip-autolaunch', + 'select-chrome', + 'verbose', + 'quiet', + 'help' +]) + .choices('output', Object.keys(Printer.OUTPUT_MODE).map(k => Printer.OUTPUT_MODE[k])) + .default('mobile', true) + .default('output', Printer.OUTPUT_MODE.pretty) + .default('output-path', 'stdout') + .check(argv => { + // Make sure lighthouse has been passed a url, or at least one of --list-all-audits + // or --list-trace-categories. If not, stop the program and ask for a url + if (!argv.listAllAudits && !argv.listTraceCategories && argv._.length === 0) { + throw new Error('Please provide a url'); + } + return true; +}) + .argv; +if (cli.listAllAudits) { + const audits = lighthouse + .getAuditList() + .map(i => { + return i.replace(/\.js$/, ''); + }); + process.stdout.write(JSON.stringify({ audits })); + process.exit(0); +} +if (cli.listTraceCategories) { + const traceCategories = lighthouse.traceCategories; + process.stdout.write(JSON.stringify({ traceCategories })); + process.exit(0); +} +const urls = cli._; +const outputMode = cli.output; +const outputPath = cli['output-path']; +const flags = cli; +let config = null; +if (cli.configPath) { + // Resolve the config file path relative to where cli was called. + cli.configPath = path.resolve(process.cwd(), cli.configPath); + config = require(cli.configPath); +} +else if (cli.perf) { + config = perfOnlyConfig; +} +// set logging preferences +flags.logLevel = 'info'; +if (cli.verbose) { + flags.logLevel = 'verbose'; +} +else if (cli.quiet) { + flags.logLevel = 'error'; +} +const cleanup = { + fns: [], + register(fn) { + this.fns.push(fn); + }, + doCleanup() { + return Promise.all(this.fns.map(c => c())); + } +}; +function launchChromeAndRun(addresses) { + const launcher = new chrome_launcher_1.ChromeLauncher({ + autoSelectChrome: !cli.selectChrome, + }); + cleanup.register(() => launcher.kill()); + return launcher + .isDebuggerReady() + .catch(() => { + console.log('Launching Chrome...'); + return launcher.run(); + }) + .then(() => lighthouseRun(addresses)) + .then(() => launcher.kill()); +} +function lighthouseRun(addresses) { + // Process URLs once at a time + const address = addresses.shift(); + if (!address) { + return; + } + return lighthouse(address, flags, config) + .then(results => Printer.write(results, outputMode, outputPath)) + .then(results => { + if (outputMode !== 'html') { + const filename = './' + assetSaver.getFilenamePrefix({ url: address }) + '.html'; + Printer.write(results, 'html', filename); + } + return lighthouseRun(addresses); + }); +} +function showConnectionError() { + console.error('Unable to connect to Chrome'); + console.error('If you\'re using lighthouse with --skip-autolaunch, ' + + 'make sure you\'re running some other Chrome with a debugger.'); + process.exit(1); +} +function showRuntimeError(err) { + console.error('Runtime error encountered:', err); + console.error(err.stack); + process.exit(1); +} +function handleError(err) { + if (err.code === 'ECONNREFUSED') { + showConnectionError(); + } + else { + showRuntimeError(err); + } +} +function run() { + if (cli.skipAutolaunch) { + lighthouseRun(urls).catch(handleError); + } + else { + // because you can't cancel a promise yet + const SIGINT = 'SIGINT'; + const isSigint = new Promise((resolve, reject) => { + process.on('SIGINT', () => reject(SIGINT)); + }); + Promise + .race([launchChromeAndRun(urls), isSigint]) + .catch(maybeSigint => { + if (maybeSigint === SIGINT) { + return cleanup + .doCleanup() + .then(() => process.exit(130)) + .catch(err => { + console.error(err); + console.error(err.stack); + process.exit(130); + }); + } + return handleError(maybeSigint); + }); + } +} +// kick off a lighthouse run +run(); +//# sourceMappingURL=index.js.map diff --git a/lighthouse-cli/js/index.js.map b/lighthouse-cli/js/index.js.map new file mode 100644 index 000000000000..e8215910998a --- /dev/null +++ b/lighthouse-cli/js/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lighthouse-cli/js/printer.js b/lighthouse-cli/js/printer.js new file mode 100644 index 000000000000..477ed7e2f4b4 --- /dev/null +++ b/lighthouse-cli/js/printer.js @@ -0,0 +1,184 @@ +/// +/** + * @license + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; +; +const fs = require('fs'); +const ReportGenerator = require('../../lighthouse-core/report/report-generator'); +const Formatter = require('../../lighthouse-core/formatters/formatter'); +const log = require('../../lighthouse-core/lib/log'); +/** + * An enumeration of acceptable output modes: + *
    + *
  • 'pretty': Pretty print the results
  • + *
  • 'json': JSON formatted results
  • + *
  • 'html': An HTML report
  • + *
+ * @enum {string} + */ +const OUTPUT_MODE = { + pretty: 'pretty', + json: 'json', + html: 'html' +}; +exports.OUTPUT_MODE = OUTPUT_MODE; +/** + * Verify output mode. + */ +function checkOutputMode(mode) { + if (!OUTPUT_MODE.hasOwnProperty(mode)) { + log.warn('Printer', `Unknown output mode ${mode}; using pretty`); + return OUTPUT_MODE.pretty; + } + return OUTPUT_MODE[mode]; +} +exports.checkOutputMode = checkOutputMode; +/** + * Verify output path to use, either stdout or a file path. + */ +function checkOutputPath(path) { + if (!path) { + log.warn('Printer', 'No output path set; using stdout'); + return 'stdout'; + } + return path; +} +exports.checkOutputPath = checkOutputPath; +function formatScore(score, suffix) { + // Until we only support node 6 we can not use default args. + suffix = suffix || ''; + const green = '\x1B[32m'; + const red = '\x1B[31m'; + const yellow = '\x1b[33m'; + const purple = '\x1b[95m'; + const reset = '\x1B[0m'; + if (typeof score === 'boolean') { + const check = `${green}✓${reset}`; + const fail = `${red}✘${reset}`; + return score ? check : fail; + } + if (typeof score !== 'number') { + return `${purple}${score}${reset}`; + } + let colorChoice = red; + if (score > 45) { + colorChoice = yellow; + } + if (score > 75) { + colorChoice = green; + } + return `${colorChoice}${score}${suffix}${reset}`; +} +/** + * Creates the results output in a format based on the `mode`. + */ +function createOutput(results, outputMode) { + const reportGenerator = new ReportGenerator(); + // HTML report. + if (outputMode === 'html') { + return reportGenerator.generateHTML(results, { inline: true }); + } + // JSON report. + if (outputMode === 'json') { + return JSON.stringify(results, null, 2); + } + // Pretty printed. + const bold = '\x1b[1m'; + const reset = '\x1B[0m'; + let output = `\n\n${bold}Lighthouse results:${reset} ${results.url}\n\n`; + results.aggregations.forEach(aggregation => { + output += `▫ ${bold}${aggregation.name}${reset}\n\n`; + aggregation.score.forEach(item => { + let score = (item.overall * 100).toFixed(0); + if (item.name) { + output += `${bold}${item.name}${reset}: ${formatScore(Number(score), '%')}\n`; + } + item.subItems.forEach(subitem => { + // Get audit object from inside of results.audits under name subitem. + // Coming soon events are not located inside of results.audits. + subitem = results.audits[subitem] || subitem; + if (subitem.comingSoon) { + return; + } + let lineItem = ` ── ${formatScore(subitem.score)} ${subitem.description}`; + if (subitem.displayValue) { + lineItem += ` (${bold}${subitem.displayValue}${reset})`; + } + output += `${lineItem}\n`; + if (subitem.debugString) { + output += ` ${subitem.debugString}\n`; + } + if (subitem.extendedInfo && subitem.extendedInfo.value) { + const formatter = Formatter.getByName(subitem.extendedInfo.formatter).getFormatter('pretty'); + output += `${formatter(subitem.extendedInfo.value)}`; + } + }); + output += '\n'; + }); + }); + return output; +} +exports.createOutput = createOutput; +/* istanbul ignore next */ +/** + * Writes the output to stdout. + */ +function writeToStdout(output) { + return new Promise((resolve, reject) => { + // small delay to avoid race with debug() logs + setTimeout(_ => { + process.stdout.write(`${output}\n`); + resolve(); + }, 50); + }); +} +/** + * Writes the output to a file. + */ +function writeFile(filePath, output, outputMode) { + return new Promise((resolve, reject) => { + // TODO: make this mkdir to the filePath. + fs.writeFile(filePath, output, 'utf8', err => { + if (err) { + return reject(err); + } + log.log('Printer', `${outputMode} output written to ${filePath}`); + resolve(); + }); + }); +} +/** + * Writes the results. + */ +function write(results, mode, path) { + return new Promise((resolve, reject) => { + const outputMode = checkOutputMode(mode); + const outputPath = checkOutputPath(path); + const output = createOutput(results, outputMode); + // Testing stdout is out of scope, and doesn't really achieve much besides testing Node, + // so we will skip this chunk of the code. + /* istanbul ignore if */ + if (outputPath === 'stdout') { + return writeToStdout(output).then(_ => resolve(results)); + } + return writeFile(outputPath, output, outputMode).then(_ => { + resolve(results); + }).catch(err => reject(err)); + }); +} +exports.write = write; +//# sourceMappingURL=printer.js.map diff --git a/lighthouse-cli/js/printer.js.map b/lighthouse-cli/js/printer.js.map new file mode 100644 index 000000000000..9e2cbd507c98 --- /dev/null +++ b/lighthouse-cli/js/printer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"printer.js","sourceRoot":"","sources":["../printer.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lighthouse-cli/jsconfig.json b/lighthouse-cli/jsconfig.json new file mode 100644 index 000000000000..3989d9323e9e --- /dev/null +++ b/lighthouse-cli/jsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES6", + "sourceMap": true, + "outDir": "outagain" + }, + "exclude": [ + "../../node_modules", + "../node_modules", + "node_modules", + "typings", + "scripts", + "out", + "outagain", + "lighthouse-core" + ] +} diff --git a/lighthouse-cli/printer.ts b/lighthouse-cli/printer.ts deleted file mode 100644 index 5504e7409fbf..000000000000 --- a/lighthouse-cli/printer.ts +++ /dev/null @@ -1,226 +0,0 @@ -/// - -/** - * @license - * Copyright 2016 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -export type Mode = 'pretty' | 'json' | 'html'; -export interface Results { - url: string; - aggregations: any[]; - audits: Object; -}; - -const fs = require('fs'); -const ReportGenerator = require('../../lighthouse-core/report/report-generator'); -const Formatter = require('../../lighthouse-core/formatters/formatter'); -const log = require('../../lighthouse-core/lib/log'); - -/** - * An enumeration of acceptable output modes: - *
    - *
  • 'pretty': Pretty print the results
  • - *
  • 'json': JSON formatted results
  • - *
  • 'html': An HTML report
  • - *
- * @enum {string} - */ -const OUTPUT_MODE = { - pretty: 'pretty', - json: 'json', - html: 'html' -}; - -/** - * Verify output mode. - */ -function checkOutputMode(mode: string): Mode { - if (!OUTPUT_MODE.hasOwnProperty(mode)) { - log.warn('Printer', `Unknown output mode ${mode}; using pretty`); - return OUTPUT_MODE.pretty as Mode; - } - - return OUTPUT_MODE[mode]; -} - -/** - * Verify output path to use, either stdout or a file path. - */ -function checkOutputPath(path: string): string { - if (!path) { - log.warn('Printer', 'No output path set; using stdout'); - return 'stdout'; - } - - return path; -} - -function formatScore(score, suffix?: string) { - // Until we only support node 6 we can not use default args. - suffix = suffix || ''; - - const green = '\x1B[32m'; - const red = '\x1B[31m'; - const yellow = '\x1b[33m'; - const purple = '\x1b[95m'; - const reset = '\x1B[0m'; - - if (typeof score === 'boolean') { - const check = `${green}✓${reset}`; - const fail = `${red}✘${reset}`; - return score ? check : fail; - } - if (typeof score !== 'number') { - return `${purple}${score}${reset}`; - } - let colorChoice = red; - if (score > 45) { - colorChoice = yellow; - } - if (score > 75) { - colorChoice = green; - } - return `${colorChoice}${score}${suffix}${reset}`; -} - -/** - * Creates the results output in a format based on the `mode`. - */ -function createOutput(results: Results, outputMode: Mode): string { - const reportGenerator = new ReportGenerator(); - - // HTML report. - if (outputMode === 'html') { - return reportGenerator.generateHTML(results, {inline: true}); - } - - // JSON report. - if (outputMode === 'json') { - return JSON.stringify(results, null, 2); - } - - // Pretty printed. - const bold = '\x1b[1m'; - const reset = '\x1B[0m'; - let output = `\n\n${bold}Lighthouse results:${reset} ${results.url}\n\n`; - - results.aggregations.forEach(aggregation => { - output += `▫ ${bold}${aggregation.name}${reset}\n\n`; - - aggregation.score.forEach(item => { - let score = (item.overall * 100).toFixed(0); - - if (item.name) { - output += `${bold}${item.name}${reset}: ${formatScore(Number(score), '%')}\n`; - } - - item.subItems.forEach(subitem => { - // Get audit object from inside of results.audits under name subitem. - // Coming soon events are not located inside of results.audits. - subitem = results.audits[subitem] || subitem; - - if (subitem.comingSoon) { - return; - } - - let lineItem = ` ── ${formatScore(subitem.score)} ${subitem.description}`; - if (subitem.displayValue) { - lineItem += ` (${bold}${subitem.displayValue}${reset})`; - } - output += `${lineItem}\n`; - if (subitem.debugString) { - output += ` ${subitem.debugString}\n`; - } - - if (subitem.extendedInfo && subitem.extendedInfo.value) { - const formatter = - Formatter.getByName(subitem.extendedInfo.formatter).getFormatter('pretty'); - output += `${formatter(subitem.extendedInfo.value)}`; - } - }); - - output += '\n'; - }); - }); - - return output; -} - -/* istanbul ignore next */ -/** - * Writes the output to stdout. - */ -function writeToStdout(output: string): Promise { - return new Promise((resolve, reject) => { - // small delay to avoid race with debug() logs - setTimeout(_ => { - process.stdout.write(`${output}\n`); - resolve(); - }, 50); - }); -} - -/** - * Writes the output to a file. - */ -function writeFile( - filePath: string, - output: string, - outputMode: Mode): Promise { - return new Promise((resolve, reject) => { - // TODO: make this mkdir to the filePath. - fs.writeFile(filePath, output, 'utf8', err => { - if (err) { - return reject(err); - } - log.log('Printer', `${outputMode} output written to ${filePath}`); - resolve(); - }); - }); -} - -/** - * Writes the results. - */ -function write(results: Results, mode: Mode, path: string): Promise { - return new Promise((resolve, reject) => { - const outputMode = checkOutputMode(mode); - const outputPath = checkOutputPath(path); - - const output = createOutput(results, outputMode); - - // Testing stdout is out of scope, and doesn't really achieve much besides testing Node, - // so we will skip this chunk of the code. - /* istanbul ignore if */ - if (outputPath === 'stdout') { - return writeToStdout(output).then(_ => resolve(results)); - } - - return writeFile(outputPath, output, outputMode).then(_ => { - resolve(results); - }).catch(err => reject(err)); - }); -} - -export { - checkOutputMode, - checkOutputPath, - createOutput, - write, - OUTPUT_MODE -} diff --git a/lighthouse-cli/test/cli/printer-test.js b/lighthouse-cli/test/cli/printer-test.js index aef39ef602c5..76c24fd7226f 100644 --- a/lighthouse-cli/test/cli/printer-test.js +++ b/lighthouse-cli/test/cli/printer-test.js @@ -16,7 +16,7 @@ 'use strict'; -const Printer = require('../../out/printer.js'); +const Printer = require('../../js/printer.js'); const assert = require('assert'); const fs = require('fs'); const sampleResults = require('../fixtures/sample.json'); diff --git a/lighthouse-cli/tsconfig.json b/lighthouse-cli/tsconfig.json deleted file mode 100644 index b192ffbf00b6..000000000000 --- a/lighthouse-cli/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - - "noImplicitAny": false, - "sourceMap": true, - "declaration": true, - "declarationDir": "dist", - "outDir": "out" - }, - "exclude": [ - "node_modules", - "typings" - ], - "include": [ - "*.ts" - ] - - -}