planttheidea / moize

The consistently-fast, complete memoization solution for JS
https://planttheidea.github.io/moize/
MIT License
892 stars 18 forks source link

[Feature Request] Tree-shakeable API #188

Open Rush opened 1 year ago

Rush commented 1 year ago

Not sure if you ever considered it but the way moize APIs are structured it's impossible to tree shake them. For example I don't use React and would be nice if it was possible for tooling to remove some unused features.

In order for APIs to be tree shakeable some of the features should be provided in the form of free-form functions. For example moizeReact vs moize.react. Or some other form of composable functions.

Obviously it's a matter of convenience vs gain but perhaps something worth considering.

planttheidea commented 1 year ago

Appreciate the feedback, and this has been considered, however there are a few fundamental architecture aspects that would need some serious consideration before this occurred. It may be more detail than you were looking for, but I'll try to cover the thoughts and trade-offs, both to inform but also in case there are ideas that you have that I may have missed. Before I dive in, though, I would recommend you check out micro-memoize, which is the engine that powers moize but has an intentionally limited feature set to be as small as possible while still covering the most common use-cases. It may give you what you need in a smaller package.

The objective of moize has been about balancing convenience with flexibility ("offers a large number of options to satisfy any number of potential use-cases", from the README). You refer to the convenience of moize.react, but that is just a one-line partial application of the isReact option, which itself is shorthand for other options ({ maxArgs: 2, isShallowEqual: true } by default), so there is interplay between the options available out of the box. More importantly, the isReact option can be applied to any implementation. Example:

const memoize = moize({
  isDeepEqual: true,
  isReact: true,
  maxAge: 5000,
  maxSize: 5,
});

This flexibility is not something we want to sacrifice, and in my research there isn't a way to provide this kind of runtime flexibility in a statically-analyzable way which allows for tree-shaking.

However, the desire for smaller asset size is actually why micro-memoize as a package exists. Since inception, there have been a subset of consumers that have requested a smaller asset size, because while moize is quite small for most (~3.71 KiB when minified and gzipped), there are use-cases where every little bit matters. Hence, the core engine of moize was split out into micro-memoize, which handles a more limited set of use-cases, but is much smaller (~1.44 KiB when minified and gzipped). Hence, the mantra to-date has been "if you value asset size over robustness of features, use micro-memoize".

That said, there are other ways to accomplish this flexibility for moize while also providing the opportunity for asset size reduction, and this is where the convenience for consumers comes in. For example, a "plugin" model was considered prior, where each option is separately imported and bolted on as a configuration. Example:

import createMoize from '@moize/core';
import deepEqualPlugin from '@moize/deep-equal-plugin';
import maxAgePlugin from '@moize/max-age-plugin';
import maxSizePlugin from '@moize/mas-size-plugin';
import reactPlugin from '@moize/react-plugin';

const moize = createMoize([deepEqualPlugin, maxAgePlugin, maxSizePlugin, reactPlugin]);

This could even be made backwards-compatible for consumers, where the "full plugin suite" is still available as moize and the "limited plugin suite" is available as micro-memoize. A good parallel here would be Babel, where you can either install babel-preset-env and call it a day, or build your own custom configuration by mixing and matching plugins (or even write your own). As you can imagine, though, this would involve a rewrite from scratch, and since the split out of micro-memoize there has not been the demand to validate the work effort involved. I still may do it, though, if there is demand (or I just get bored enough :) ).

If you have thoughts or ideas on the topic, I'd love to hear them.