Repository navigation
2.0.0 #206
unadlib
announced in
Announcements
2.0.0
#206
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Mutative v2 keeps the v1 API and makes updates faster and more correct. Across 97 benchmarked workloads, it is 4.3x faster than Mutative 1.3.0 on geometric mean, and 3.6x faster than Immer 11.1.18 with matched settings, or 6.6x with each library's defaults. It also fixes many cases in which v1 produced wrong states or patches, and production bundles leave out the development checks. Some of these changes can affect existing code: read the breaking changes below and the migration guide before you upgrade.
Highlights
shift,unshift,spliceandreversemove the elements of a plain array directly on the draft's copy, andindexOf,lastIndexOfandincludessearch it natively. Removing the first of 10,000 rows takes 7.04 µs, against 7,408 µs in Immer, and the patches of such moves replay in both directions.current()of a changed array copies the current array instead of reading each element through the draft, socurrent(draft.list).findIndex(…)searches a large array without creating a draft for each element.-0and of Map keys that are arrays now reproduce the next state, and Map and Set drafts freeze and iterate like built-in Maps and Sets. See fixes that change results.apply(). Patches cannot change the prototypes of objects:apply()also rejects a path that ends in__proto__, and reads Set items only at their indices.process.env.NODE_ENVat each development check, so production bundles leave out the development checks and warnings, and production errors are short codes that link to the errors page.apply()types frozen and in-place results, and a curried recipe that annotates its draft gives a typed producer.llms.txt.Breaking changes
The migration guide describes each change and what to do about it.
Build output and package entries
Proxybut not ES2018 syntax, such as Chrome 49–59, Firefox 18–54, Safari 10–11.0 and Edge 12–18, need Mutative transpiled by your build.process.env.NODE_ENVat each development check instead of always running development code. Bundles that target Node.js without definingNODE_ENV, such as esbuild withplatform: 'node', now include both CommonJS builds; defineNODE_ENVor keep Mutative external.importresolves a module that re-exports the CommonJS build, soimportandrequireshare one instance and both followNODE_ENV. Previously,importalways ran the development ESM build as a separate instance.dist/mutative.esm.mjsanddist/mutative.esm.jsreadprocess.env.NODE_ENVwhen they load, so loading them without a bundler, from a<script type="module">with a raw CDN URL or in another runtime withoutprocess, throwsprocess is not defined. Loaddist/mutative.esm.production.min.mjsinstead, or the UMD build that theunpkgandjsdelivrfields point to.Minified Mutative error #<code>with a link to the errors page instead of the full message. Code that matches error messages in production must match the codes instead.Patches
enableAutoFreeze.apply()still copies patch values; copy a patch value before you change it.sort()or an assignment moved it or another value replaced it there, emits no patches under its old path; the patches of its parent carry its value.removeandaddpatches instead of patches under its position.Arrays
shift,unshift,spliceandreverserun natively on the copy of a plain array, andindexOf,lastIndexOfandincludessearch it natively. For data arrays the results are those of v1, but an accessor property on an array index is read as a data value, so its getter may run a different number of times.current()of a changed array copies the current array. Base elements that a native method moved and that hold drafts of an outercreate()call are left as they are.Returned values
enableAutoFreeze, production builds no longer search frozen objects in a value that a recipe returns for drafts, and development builds throw when they find one there. Never put a draft in a frozen object or in a value it holds.Development builds
create()warns once when it receives a draft with a recipe, since it drafts a copy of the draft's current state; seecreate()on a draft.enablePatches: { pathAsArray: false }, a patch path that would hold a Map key that is not a string, or a symbol key, throws. Production builds still generate such patches, as v1 did.set()method of a Map draft throws, since the next state would keep the revoked draft as a key.enableAutoFreeze, a circular reference is reported only for an object that holds itself.rawReturn()of a value without drafts no longer prints contradictory warnings.TypeScript
create()with an explicit state type and an async recipe, such ascreate<State>(base, async (draft) => { … }), and its curried form returnPromise<State>; v1 typed the result asState.apply()acceptsenableAutoFreeze: trueand then returnsImmutable<State>; withmutabletyped asboolean, it returnsState | void.create((draft: State) => ({ ...draft, count: 0 })), returnsState; v1 typed such a call as a manual draft.State | Promise<State>; v1 typed the result asState.Fixes that change results
v1 gave other results in these cases; the migration guide describes each of them.
enablePatches, every changed item of a Set keeps its changes; a Set that receives an unchanged draft holds the original object; a Set draft that the recipe moves elsewhere keeps its changes; and a draft of a Set subclass changes its copy, so the subclass's ownadd,has,deleteandcleartake effect during the recipe, and itsaddmust store the value that it receives.undefinedto a key thatdelete,shift,unshiftor a shrinkingspliceremoved adds the key back.__proto__key, asJSON.parse()creates one, threw. A class instance that a mark makes immutable is copied by assigning its own properties, so such a setter now runs on that copy instead of through the draft; see copying marked instances.mutable, a value that the recipe assigned or moved is read back as assigned, through the draft and incurrent().current()returns a snapshot of a draft whose state holds a plain Set with drafts, and snapshots an assigned object that a mark makes draftable together with the drafts it holds.enableAutoFreeze, Map and Set instances are frozen too, and later producers skip them.apply()copies the symbol keys and own__proto__keys of patch values, rejects a path that ends in__proto__, reads Set items only at their indices, uses Map keys as they are, and withmutable: truethrows for a patch that replaces the root state.__proto__key as a property of its copy.0and-0, emit no patch for an element that staysNaN, and replace the indices that an array exposes again after it shrank and grew.unsafe()call no longer ends the access of the outer call.Symbol.isConcatSpreadableis false copies its elements.Other changes
NODE_ENVset toproduction,createalone is 7.9 kB with Brotli, against 5.8 kB with 1.3.0, andcreate,apply,currentandoriginaltogether are 8.5 kB, against 6.4 kB. Patches, Maps, Sets and array methods still need no plugins.What's Changed
New Contributors
Full Changelog: v1.3.0...v2.0.0
This discussion was created from the release 2.0.0.
All reactions