immerjs / immer

Create the next immutable state by mutating the current one
https://immerjs.github.io/immer/
MIT License
27.5k stars 850 forks source link

fix: Reorganize code for maximum tree-shakability #1125

Open steveluscher opened 3 months ago

steveluscher commented 3 months ago

Problem

Because every method is bound up in a Class, instantiated in the module factory, then exported, consumers will get every method of Immer in their bundle, whether they use it or not.

A slight reorganization of the code would allow their optimizing compilers to tree-shake away the method implementations that they don't need.

Summary

This PR reorganizes the code such that requiring one method of Immer doesn't force you to take a hard dependency on all the others. You can now do this:

import { produce } from 'immer';
produce(state, draft => { /* ... */ });

…and have all of the other methods that you haven't used (produceWithPatches, setAutoFreeze, setUseStrictShallowCopy, applyPatches, createDraft, finishDraft) be reaped by your optimizing compiler.

Results

Consider this typical application that only uses produce():

import { produce } from "immer";

const state = {
  name: { first: "Ada", last: "Byron" },
};

console.log({
  before: state,
  after: produce(state, (draft) => {
    draft.name.last = "Lovelace";
  }),
});

When bundled with an optimizing compiler:

pnpm dlx esbuild --bundle --define:process.env.NODE_ENV='"production"' --tree-shaking index.ts  

This PR (in combination with #1124) results in a bundle that's 13% smaller, gzipped (diff)

Test plan

yarn test