@alithanar/react-automation-profiler
Version:
Automated React profiling and data visualization using React's Profiler API, Puppeteer, and D3.
188 lines (187 loc) • 8.09 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const d3 = (0, tslib_1.__importStar)(require("d3"));
const charts_util_1 = require("./charts.util");
const { INTERACTIONS, RECT, TOTAL } = charts_util_1.MouseEventSelectors;
const { ACTUAL_DURATION, BASE_DURATION, NUMBER_OF_INTERACTIONS, TOTAL_AUTOMATION_TIME_ELAPSED, } = charts_util_1.ParagraphMap;
(async function () {
const height = 500;
let width = 1000;
let bodyWidth = 0;
const margin = {
bottom: 20,
left: 40,
right: 10,
top: 10,
};
const allJsonValues = [];
const carouselIds = [];
const interactions = [];
const itemIdLengths = [];
d3.select('html').on('mousemove', (e) => (0, charts_util_1.updateTooltipPosition)(e));
const jsonFiles = document.querySelectorAll('.json');
const jsonMap = new Map();
jsonFiles.forEach((file) => {
const contents = JSON.parse(file.innerHTML);
const id = file.id;
interactions.push(contents.numberOfInteractions);
contents.logs = contents.logs.map((item, index) => {
item[ACTUAL_DURATION] = item.actualDuration;
item[BASE_DURATION] = item.baseDuration;
item.Render = `${index + 1}: ${item.id}`;
allJsonValues.push(item[ACTUAL_DURATION], item[BASE_DURATION]);
itemIdLengths.push(item.id.length);
delete item.actualDuration;
delete item.baseDuration;
delete item.id;
delete item.interactions;
delete item.phase;
return item;
});
jsonMap.set(id, [...contents.logs]);
});
const longestId = Math.max(...itemIdLengths);
const tallestRect = Math.max(...allJsonValues);
const scaleMax = Math.round((tallestRect + tallestRect * 0.05) * 10) / 10;
for (const [key, value] of jsonMap.entries()) {
const [singularId, multipleId] = key.split('-');
const carouselId = singularId === 'average' ? multipleId : singularId;
carouselIds.push(carouselId);
let carouselEl = document.getElementById(carouselId);
if (!carouselEl) {
carouselEl = (0, charts_util_1.createCarousel)(carouselId);
const h2El = document.createElement('h2');
let innerText = carouselId.replace(/([^A-Z])([A-Z])/g, '$1 $2');
innerText = innerText[0].toUpperCase() + innerText.substring(1);
h2El.innerText = innerText;
carouselEl.appendChild(h2El);
document.body.appendChild(carouselEl);
}
const svgEl = (0, charts_util_1.createSVG)(key);
carouselEl.appendChild(svgEl);
const data = Object.assign(value, {
columns: ['Render', BASE_DURATION, ACTUAL_DURATION],
});
const totalTimeElapsed = data[data.length - 1].commitTime - data[0].startTime;
const potentialWidth = ~~(data.length / 10) * 875 + Math.abs(longestId - 5) * 175 - 1000;
width = potentialWidth > 1000 ? potentialWidth : 1000;
const potentialBodyWidth = width + 600;
if (bodyWidth < potentialBodyWidth)
bodyWidth = potentialBodyWidth;
svgEl.setAttribute('width', `${width}`);
const [groupKey, ...keys] = data.columns;
const color = d3.scaleOrdinal().range(['#5A78E6', '#56A6FC', '#52C9F2']);
const legend = (svg) => {
const g = svg
.attr('transform', `translate(${width},0)`)
.attr('text-anchor', 'end')
.attr('font-family', 'sans-serif')
.attr('font-size', 10)
.selectAll('g')
.data(color.domain().slice().reverse())
.join('g')
.attr('transform', (d, i) => `translate(0,${i * 20})`);
g.append('rect')
.attr('x', -19)
.attr('width', 19)
.attr('height', 19)
.attr('fill', color);
g.append('text')
.attr('x', -24)
.attr('y', 9.5)
.attr('dy', '0.35em')
.text((d) => d);
};
const xAxis = (g) => g
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x0).tickSizeOuter(0))
.call((g) => g.select('.domain').remove());
const yAxis = (g) => g
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(null, 's'))
.call((g) => g.select('.domain').remove())
.call((g) => g
.select('.tick:last-of-type text')
.clone()
.attr('x', 3)
.attr('text-anchor', 'start')
.attr('font-weight', 'bold')
.text('Milliseconds'));
const x0 = d3
.scaleBand()
.domain(data.map((d) => d['Render']))
.rangeRound([margin.left, width - margin.right])
.paddingInner(0.1);
const x1 = d3
.scaleBand()
.domain(keys)
.rangeRound([0, x0.bandwidth()])
.padding(0.05);
const y = d3
.scaleLinear()
.domain([0, scaleMax])
.nice()
.rangeRound([height - margin.bottom, margin.top]);
const chart = () => {
const svg = d3.select(`#chart-${key}`);
svg
.append('g')
.selectAll('g')
.data(data)
.join('g')
.attr('transform', (d) => `translate(${x0(d[groupKey])},0)`)
.selectAll('rect')
.data((d) => keys.map((key) => ({ key, value: d[key] })))
.join('rect')
.attr('x', (d) => x1(d.key))
.attr('y', (d) => y(d.value))
.attr('width', x1.bandwidth())
.attr('height', (d) => y(0) - y(d.value))
.attr('fill', (d) => color(d.key));
svg.append('g').call(xAxis);
svg.append('g').call(yAxis);
svg.append('g').call(legend);
svg
.append('text')
.attr('transform', `translate(45,${height - margin.bottom + 35})`)
.attr('text-align', 'start')
.attr('font-size', '11')
.attr('font-weight', 'bold')
.text('Renders');
svg
.append('text')
.attr('transform', `translate(${width - 12},${height - margin.bottom + 35})`)
.attr('text-anchor', 'end')
.attr('font-size', '11')
.attr('font-weight', 'bold')
.attr('class', 'total')
.text(`${TOTAL_AUTOMATION_TIME_ELAPSED}: ${totalTimeElapsed} ms`);
svg
.append('text')
.attr('transform', `translate(${width - 12},${height - margin.bottom + 55})`)
.attr('text-anchor', 'end')
.attr('font-size', '11')
.attr('font-weight', 'bold')
.attr('class', 'interactions')
.text(`${NUMBER_OF_INTERACTIONS}: ${interactions.shift()}`);
svg
.select('.total')
.on('mouseover', () => (0, charts_util_1.handleMouseOver)(TOTAL))
.on('mouseout', () => (0, charts_util_1.handleMouseOut)());
svg
.select('.interactions')
.on('mouseover', () => (0, charts_util_1.handleMouseOver)(INTERACTIONS))
.on('mouseout', () => (0, charts_util_1.handleMouseOut)());
svg
.selectAll('rect')
.on('mouseover', (e) => (0, charts_util_1.handleMouseOver)(RECT, e))
.on('mouseout', (e) => (0, charts_util_1.handleMouseOut)(e));
return svg.node();
};
chart();
}
(0, charts_util_1.initCarouselState)(carouselIds);
(0, charts_util_1.addExportListener)();
if (bodyWidth)
document.body.style.width = `${bodyWidth}px`;
})();