4 ms·
Oops.js
- T3RMINATED 2y ago[dead]
- m0rde 2y agoWas just thinking about the lack of undo/redo in a complex web app we're building involving ling-running APIs and DB transactions. What are some other undo/redo TypeScript libraries out there. For Oops particularly, I think TS interfaces for commands would help quite or lot here. Or maybe even annotations or decorators?
- FractalHQ 2y agoNo types is a non-starter 100% of the time. I wouldn’t use a library for something like an undo manager though — the core is quite simple and you’ll want full control.
- mmcwilliams 2y agoIt's a ~600 line file with extensive comments, probably 300 of code. It wouldn't be too hard to type this at all.
- unconed 2y agoUndo/redo seems like one of those problems where the knowledge of how to actually do it properly seems lost. People just dig up the supposedly 'solved' ancient solution and then cargo cult it. So you end up with something like this, which looks like a polished and approachable library of a "standard" command pattern. But if you use patterns modeled after single user / local-only apps, you will code yourself into a corner. i.e. In a multiplayer environment, the command pattern is not what you want, because every user has to be able to undo only their own local changes. This means rebasing the local undo/redo history on top of remote changes. Reverting an operation might not result in the same state you had when you performed the action. If the logic of how the command works is frozen inside the code inside a class, no other code can operate on it. I've had much more success with a more functional method based on diffs and patches, i.e. mutations as data. For convenience as a dev, you want to be able to express local changes in a non-reversible way, without the undo/redo nature of the app forcing you to rewrite every change as a non-composable command. You can then convert these into reversible changes automatically (e.g. OTs), which you can put in your undo/redo history, and which can be rebased over each other. I've been trying to lone-star adding proper undo/redo systems to the apps I work on for years, and it always runs headfirst into the fact that the other devs—especially back-end devs—are not able or willing to admit that most everything they know about building applications is wrong and has to be thrown out. These people of course also swear by Git and would refuse to do their jobs without it.
- coolhand2120 2y agoI write undo/redo/history in web/JS extensively. This the best lib out there for such tasks IMHO: https://github.com/yjs/yjs https://github.com/yjs/yjs And you're right. You don't want undo/redo only in multi-user apps. You want to have each user have their own local undo/redo events that they can apply and unapply from the shared state which has its own events apart from each user. Everyone involved needs to keep track of what events they have created forever and always for things to work correctly. This is exactly what ES, OT, and CRDT patterns do, CRDT being the most recent and most capable.
- danjl 2y agoI like the C++-style, class-based implementation. We need more JS modules like this. Zero dependencies. No async code. No callbacks. No HTML.
- coolhand2120 2y agoAfter reviewing the ~600 lines of code, I have to ask what about this undo/redo manager is "advanced"? This seems like a naive implementation of a snapshot collection that is selected via array index. It's not event sourcing, OT or CRDT. With every event, the entire object is serialized and put into the heap. I can't even imagine what this does for performance when you deal with any object of significant size. What if you wanted to do something like type? Thousands of copies of the same thing. Why not https://github.com/yjs/yjs https://github.com/yjs/yjs? Event sourcing is cool. Operational transformation is awesome. But Conflict Free Replicated Data Types are king. Read up on event sourcing, OT and CRDT. If you're not using one of these patterns and you haven't come up with something better you're creating foot guns for the world to shoot themselves with. I apologize for being so harsh. I write undo/redo on JS/web quite a lot and this is going down a dark path. Also, you should not put your dist directory in your repo. It should be a deployed artifact connected to a tagged release - or even better keep it in NPM where it belongs.