@alithanar/react-automation-profiler
Version:
Automated React profiling and data visualization using React's Profiler API, Puppeteer, and D3.
162 lines • 6.54 kB
JavaScript
;
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const browser_sync_1 = __importDefault(require("browser-sync"));
const promises_1 = __importDefault(require("fs/promises"));
const path_1 = __importDefault(require("path"));
const yargs_1 = __importDefault(require("yargs"));
const automation_1 = __importDefault(require("./automation/automation"));
const util_1 = require("./utils/util");
const helpers_1 = require("yargs/helpers");
const AutomationResultsStorage_1 = require("./automation/AutomationResultsStorage");
const interfaces_1 = require("./interfaces");
const path_2 = require("path");
console.log(`
█▀█ ▄▀█ █▀█
█▀▄ █▀█ █▀▀ \x1b[1;32mreact automation profiler\x1b[37m
`);
const options = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
.usage(`Usage: --averageOf <averageOf> --changeInterval <changeInterval> \
--includeMount <includeMount> --page <page> --port <port> --watch <watch>`)
.option('averageOf', {
describe: 'run each flow n number of times and average out the metrics',
type: 'number',
})
.option('changeInterval', {
describe: 'number of changes before automation is rerun',
type: 'number',
})
.option('includeMount', {
describe: 'includes the initial mount render',
type: 'boolean',
})
.option('page', {
describe: 'page to be tested',
type: 'string',
demandOption: true,
})
.option('port', {
describe: 'port to be used for server',
type: 'number',
})
.option('watch', {
describe: 'generate charts on every new build',
type: 'boolean' || 'string',
})
.option('output', {
describe: 'choose the desired output. Acceptable values: [chart, json]',
type: 'string',
})
.option('headless', {
describe: 'determines if chromium browser window should be visible',
type: 'boolean',
}).argv;
const { averageOf = 1, changeInterval = 1, includeMount = false, page, port = 1235, watch = false, headless = true, output = interfaces_1.OutputType.CHART, } = options;
const cwd = path_1.default.resolve();
const scriptPath = (0, path_2.resolve)('./lib/bin.js');
const packagePath = `${scriptPath.slice(0, scriptPath.lastIndexOf('/'))}`;
const serverPath = `http://localhost:${port + 1}`;
let changeCount = 0;
let versionCount = 0;
let isServerReady = false;
let timer;
const resultsStorage = new AutomationResultsStorage_1.AutomationResultsStorage();
function checkShouldAutomate() {
clearTimeout(timer);
timer = setTimeout(async () => {
changeCount++;
if (changeCount >= changeInterval) {
changeCount = 0;
await handleAutomation();
browser_sync_1.default.reload();
}
// will re-automate after 10 seconds to give time for the host project
// to rebuild after changes
}, 10000);
}
function getStopMessage(output) {
return output === interfaces_1.OutputType.CHART
? `Displaying ${versionCount++ ? `${versionCount} versions of ` : ''}charts at: \x1b[1;32mhttp://localhost:${port}\x1b[37m`
: 'Automation finished';
}
async function handleAutomation() {
for (let automationCount = 1; automationCount <= averageOf; automationCount++) {
(0, util_1.printMessage)("AUTOMATION_START" /* AUTOMATION_START */);
const automationProps = {
automationCount,
averageOf,
cwd,
includeMount,
isServerReady,
packagePath,
serverPort: port + 1,
url: page,
headless,
output,
};
await (0, automation_1.default)(automationProps, resultsStorage);
(0, util_1.printMessage)("AUTOMATION_STOP" /* AUTOMATION_STOP */, { log: getStopMessage(output) });
if (!isServerReady && automationCount === averageOf)
isServerReady = true;
}
}
function setupProxy() {
browser_sync_1.default.init({
browser: 'google chrome',
logLevel: 'silent',
notify: false,
open: true,
port,
proxy: serverPath,
reloadOnRestart: true,
});
}
// run
/***********************/
(async () => {
var e_1, _a;
try {
await handleAutomation();
}
catch (error) {
(0, util_1.printMessage)("AUTOMATION_STOP" /* AUTOMATION_STOP */, { e: error });
process.exit();
}
if (output === interfaces_1.OutputType.CHART) {
setupProxy();
if (watch) {
const watchDir = typeof watch === 'string' ? `${cwd}/${watch}` : cwd;
const events = promises_1.default.watch(watchDir, { recursive: true }
// node types are saying that fs.watch returns AsyncIterable<string>, but
// it's actually AsyncIterable<{ eventType: string; filename: string }>.
// Have to cast as unknown first to get around this.
);
try {
for (var events_1 = __asyncValues(events), events_1_1; events_1_1 = await events_1.next(), !events_1_1.done;) {
const { eventType, filename } = events_1_1.value;
if (eventType === 'change' && !filename.startsWith('node_modules')) {
checkShouldAutomate();
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (events_1_1 && !events_1_1.done && (_a = events_1.return)) await _a.call(events_1);
}
finally { if (e_1) throw e_1.error; }
}
}
}
})();
//# sourceMappingURL=bin.js.map