lighthouse
Advanced tools
Comparing version 1.0.2 to 1.0.3
@@ -22,3 +22,2 @@ #!/usr/bin/env node | ||
const yargs = require('yargs'); | ||
const log = require('../lighthouse-core/lib/log.js'); | ||
const semver = require('semver'); | ||
@@ -40,3 +39,2 @@ const Printer = require('./printer'); | ||
.usage('$0 url') | ||
.demand(1, 'Please provide a url') | ||
@@ -104,2 +102,11 @@ // List of options | ||
.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; | ||
@@ -119,5 +126,5 @@ | ||
if (cli.listTraceCategories) { | ||
const categories = lighthouse.traceCategories; | ||
const traceCategories = lighthouse.traceCategories; | ||
process.stdout.write(JSON.stringify({traceCategories: categories})); | ||
process.stdout.write(JSON.stringify({traceCategories})); | ||
process.exit(0); | ||
@@ -132,8 +139,2 @@ } | ||
// If the URL isn't https or localhost complain to the user. | ||
if (url.indexOf('https') !== 0 && url.indexOf('http://localhost') !== 0) { | ||
log.warn('Lighthouse', 'The URL provided should be on HTTPS'); | ||
log.warn('Lighthouse', 'Performance stats will be skewed redirecting from HTTP to HTTPS.'); | ||
} | ||
// set logging preferences | ||
@@ -140,0 +141,0 @@ flags.logLevel = 'info'; |
@@ -47,3 +47,3 @@ /** | ||
if (!OUTPUT_MODE.hasOwnProperty(mode)) { | ||
log.log('warn', `Unknown output mode ${mode}; using pretty`); | ||
log.warn('Printer', `Unknown output mode ${mode}; using pretty`); | ||
return OUTPUT_MODE.pretty; | ||
@@ -61,3 +61,3 @@ } | ||
if (!path) { | ||
log.log('warn', 'No output path set; using stdout'); | ||
log.warn('Printer', 'No output path set; using stdout'); | ||
return 'stdout'; | ||
@@ -153,3 +153,3 @@ } | ||
} | ||
log.info('printer', `${outputMode} output written to ${filePath}`); | ||
log.log('Printer', `${outputMode} output written to ${filePath}`); | ||
resolve(); | ||
@@ -156,0 +156,0 @@ }); |
@@ -24,5 +24,9 @@ /** | ||
describe('CLI Tests', function() { | ||
it('should list all audits and exit immediately after', () => { | ||
it('fails if a url is not provided', () => { | ||
assert.throws(() => childProcess.execSync('node lighthouse-cli/index.js')); | ||
}); | ||
it('should list all audits without a url and exit immediately after', () => { | ||
const output = JSON.parse(childProcess.execSync( | ||
'node lighthouse-cli/index.js https://example.com --list-all-audits').toString()); | ||
'node lighthouse-cli/index.js --list-all-audits').toString()); | ||
assert(Array.isArray(output.audits)); | ||
@@ -32,5 +36,5 @@ assert(output.audits.length > 0); | ||
it('should print trace categories list-trace-categories flag and exit immediately after', () => { | ||
it('accepts just the list-trace-categories flag and exit immediately after', () => { | ||
const output = JSON.parse(childProcess.execSync( | ||
'node lighthouse-cli/index.js https://example.com --list-trace-categories').toString()); | ||
'node lighthouse-cli/index.js --list-trace-categories').toString()); | ||
assert(Array.isArray(output.traceCategories)); | ||
@@ -37,0 +41,0 @@ assert(output.traceCategories.length > 0); |
@@ -40,3 +40,4 @@ /** | ||
return HTTPS.generateAuditResult({ | ||
value: !!artifacts.HTTPS | ||
value: artifacts.HTTPS.value, | ||
debugString: artifacts.HTTPS.debugString | ||
}); | ||
@@ -43,0 +44,0 @@ } |
@@ -21,2 +21,17 @@ /** | ||
/** | ||
* The relationship between these root modules: | ||
* | ||
* core.js - the gathering, auditing and aggregation | ||
* runner.js - the shared handler (for both module & extension) that needs to be given a driver, | ||
* and sets up the core to do its job | ||
* index.js - the require('lighthouse') hook for Node modules (including the CLI) | ||
* | ||
* lighthouse-cli \ | ||
* -- index.js \ | ||
* ----- runner.js ----> core.js [Gather / Audit / Aggregate] | ||
* lighthouse-extension / | ||
* | ||
*/ | ||
class Core { | ||
@@ -75,4 +90,4 @@ static audit(artifacts, audits) { | ||
if (rejected.length) { | ||
log.log('info', 'Running these audits:', `${filteredAudits.join(', ')}`); | ||
log.log('info', 'Skipping these audits:', `${rejected.join(', ')}`); | ||
log.log('Running these audits:', `${filteredAudits.join(', ')}`); | ||
log.log('Skipping these audits:', `${rejected.join(', ')}`); | ||
} | ||
@@ -79,0 +94,0 @@ |
@@ -87,3 +87,3 @@ /** | ||
// log events received | ||
this._chrome.on('event', req => _log('verbose', '<=', req)); | ||
this._chrome.on('event', req => _log('<=', req, 'verbose')); | ||
} | ||
@@ -101,3 +101,3 @@ | ||
// log event listeners being bound | ||
_log('info', 'listen for event =>', {method: eventName}); | ||
_log('listen for event =>', {method: eventName}); | ||
this._chrome.on(eventName, cb); | ||
@@ -117,3 +117,3 @@ } | ||
// log event listeners being bound | ||
_log('info', 'listen once for event =>', {method: eventName}); | ||
_log('listen once for event =>', {method: eventName}); | ||
this._chrome.once(eventName, cb); | ||
@@ -147,10 +147,10 @@ } | ||
return new Promise((resolve, reject) => { | ||
_log('http', 'method => browser', {method: command, params: params}); | ||
_log('method => browser', {method: command, params: params}); | ||
this._chrome.send(command, params, (err, result) => { | ||
if (err) { | ||
_log('error', 'method <= browser', {method: command, params: result}); | ||
_log('method <= browser ERR', {method: command, params: result}, 'error'); | ||
return reject(result); | ||
} | ||
_log('http', 'method <= browser OK', {method: command, params: result}); | ||
_log('method <= browser OK', {method: command, params: result}); | ||
resolve(result); | ||
@@ -162,9 +162,9 @@ }); | ||
function _log(level, prefix, data) { | ||
function _log(prefix, data, level) { | ||
const columns = (typeof process === 'undefined') ? Infinity : process.stdout.columns; | ||
const maxLength = columns - data.method.length - prefix.length - 7; | ||
const maxLength = columns - data.method.length - prefix.length - 18; | ||
const snippet = data.params ? JSON.stringify(data.params).substr(0, maxLength) : ''; | ||
log.log(level, prefix, data.method, snippet); | ||
log[level ? level : 'log'](prefix, data.method, snippet); | ||
} | ||
module.exports = CriDriver; |
@@ -126,7 +126,7 @@ /** | ||
if (!this._tabId) { | ||
log.log('error', 'No tabId set for sendCommand'); | ||
log.error('No tabId set for sendCommand'); | ||
} | ||
chrome.debugger.sendCommand({tabId: this._tabId}, command, params, result => { | ||
if (chrome.runtime.lastError) { | ||
log.log('error', 'method <= browser', command, result); | ||
log.error('method <= browser', command, result); | ||
return reject(chrome.runtime.lastError); | ||
@@ -133,0 +133,0 @@ } |
@@ -39,2 +39,9 @@ /** | ||
} | ||
// Treat favicons as non-critical resources | ||
if (request.mimeType === 'image/x-icon' || | ||
(request.parsedURL && request.parsedURL.lastPathComponent === 'favicon.ico')) { | ||
return false; | ||
} | ||
return includes(['VeryHigh', 'High', 'Medium'], request.priority()); | ||
@@ -41,0 +48,0 @@ } |
@@ -211,7 +211,9 @@ /** | ||
const hostname = parsedResourceURL.hostname; | ||
let file = parsedResourceURL.path | ||
// Remove any query strings. | ||
.replace(/\?.*/, '') | ||
// Grab the last two parts of the path. | ||
// Handle 'about:*' URLs specially since they have no path. | ||
let file = parsedResourceURL.protocol === 'about:' ? parsedResourceURL.href : | ||
// Otherwise, remove any query strings from the path. | ||
parsedResourceURL.path.replace(/\?.*/, '') | ||
// And grab the last two parts. | ||
.split('/').slice(-2).join('/'); | ||
if (file.length > MAX_FILENAME_LENGTH) { | ||
@@ -218,0 +220,0 @@ file = file.slice(0, MAX_FILENAME_LENGTH) + '...'; |
@@ -80,3 +80,3 @@ /** | ||
fs.writeFileSync(artifactsFilename, stringify(artifacts)); | ||
log.log('info', 'artifacts file saved to disk', artifactsFilename); | ||
log.log('artifacts file saved to disk', artifactsFilename); | ||
} | ||
@@ -95,7 +95,7 @@ | ||
fs.writeFileSync(traceFilename + '.trace.json', stringify(assets.traceData, null, 2)); | ||
log.log('info', 'trace file saved to disk', traceFilename); | ||
log.log('trace file saved to disk', traceFilename); | ||
const screenshotsFilename = getFilenamePrefix(options); | ||
fs.writeFileSync(screenshotsFilename + '.screenshots.html', assets.html); | ||
log.log('info', 'screenshots saved to disk', screenshotsFilename); | ||
log.log('screenshots saved to disk', screenshotsFilename); | ||
} | ||
@@ -102,0 +102,0 @@ |
@@ -19,7 +19,37 @@ /** | ||
const npmlog = require('npmlog'); | ||
const debug = require('debug'); | ||
// Use `npmlog` in node, `console` in browser and electron. | ||
const isNode = !!process && !process.browser && !process.versions.electron; | ||
function setLevel(level) { | ||
if (level === 'verbose') { | ||
debug.enable('*'); | ||
} else if (level === 'error') { | ||
debug.enable('*:error'); | ||
} else { | ||
debug.enable('*, -*:verbose'); | ||
} | ||
} | ||
module.exports = isNode ? npmlog : console; | ||
const loggers = {}; | ||
function _log(title, logargs) { | ||
const args = [...logargs].slice(1); | ||
if (!loggers[title]) { | ||
loggers[title] = debug(title); | ||
} | ||
return loggers[title](...args); | ||
} | ||
module.exports = { | ||
setLevel, | ||
log(title) { | ||
return _log(title, arguments); | ||
}, | ||
warn(title) { | ||
return _log(`${title}:warn`, arguments); | ||
}, | ||
error(title) { | ||
return _log(`${title}:error`, arguments); | ||
}, | ||
verbose(title) { | ||
return _log(`${title}:verbose`, arguments); | ||
} | ||
}; |
@@ -128,9 +128,18 @@ /** | ||
* durations. | ||
* If one of the durations overlaps the end of the window, the full | ||
* duration should be in the duration array, but the length not included | ||
* within the window should be given as `clippedLength`. For instance, if a | ||
* 50ms duration occurs 10ms before the end of the window, `50` should be in | ||
* the `durations` array, and `clippedLength` should be set to 40. | ||
* @see https://docs.google.com/document/d/18gvP-CBA2BiBpi3Rz1I1ISciKGhniTSZ9TY0XCnXS7E/preview | ||
* @param {!Array<number>} durations Array of durations, sorted in ascending order. | ||
* @param {number} totalTime Total time (in ms) of interval containing durations. | ||
* @param {!Array<number>} percentiles Array of percentiles of interest, in ascending order. | ||
* @param {number=} clippedLength Optional length clipped from a duration overlapping end of window. Default of 0. | ||
* @return {!Array<{percentile: number, time: number}>} | ||
* @private | ||
*/ | ||
static _riskPercentiles(durations, totalTime, percentiles) { | ||
static _riskPercentiles(durations, totalTime, percentiles, clippedLength) { | ||
clippedLength = clippedLength || 0; | ||
let busyTime = 0; | ||
@@ -140,2 +149,3 @@ for (let i = 0; i < durations.length; i++) { | ||
} | ||
busyTime -= clippedLength; | ||
@@ -146,5 +156,11 @@ // Start with idle time already complete. | ||
let cdfTime = completedTime; | ||
let remainingCount = durations.length + 1; | ||
const results = []; | ||
let durationIndex = -1; | ||
let remainingCount = durations.length + 1; | ||
if (clippedLength > 0) { | ||
// If there was a clipped duration, one less in count since one hasn't started yet. | ||
remainingCount--; | ||
} | ||
// Find percentiles of interest, in order. | ||
@@ -155,9 +171,16 @@ for (let percentile of percentiles) { | ||
const percentileTime = percentile * totalTime; | ||
while (cdfTime < percentileTime && remainingCount > 1) { | ||
while (cdfTime < percentileTime && durationIndex < durations.length) { | ||
completedTime += duration; | ||
remainingCount--; | ||
duration = durations[durations.length - remainingCount]; | ||
remainingCount -= (duration < 0 ? -1 : 1); | ||
if (clippedLength > 0 && clippedLength < durations[durationIndex + 1]) { | ||
duration = -clippedLength; | ||
clippedLength = 0; | ||
} else { | ||
durationIndex++; | ||
duration = durations[durationIndex]; | ||
} | ||
// Calculate value of CDF (multiplied by totalTime) for the end of this duration. | ||
cdfTime = completedTime + duration * remainingCount; | ||
cdfTime = completedTime + Math.abs(duration) * remainingCount; | ||
} | ||
@@ -178,2 +201,3 @@ | ||
* selected percentiles within a window of the main thread. | ||
* @see https://docs.google.com/document/d/18gvP-CBA2BiBpi3Rz1I1ISciKGhniTSZ9TY0XCnXS7E/preview | ||
* @param {!traceviewer.Model} model | ||
@@ -191,5 +215,8 @@ * @param {!Array<!Object>} trace | ||
const totalTime = endTime - startTime; | ||
if (percentiles) { | ||
percentiles.sort((a, b) => a - b); | ||
} else { | ||
percentiles = [0.5, 0.75, 0.9, 0.99, 1]; | ||
} | ||
percentiles = percentiles || [0.5, 0.75, 0.9, 0.99, 1]; | ||
// Find the main thread. | ||
@@ -204,2 +231,3 @@ const startEvent = trace.find(event => { | ||
const durations = []; | ||
let clippedLength = 0; | ||
mainThread.sliceGroup.topLevelSlices.forEach(slice => { | ||
@@ -211,3 +239,16 @@ // Discard slices outside range. | ||
durations.push(slice.duration); | ||
// Clip any at edges of range. | ||
let duration = slice.duration; | ||
let sliceStart = slice.start; | ||
if (sliceStart < startTime) { | ||
// Any part of task before window can be discarded. | ||
sliceStart = startTime; | ||
duration = slice.end - sliceStart; | ||
} | ||
if (slice.end > endTime) { | ||
// Any part of task after window must be clipped but accounted for. | ||
clippedLength = duration - (endTime - sliceStart); | ||
} | ||
durations.push(duration); | ||
}); | ||
@@ -217,3 +258,3 @@ durations.sort((a, b) => a - b); | ||
// Actual calculation of percentiles done in _riskPercentiles. | ||
return TraceProcessor._riskPercentiles(durations, totalTime, percentiles); | ||
return TraceProcessor._riskPercentiles(durations, totalTime, percentiles, clippedLength); | ||
} | ||
@@ -220,0 +261,0 @@ |
@@ -5,3 +5,3 @@ { | ||
"description": "Lighthouse core", | ||
"main": "./module/index.js", | ||
"main": "./index.js", | ||
"engines": { | ||
@@ -34,3 +34,4 @@ "node": ">=5" | ||
"chrome-remote-interface": "^0.11.0", | ||
"devtools-timeline-model": "1.1.4", | ||
"debug": "^2.2.0", | ||
"devtools-timeline-model": "1.1.6", | ||
"gl-matrix": "2.3.2", | ||
@@ -40,5 +41,4 @@ "handlebars": "^4.0.5", | ||
"jszip": "2.6.0", | ||
"npmlog": "^2.0.3", | ||
"semver": ">=4.3.3", | ||
"speedline": "^0.1.2" | ||
"speedline": "0.2.2" | ||
}, | ||
@@ -45,0 +45,0 @@ "devDependencies": { |
@@ -16,23 +16,30 @@ /** | ||
*/ | ||
'use strict'; | ||
const Audit = require('../../audits/is-on-https.js'); | ||
const assert = require('assert'); | ||
/* global describe, it*/ | ||
/* eslint-env mocha */ | ||
describe('Security: HTTPS audit', () => { | ||
it('fails when no input present', () => { | ||
return assert.equal(Audit.audit({}).value, false); | ||
}); | ||
it('fails when not on HTTPS', () => { | ||
return assert.equal(Audit.audit({ | ||
HTTPS: false | ||
}).value, false); | ||
const debugString = 'Error string'; | ||
const result = Audit.audit({ | ||
HTTPS: { | ||
value: false, | ||
debugString | ||
} | ||
}); | ||
assert.strictEqual(result.value, false); | ||
assert.strictEqual(result.debugString, debugString); | ||
}); | ||
it('passes when on HTTPS', () => { | ||
return assert.equal(Audit.audit({ | ||
HTTPS: true | ||
}).value, true); | ||
const result = Audit.audit({ | ||
HTTPS: { | ||
value: true | ||
} | ||
}); | ||
assert.strictEqual(result.value, true); | ||
}); | ||
}); |
@@ -24,3 +24,7 @@ /** | ||
return Core | ||
.audit([{}], ['is-on-https']) | ||
.audit({ | ||
HTTPS: { | ||
value: false | ||
} | ||
}, ['is-on-https']) | ||
.then(modifiedResults => { | ||
@@ -27,0 +31,0 @@ assert.ok(Array.isArray(modifiedResults)); |
@@ -290,2 +290,23 @@ /** | ||
it('discards favicons as non-critical', () => { | ||
const networkRecords = mockTracingData([HIGH, HIGH, HIGH], [[0, 1], [0, 2]]); | ||
// 2nd record is a favicon | ||
networkRecords[1].url = 'https://example.com/favicon.ico'; | ||
networkRecords[1].parsedURL = { | ||
lastPathComponent: 'favicon.ico' | ||
}; | ||
// 3rd record is also a favicon | ||
networkRecords[2].mimeType = 'image/x-icon'; | ||
Gatherer.afterPass(null, {networkRecords}); | ||
const criticalChains = Gatherer.artifact; | ||
assert.deepEqual(criticalChains, { | ||
0: { | ||
request: constructEmptyRequest(), | ||
children: {} | ||
} | ||
}); | ||
}); | ||
it('handles non-existent nodes when building the tree', () => { | ||
@@ -292,0 +313,0 @@ const networkRecords = mockTracingData([HIGH, HIGH], [[0, 1]]); |
@@ -53,2 +53,12 @@ /** | ||
children: {} | ||
}, | ||
3: { | ||
request: { | ||
endTime: 18, | ||
responseReceivedTime: 16, | ||
startTime: 13, | ||
url: 'about:blank', | ||
transferSize: 1 | ||
}, | ||
children: {} | ||
} | ||
@@ -59,3 +69,3 @@ } | ||
/* global describe, it */ | ||
/* eslint-env mocha */ | ||
@@ -79,2 +89,3 @@ describe('CRC Formatter', () => { | ||
assert.ok(truncatedURLRegExp.test(output)); | ||
assert.ok(/about:blank/.test(output)); | ||
}); | ||
@@ -81,0 +92,0 @@ |
@@ -29,3 +29,3 @@ /** | ||
* @param {!Array<number>} percentiles | ||
* @param {!array<number>} times | ||
* @param {!Array<number>} times | ||
* @return {!Array<{percentile: number, time: number}>} | ||
@@ -75,3 +75,72 @@ */ | ||
}); | ||
// Three tasks of one second each, all within a five-second window. | ||
// Mean Queueing Time of 300ms. | ||
it('correctly calculates percentiles of three one-second tasks in a five-second window', () => { | ||
const results = TracingProcessor._riskPercentiles([1000, 1000, 1000], 5000, | ||
defaultPercentiles, 0); | ||
// Round to hundredths to simplify floating point comparison. | ||
results.forEach(result => { | ||
result.time = Number(result.time.toFixed(2)); | ||
}); | ||
const expected = createRiskPercentiles(defaultPercentiles, | ||
[16, 16, 182.67, 599.33, 849.33, 999.33, 1016]); | ||
assert.deepEqual(results, expected); | ||
}); | ||
it('correctly calculates percentiles of tasks with a clipped task', () => { | ||
const results = TracingProcessor._riskPercentiles([10, 20, 50, 60, 90, 100], 300, | ||
defaultPercentiles, 30); | ||
// Round to hundredths to simplify floating point comparison. | ||
results.forEach(result => { | ||
result.time = Number(result.time.toFixed(2)); | ||
}); | ||
const expected = createRiskPercentiles(defaultPercentiles, | ||
[16, 32.25, 53.5, 74.33, 96, 113, 116]); | ||
assert.deepEqual(results, expected); | ||
}); | ||
// One 20 second long task over three five-second windows. | ||
it('correctly calculates percentiles of single task over multiple windows', () => { | ||
// Starts 3 seconds into the first window. Mean Queueing Time = 7600ms. | ||
const TASK_LENGTH = 20000; | ||
let results1 = TracingProcessor._riskPercentiles([TASK_LENGTH], 5000, | ||
defaultPercentiles, TASK_LENGTH - 2000); | ||
const expected1 = createRiskPercentiles(defaultPercentiles, | ||
[16, 16, 16, 18766, 19516, 19966, 20016]); | ||
assert.deepEqual(results1, expected1); | ||
// Starts 2 seconds before and ends 13 seconds after. Mean Queueing Time = 15500ms. | ||
const results2 = TracingProcessor._riskPercentiles([TASK_LENGTH - 2000], 5000, | ||
defaultPercentiles, TASK_LENGTH - 7000); | ||
const expected2 = createRiskPercentiles(defaultPercentiles, | ||
[16, 14266, 15516, 16766, 17516, 17966, 18016]); | ||
assert.deepEqual(results2, expected2); | ||
// Starts 17 seconds before and ends 3 seconds into the window. Mean Queueing Time = 900ms. | ||
const results3 = TracingProcessor._riskPercentiles([TASK_LENGTH - 17000], 5000, | ||
defaultPercentiles, 0); | ||
const expected3 = createRiskPercentiles(defaultPercentiles, | ||
[16, 16, 516, 1766, 2516, 2966, 3016]); | ||
assert.deepEqual(results3, expected3); | ||
}); | ||
it('correctly calculates with a task shorter than the clipped length of another', () => { | ||
const results = TracingProcessor._riskPercentiles([40, 100], 100, | ||
defaultPercentiles, 50); | ||
const expected = createRiskPercentiles(defaultPercentiles, | ||
[16, 31, 56, 91, 106, 115, 116]); | ||
assert.deepEqual(results, expected); | ||
}); | ||
it('correctly calculates with a task clipped completely', () => { | ||
const results = TracingProcessor._riskPercentiles([40, 100], 100, | ||
defaultPercentiles, 100); | ||
const expected = createRiskPercentiles(defaultPercentiles, | ||
[16, 16, 16, 31, 46, 55, 56]); | ||
assert.deepEqual(results, expected); | ||
}); | ||
}); | ||
}); |
@@ -23,2 +23,3 @@ /** | ||
const config = require('../../../lighthouse-core/config/default.json'); | ||
const log = require('../../../lighthouse-core/lib/log'); | ||
@@ -40,2 +41,5 @@ window.createPageAndPopulate = function(results) { | ||
window.runAudits = function(options) { | ||
// Default to 'info' logging level. | ||
log.setLevel('info'); | ||
const driver = new ExtensionProtocol(); | ||
@@ -42,0 +46,0 @@ |
@@ -117,3 +117,2 @@ // generated on 2016-03-19 using generator-chrome-extension 0.5.4 | ||
}) | ||
.ignore('npmlog') | ||
.ignore('chrome-remote-interface'); | ||
@@ -120,0 +119,0 @@ |
{ | ||
"name": "lighthouse", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "Lighthouse", | ||
@@ -11,9 +11,6 @@ "main": "./lighthouse-core/module/index.js", | ||
"scripts": { | ||
"//": | ||
"// dependency installation", | ||
"//": "// passing through tasks to core", | ||
"postinstall": "npm run core-install && npm run extension-install", | ||
"core-install": "npm --prefix ./lighthouse-core install ./lighthouse-core", | ||
"extension-install": "npm --prefix ./lighthouse-extension install ./lighthouse-extension", | ||
"//": | ||
"// global tasks", | ||
"lint": "eslint .", | ||
@@ -24,9 +21,5 @@ "smoke": "lighthouse-cli/scripts/run-smoke-tests.sh", | ||
"start": "node ./lighthouse-cli/index.js", | ||
"//": | ||
"// test", | ||
"test": "npm run lint --silent && npm run unit && npm run closure", | ||
"cli-unit": "mocha $(find lighthouse-cli/test -name '*.js') --timeout 60000", | ||
"unit": "npm run cli-unit && npm --prefix ./lighthouse-core run unit", | ||
"//": | ||
"// passing through tasks to core", | ||
"closure": "npm --prefix ./lighthouse-core run closure", | ||
@@ -44,2 +37,3 @@ "watch": "npm --prefix ./lighthouse-core run watch", | ||
"dependencies": { | ||
"semver": ">=4.3.3", | ||
"yargs": "3.30.0" | ||
@@ -46,0 +40,0 @@ }, |
@@ -98,14 +98,7 @@ # lighthouse | ||
Moreover… | ||
##### Internal module graph | ||
![graph of lighthouse-core module dependencies](https://cloud.githubusercontent.com/assets/39191/16317303/54a25e20-3982-11e6-9374-dd3c24b70468.png) | ||
<small><code>npm install -g js-vd; vd --exclude "node_modules|third_party" lighthouse-core/ > graph.html</code></small> | ||
* `/core.js` does the gathering, auditing and aggregation | ||
* `/runner.js` is the shared handler (for both module & extension) that needs to be given a driver, and sets up the core to do its job | ||
* `/module/index` is the require('lighthouse') file so you can use it in Node, and it uses the runner | ||
``` | ||
module/index \ | ||
----- Runner ----- Core [Gather / Audit / Aggregate] | ||
extension / | ||
``` | ||
### Protocol | ||
@@ -112,0 +105,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
23
2
33075332
2
429
80713
176
+ Addedsemver@>=4.3.3
+ Addedsemver@7.6.3(transitive)