Skip to content

[core] Replace reselect with local memoizers in x-internals#22721

Draft
sai6855 wants to merge 2 commits into
mui:masterfrom
sai6855:reselect
Draft

[core] Replace reselect with local memoizers in x-internals#22721
sai6855 wants to merge 2 commits into
mui:masterfrom
sai6855:reselect

Conversation

@sai6855

@sai6855 sai6855 commented Jun 10, 2026

Copy link
Copy Markdown
Member

Replace the reselect runtime dependency with small local implementations of the two memoizers actually used:

  • lruMemoize: least-recently-used cache (maxSize 1 by default) with configurable equalityCheck and resultEqualityCheck, matching the reselect API subset used by the data grid and the store.
  • weakMapMemoize: argument-keyed cache tree holding object arguments weakly, used to memoize selectors on their arguments.

createSelector keeps the exact same memoization strategy as before: the combiner is memoized on its input values (latest call, Object.is), the selector itself is memoized on its arguments through the weak cache, and resultEqualityCheck overrides keep working for the chart tooltip selectors.

reselect stays in package.json as it is still used for type-only imports.

This removes ~8kB minified (~0.8-1kB gzip) from every bundle that includes the x-internals store: all data grid, charts and tree view packages. Combined full-barrel gzip size drops by ~6.8kB as measured with pnpm size:snapshot.

Replace the reselect runtime dependency with small local
implementations of the two memoizers actually used:

- lruMemoize: least-recently-used cache (maxSize 1 by default) with
  configurable equalityCheck and resultEqualityCheck, matching the
  reselect API subset used by the data grid and the store.
- weakMapMemoize: argument-keyed cache tree holding object arguments
  weakly, used to memoize selectors on their arguments.

createSelector keeps the exact same memoization strategy as before:
the combiner is memoized on its input values (latest call, Object.is),
the selector itself is memoized on its arguments through the weak
cache, and resultEqualityCheck overrides keep working for the chart
tooltip selectors.

reselect stays in package.json as it is still used for type-only
imports.

This removes ~8kB minified (~0.8-1kB gzip) from every bundle that
includes the x-internals store: all data grid, charts and tree view
packages. Combined full-barrel gzip size drops by ~6.8kB as measured
with pnpm size:snapshot.
@sai6855 sai6855 added scope: data grid Changes related to the data grid. plan: Pro Impact at least one Pro user. plan: Premium Impact at least one Premium user. type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature. scope: tree view Changes related to the tree view. This includes TreeView, TreeItem. scope: charts Changes related to the charts. labels Jun 10, 2026
@sai6855 sai6855 changed the title [core] Replace reselect with local memoizers in @mui/x-internals [core] Replace reselect with local memoizers in x-internals Jun 10, 2026
@code-infra-dashboard

code-infra-dashboard Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploy preview

https://deploy-preview-22721--material-ui-x.netlify.app/

Bundle size

Bundle Parsed size Gzip size
@mui/x-data-grid ▼-2.32KB(-0.56%) ▼-886B(-0.73%)
@mui/x-data-grid-pro ▼-2.3KB(-0.43%) ▼-879B(-0.56%)
@mui/x-data-grid-premium ▼-2.32KB(-0.32%) ▼-884B(-0.43%)
@mui/x-charts ▼-2.31KB(-0.58%) ▼-872B(-0.74%)
@mui/x-charts-pro ▼-2.32KB(-0.45%) ▼-806B(-0.53%)
@mui/x-charts-premium ▼-2.32KB(-0.37%) ▼-773B(-0.42%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view ▼-2.31KB(-3.54%) ▼-864B(-4.45%)
@mui/x-tree-view-pro ▼-2.32KB(-1.92%) ▼-879B(-2.39%)
@mui/x-license 0B(0.00%) 0B(0.00%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@sai6855

sai6855 commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

@romgrk Before I make this PR ready for review, I'd like to check the direction with you.

The idea: @mui/x-internals only uses a small subset of reselect (lruMemoize with maxSize: 1 and the default weakMapMemoize for args). This PR replaces that subset with ~150 lines of local code with the same memoization semantics — combiner memoized on input values (Object.is, latest call), selector memoized on its arguments through a WeakMap cache tree, resultEqualityCheck still supported for the chart tooltip selectors. Public API of createSelector/createSelectorMemoized is unchanged and the existing grid/charts/tree-view test suites pass.

Result: one less runtime dependency, and ~0.8–1kB gzip off every package that bundles the store (data grid, charts, tree view — all tiers), ~6.9kB total measured with pnpm size:snapshot.

Does this seem like a direction worth taking?

@romgrk

romgrk commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

I'm in favor of this change, but duplicated version of the store code exist here and in the Base UI repository. I'm trying to merge those versions so whatever changes we do here, we also need to do on the BUI repository. I'd open a parallel PR to validate that the changes pass tests on both sides before merging anything.

reselect stays in package.json as it is still used for type-only imports.

Ideally we'd get rid of it completely.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I like about reselect is that it has a fast version of lruMemoize optimized for maxSize: 1, which is our default (and maybe only) value for that option. I guess we'd lose some of the size benefits by doing the same here, I'd be curious to know how much it costs.

See https://github.com/reduxjs/reselect/blob/master/src/lruMemoize.ts

@sai6855

sai6855 commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

I'm in favor of this change

Great

I'd open a parallel PR to validate that the changes pass tests on both sides before merging anything.

Got it, let me refine PR and do changes in both repos

Ideally we'd get rid of it completely.

I'll check

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Result: one less runtime dependency, and ~0.8–1kB gzip off every package that bundles the store (data grid, charts, tree view — all tiers)

Although considering the popularity of Redux Toolkit, some of our users might see a net loss because they'd be shipping both our code and reselect's code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plan: Premium Impact at least one Premium user. plan: Pro Impact at least one Pro user. scope: charts Changes related to the charts. scope: data grid Changes related to the data grid. scope: tree view Changes related to the tree view. This includes TreeView, TreeItem. type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants