UNPKG

anta

Version:

CLI tool and lib to gather app audits via [Lighthouse](https://github.com/GoogleChrome/lighthouse/).

255 lines 21.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const chrome_launcher_1 = require("chrome-launcher"); const lighthouse = require('lighthouse'); const path = require('path'); const metrics = require('./metrics'); const expectations = require('./expectations'); const lhConfig = require('./lh-config'); const realDevice = require('./real-device'); const MAX_LIGHTHOUSE_TRIES = 2; const getScore = (result) => { let score = 0; result.reportCategories.forEach((cate) => { if (cate.name === 'Performance') { score = cate.score; } }); return score; }; class AntA { constructor(urls, opts) { this.urls = urls; this.flags = { runs: 3, view: false, expectations: false, json: false, chromeFlags: [] }; this.flags = Object.assign({}, this.flags, opts ? opts.flags : null); this.runs = this.flags.runs; this.expectations = opts ? opts.expectations : {}; this.tryLighthouseCounter = 0; // normalize path if provided if (this.flags.chromePath) { this.flags.chromePath = path.normalize(this.flags.chromePath); } if (this.flags.expectations) { if (this.expectations) { expectations.validateMetrics(this.expectations); this.expectations = expectations.normalizeMetrics(this.expectations); } else throw new Error('NO_EXPECTATIONS_FOUND'); } if (opts.runEnv === 'alipayApp') { this.runEnv = 'alipayApp'; } } // public api, No arguments start() { return __awaiter(this, void 0, void 0, function* () { let finalResults = []; if (typeof this.urls === 'string') { this.urls = [this.urls]; } // on real device's Alipay APP if (this.runEnv === 'alipayApp') { // 重复设置 url 使之与 flags.runs 设置一样 const urls = []; const resGroupArr = []; this.urls.forEach(item => { resGroupArr.push([]); for (let index = 0; index < this.runs; index++) { urls.push(item); } }); const res = yield realDevice(urls); for (let index = 0; index < res.length; index++) { const single = res[index]; resGroupArr[this.urls.indexOf(single.initialUrl)].push(single); // console.log('res single', single.initialUrl); } // console.log('alipay...', urls, resGroupArr); const newRes = []; resGroupArr.forEach((arr) => { // 多次运行结果,根据分数由高到低排序,只取最高分数返回 newRes.push(arr.sort((a, b) => getScore(b.runs[0]) - getScore(a.runs[0]))[0]); }); return newRes; } // on pc chrome for (let url of this.urls) { const currentUrlMetric = yield this.startInner(url); finalResults.push(currentUrlMetric); } return finalResults; }); } startInner(url) { return __awaiter(this, void 0, void 0, function* () { const runs = Array.apply(null, { length: +this.runs }).map(Number.call, Number); let metricsResults = []; let resultHasExpectationErrors = false; for (let runIndex of runs) { try { const currentMetricResult = yield this.run(url); if (!resultHasExpectationErrors && this.flags.expectations) { resultHasExpectationErrors = this.resultHasExpectationErrors(currentMetricResult); } metricsResults[runIndex] = currentMetricResult; console.log('SUCCESS', 'SUCCESS_RUN', `Run ${runIndex + 1} of ${runs.length} finished successfully.`); } catch (error) { metricsResults[runIndex] = error; console.error('ERROR', 'FAILED_RUN', runIndex, runs.length, error.message); } } const res = metricsResults.filter(r => !(r instanceof Error)); // 多次运行结果,根据分数由高到低排序 let results = { runs: res.sort((a, b) => getScore(b) - getScore(a)) }; if (results.runs.length > 0) { // if (this.runs > 1 && !this.flags.submit) { // results.median = this.findMedianRun(results.runs); // console.log(messages.getMessage('MEDIAN_RUN')); // this.displayOutput(results.median); // } else if (this.flags.submit) { // const sheets = new Sheets(this.sheets, this.clientSecret); // await sheets.appendResults(results.runs); // } } if (resultHasExpectationErrors && this.flags.expectations) { throw new Error('HAS_EXPECTATION_ERRORS'); } return results; }); } resultHasExpectationErrors(metrics) { return metrics.timings.some((timing) => { const expectation = this.expectations[timing.id]; if (!expectation) { return false; } const expectedErrorLimit = expectation.error; return expectedErrorLimit !== undefined && timing.timing >= expectedErrorLimit; }); } run(url) { return __awaiter(this, void 0, void 0, function* () { try { let lhResults; yield this.launchChrome(); if (process.env.CI) { // handling CRI_TIMEOUT issue - https://github.com/GoogleChrome/lighthouse/issues/833 this.tryLighthouseCounter = 0; lhResults = yield this.runLighthouseOnCI(url).then((lhResults) => { // fix for https://github.com/paulirish/pwmetrics/issues/63 return new Promise(resolve => { console.log('WAITING'); setTimeout(_ => { return resolve(lhResults); }, 2000); }); }); } else { // lhResults = await lighthouse(url, this.flags, null); // use lh default config lhResults = yield lighthouse(url, this.flags, lhConfig); } const metricsResults = yield this.recordLighthouseTrace(lhResults); yield this.killLauncher(); return metricsResults; } catch (error) { yield this.killLauncher(); throw error; } }); } killLauncher() { return __awaiter(this, void 0, void 0, function* () { if (typeof this.launcher !== 'undefined') { yield this.launcher.kill(); } }); } runLighthouseOnCI(url) { return __awaiter(this, void 0, void 0, function* () { try { return yield lighthouse(url, this.flags, lhConfig); } catch (error) { if (error.code === 'CRI_TIMEOUT' && this.tryLighthouseCounter <= MAX_LIGHTHOUSE_TRIES) { return yield this.retryLighthouseOnCI(url); } if (this.tryLighthouseCounter > MAX_LIGHTHOUSE_TRIES) { throw new Error('CRI_TIMEOUT_REJECT'); } } }); } retryLighthouseOnCI(url) { return __awaiter(this, void 0, void 0, function* () { this.tryLighthouseCounter++; console.log('CRI_TIMEOUT_RELAUNCH'); try { return yield this.runLighthouseOnCI(url); } catch (error) { console.error(error.message); console.error('CLOSING_CHROME'); yield this.killLauncher(); } }); } launchChrome() { return __awaiter(this, void 0, void 0, function* () { try { console.log('LAUNCHING_CHROME'); this.launcher = yield chrome_launcher_1.launch({ port: this.flags.port, chromeFlags: this.flags.chromeFlags, chromePath: this.flags.chromePath }); this.flags.port = this.launcher.port; return this.launcher; } catch (error) { yield this.killLauncher(); return error; } }); } recordLighthouseTrace(data) { return __awaiter(this, void 0, void 0, function* () { try { const preparedData = metrics.prepareData(data); // if (this.flags.upload) { // const driveResponse = await upload(data, this.clientSecret); // this.view(driveResponse.id); // } // if (!this.flags.submit && this.runs <= 1) { // this.displayOutput(preparedData); // } if (this.flags.expectations) { expectations.checkExpectations(preparedData.timings, this.expectations); } return preparedData; } catch (error) { throw error; } }); } } module.exports = AntA; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBSUEscURBQXlEO0FBRXpELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUN6QyxNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDN0IsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQ3JDLE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBQy9DLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUV4QyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUM7QUFNNUMsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLENBQUM7QUFDL0IsTUFBTSxRQUFRLEdBQUcsQ0FBQyxNQUFzQixFQUFFLEVBQUU7SUFDMUMsSUFBSSxLQUFLLEdBQVcsQ0FBQyxDQUFDO0lBQ3RCLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFTLEVBQUUsRUFBRTtRQUM1QyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDaEMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDckIsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQztBQUNmLENBQUMsQ0FBQztBQUVGO0lBY0UsWUFBbUIsSUFBNEIsRUFBRSxJQUFvQjtRQUFsRCxTQUFJLEdBQUosSUFBSSxDQUF3QjtRQWIvQyxVQUFLLEdBQWlCO1lBQ3BCLElBQUksRUFBRSxDQUFDO1lBQ1AsSUFBSSxFQUFFLEtBQUs7WUFDWCxZQUFZLEVBQUUsS0FBSztZQUNuQixJQUFJLEVBQUUsS0FBSztZQUNYLFdBQVcsRUFBRSxF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