Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Improve code splitting #1071

Merged
merged 2 commits into from
Jun 20, 2023
Merged

perf: Improve code splitting #1071

merged 2 commits into from
Jun 20, 2023

Conversation

bprusinowski
Copy link
Collaborator

@bprusinowski bprusinowski commented Jun 19, 2023

  • Do not import ContentMDXProvider in _app.tsx, to prevent adding ~2.8MB in payload size to every page, but rather only use it where it's necessary

Further ideas

Right now, if we want to render a simple column chart, we bundle all column chart related logic, including the grouped chart state, stacked chart state, code for rendering grouped & stacked charts, etc.

I believe that this could be avoided if we split the code in a manner that we treat these as different chart types and not include them in one function (ChartColumnsVisualization) that conditionally renders a given chart subtype. I think this would be a bigger change, as we would need to treat these chart subtypes as chart types, e.g. "column-simple", "column-grouped", "column-stacked". With this we wouldn't bundle things that are not necessary.

@vercel
Copy link

vercel bot commented Jun 19, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
visualization-tool ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 20, 2023 8:05am

@bprusinowski
Copy link
Collaborator Author

@ptbrowne I am going to merge, let me know if you have any thoughts on this :)

@bprusinowski bprusinowski merged commit 84f0a4d into main Jun 20, 2023
@bprusinowski bprusinowski deleted the perf/code-splitting branch June 20, 2023 08:26
@ptbrowne
Copy link
Collaborator

Thanks Bartosz, LGTM.

On the further notes, I am wondering why every chart is bundled when the dynamic tag is used (I see that in app/components/common-chart.tsx) ? It would have seemed to me that the components wrapped in dynamic would only bring their code when the component was rendered ?

@bprusinowski
Copy link
Collaborator Author

Yes, that's the case – but the column chart that we import is basically this,

export const ChartColumns = memo(
({
observations,
dimensions,
measures,
chartConfig,
}: {
observations: Observation[];
dimensions: DimensionMetadataFragment[];
measures: DimensionMetadataFragment[];
chartConfig: ColumnConfig;
}) => {
const { fields, interactiveFiltersConfig } = chartConfig;
return (
<>
{/* FIXME: These checks should probably be handled somewhere else */}
{fields.segment?.componentIri && fields.segment.type === "stacked" ? (
<StackedColumnsChart
data={observations}
fields={fields}
dimensions={dimensions}
measures={measures}
aspectRatio={0.4}
chartConfig={chartConfig}
>
<ChartContainer>
<ChartSvg>
<AxisHeightLinear /> <AxisWidthBand />
<ColumnsStacked /> <AxisWidthBandDomain />
<InteractionColumns />
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
</ChartSvg>
<Tooltip type="multiple" />
</ChartContainer>
<LegendColor
symbol="square"
interactive={
fields.segment && interactiveFiltersConfig?.legend.active
}
/>
{fields.animation && (
<TimeSlider
componentIri={fields.animation.componentIri}
dimensions={dimensions}
showPlayButton={fields.animation.showPlayButton}
animationDuration={fields.animation.duration}
animationType={fields.animation.type}
/>
)}
</StackedColumnsChart>
) : fields.segment?.componentIri &&
fields.segment.type === "grouped" ? (
<GroupedColumnChart
data={observations}
fields={fields}
dimensions={dimensions}
measures={measures}
aspectRatio={0.4}
chartConfig={chartConfig}
>
<ChartContainer>
<ChartSvg>
<AxisHeightLinear />
<AxisWidthBand />
<ColumnsGrouped />
<ErrorWhiskersGrouped />
<AxisWidthBandDomain />
<InteractionColumns />
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
</ChartSvg>
<Tooltip type="multiple" />
</ChartContainer>
<LegendColor
symbol="square"
interactive={
fields.segment && interactiveFiltersConfig?.legend.active
}
/>
{fields.animation && (
<TimeSlider
componentIri={fields.animation.componentIri}
dimensions={dimensions}
showPlayButton={fields.animation.showPlayButton}
animationDuration={fields.animation.duration}
animationType={fields.animation.type}
/>
)}
</GroupedColumnChart>
) : (
<ColumnChart
data={observations}
measures={measures}
dimensions={dimensions}
aspectRatio={0.4}
chartConfig={chartConfig}
>
<ChartContainer>
<ChartSvg>
<AxisHeightLinear />
<AxisWidthBand />
<Columns />
<ErrorWhiskers />
<AxisWidthBandDomain />
<InteractionColumns />
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
</ChartSvg>
<Tooltip type="single" />
</ChartContainer>
{fields.animation && (
<TimeSlider
componentIri={fields.animation.componentIri}
dimensions={dimensions}
showPlayButton={fields.animation.showPlayButton}
animationDuration={fields.animation.duration}
animationType={fields.animation.type}
/>
)}
</ColumnChart>
)}
</>
);
}
);
which means that we have three charts inside one function.

@bprusinowski
Copy link
Collaborator Author

bprusinowski commented Jun 20, 2023

I think the problem is that we have one function that renders different chart subtype based on some conditions – if it was split inside three functions, that would prevent bundling everything. I tried to split that, but still there was a root check on chart type (column)

switch (chartConfig.chartType) {
case "column":
return <ChartColumnsVisualization {...props} chartConfig={chartConfig} />;
case "line":
return <ChartLinesVisualization {...props} chartConfig={chartConfig} />;
case "area":
return <ChartAreasVisualization {...props} chartConfig={chartConfig} />;
case "scatterplot":
return (
<ChartScatterplotVisualization {...props} chartConfig={chartConfig} />
);
case "pie":
return <ChartPieVisualization {...props} chartConfig={chartConfig} />;
case "table":
return <ChartTableVisualization {...props} chartConfig={chartConfig} />;
case "map":
return <ChartMapVisualization {...props} chartConfig={chartConfig} />;
default:
const _exhaustiveCheck: never = chartConfig;
return _exhaustiveCheck;
}
};
+ additional checks below it on which subtype to render, and that didn't work, that's why I think these would need to be distinguishable at the same level as other dynamic imports (chart type: area, line, ...) 🤔 I hope it makes sense 😅

@ptbrowne
Copy link
Collaborator

ptbrowne commented Jun 20, 2023 via email

@bprusinowski
Copy link
Collaborator Author

Yup, I used @next/bundle-analyzer and found the issue with MDX provider 😅 But it's true that icons are the next big thing to look at 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants