Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next #3093

Closed
wants to merge 168 commits into from
Closed

Next #3093

wants to merge 168 commits into from

Conversation

@ianstormtaylor
Copy link
Owner

ianstormtaylor commented Nov 6, 2019

This work is ongoing and not ready yet.


Differences (incomplete)

There are lots of changes in this branch. But here's an overview of the big differences from an architectural point of view.

More coming, still in progress…

JSON

The data model is now comprised of simple JSON objects. Previously, it used Immutable.js data structures. This is a huge change, and one that unlocks many other things. Hopefully it will also increase the average performance when using Slate. It also makes it much easier to get started for newcomers. This will be a large change to migrate from, but it will be worth it.

Interfaces & Namespaces

The data model is interface-based. Previously each model was an instance of a class. Now, not only is the data plain objects, but Slate only expects that the objects implement an interface. So custom properties that used to live in node.data can now live at the top-level of the nodes. Helpers are exposed as a collection of helper functions on a namespace. For example, Node.get(root, path) or Range.isCollapsed(range). This ends up making code much clearer because you can always quickly see what interface you're working with.

TypeScript

The codebase now uses TypeScript. Working with pure JSON as a data model, and using an interface-based API are two things that have been made easier by migrating to TypeScript. You don't need to use it yourself, but if you do you'll get a lot more security when using the APIs. (And if you use VS Code you'll get nice autocompletion regardless!)

Fewer Concepts

The number of interfaces and commands has been reduced. Previously Selection, Annotation, Decoration used to all be separate classes. Now they are simply objects that implement the Range interface. Previously Block and Inline were separate, now they are objects that implement the Element interface. Previously there was a Document and Value, but now the top-level Editor contains the children nodes of the document itself.

The number of commands has been reduced too. Previously we had commands for every type of input, like insertText, insertTextAtRange, insertTextAtPath. These have been merged into a smaller set of more customizable commands, eg. insertText which can take at: Path | Range | Point.

Fewer Packages

In attempt to decrease the maintenance burden, and because the new abstraction and APIs in Slate's core packages make things much easier, the total number of packages has been reduced. Things like slate-plain-serializer, slate-base64-serializer, etc. have been removed and can be implemented in userland easily if needed. Even the slate-html-deserializer can now be implemented in userland (in ~10 LOC leveraging slate-hyperscript). And internal packages like slate-dev-environment, slate-dev-test-utils, etc. are no longer exposed because they are implementation details.

Plugins

Plugins are now plain functions that augment the Editor object they receive and return it again. For example can augment the command execution by composing the editor.exec function. Or listen to operations by composing editor.apply. Previously they relied on a custom middleware stack, and they were just bags of handlers that got merged onto an editor. Now we're using plain old function composition (aka wrapping) instead.

Elements

Block-ness and inline-ness is now a runtime choice. Previously it was baked into the data model with the object: 'block' or object: 'inline' attributes. Now, it checks whether an "element" is inline or not at runtime. For example, you might check to see that element.type === 'link' and treat it as inline.

beforeinput

We now use the beforeinput event almost exclusively. Instead of having relying on a series of shims and the quirks of React synthetic events, we're now using the standardized beforeinput event as our baseline. It is fully supported in Safari and Chrome, will soon be supported in the new Chromium-based Edge, and is currently being worked on in Firefox. In the meantime there are a few patches to make Firefox work. Internet Explorer is no longer supported in core out of the box.

More React-ish

Rendering and event-handling is no longer a plugin's concern. Previously plugins had full control over the rendering logic, and event-handling logic in the editor. This creates a bad incentive to start putting all rendering logic in plugins, which puts Slate in a position of being a wrapper around all of React, which is very hard to do well. Instead, the new architecture has plugins focused purely on the rich-text aspects, and leaves the rendering and event handling aspects to React.

Context

Previously the <Editor> component was doing double duty as a sort of "controller" object and also the contenteditable DOM element. This led to a lot of awkwardness in how other components worked with Slate. In the new version, there is a new <Slate> context provider and a simpler <Editable> contenteditable-like component. By putting the <Slate> provider higher up in your component tree, you can share the editor directly with toolbars, buttons, etc. using the useSlate hook.

Hooks

In addition to the useSlate hook, there are a handful of other hooks. For example the useSelected and useFocused hooks help with knowing when to render selected states (often for void nodes). And since the use React's Content API they will automatically re-render when their state changes.


Reductions

One of the goals was to dramatically simplify a lot of the logic in Slate to make it easier to maintain and iterate on. This was done by refactoring to better base abstractions that can be built on, by leveraging modern DOM APIs, and by migrating to simpler React patterns.

To give you a sense for the change in total lines of code:

slate                       8,436  ->  4,038  (48%)
slate-react                 3,905  ->    715  (18%)

slate-base64-serializer        38  ->      0
slate-dev-benchmark           340  ->      0
slate-dev-environment         102  ->      0
slate-dev-test-utils           44  ->      0
slate-history                   0  ->    201
slate-hotkeys                  62  ->      0
slate-html-serializer         253  ->      0
slate-hyperscript             447  ->    410
slate-plain-serializer         56  ->      0
slate-prop-types               62  ->      0
slate-react-placeholder        62  ->      0
slate-schema                    0  ->    504

total                      13,807  ->  5,868  (43%)

It's quite a big difference, although it's not done so the final sizes will likely grow a bit before it's ready. But that doesn't even include the dependencies that were shed in the process too.


Fixes

This is an estimate of which issues are fixed by this pull request. There are a lot of them, because it changes a lot of things. There might be a few incorrectly "fixed" ones here, so if one of them is your issue and you don't think it's fixed feel free to reopen a new issue.

Fixes #3087
Fixes #3056
Fixes #3090
Fixes #3075
Fixes #2890
Fixes #2325
Fixes #3007
Fixes #3061
Fixes #560
Fixes #2869
Fixes #3028
Fixes #3027
Fixes #1762
Fixes #1022
Fixes #3020
Fixes #2746
Fixes #2991
Fixes #2333
Fixes #2711
Fixes #2413
Fixes #2345
Fixes #2812
Fixes #2859
Fixes #2862
Fixes #2863
Fixes #2495
Fixes #2864
Fixes #2860
Fixes #2878
Fixes #2858
Fixes #2861
Fixes #2985
Fixes #2987
Fixes #1883
Fixes #2002
Fixes #2022
Fixes #2989
Fixes #2990
Fixes #2876
Fixes #2983
Fixes #2945
Fixes #2986
Fixes #2939
Fixes #2968
Fixes #2895
Fixes #2900
Fixes #2873
Fixes #2567
Fixes #2868
Fixes #2867
Fixes #2668
Fixes #2029
Fixes #2759
Fixes #2701
Fixes #1884
Fixes #2503
Fixes #2620
Fixes #2420
Fixes #2708
Fixes #2538
Fixes #1247
Fixes #2466
Fixes #2111
Fixes #2297
Fixes #2321
Fixes #2329
Fixes #2060
Fixes #2274
Fixes #2108
Fixes #1466
Fixes #1759
Fixes #2043
Fixes #1128
Fixes #1464
Fixes #721
Fixes #674
Fixes #2977
Fixes #2336
Fixes #2361
Fixes #2093
Fixes #802
Fixes #2871
Fixes #3113
Fixes #2734
Fixes #3077
Fixes #3040
Fixes #2144
Fixes #3041
Fixes #2743
Fixes #2680
Fixes #2937
Fixes #2907
Fixes #2931
Fixes #2871
Fixes #2850
Fixes #2436
Fixes #1823
Fixes #2073
Fixes #1576
Fixes #1490
Fixes #1202
Fixes #1027


Eliminates

In addition to fixing a lot of things, the significant changes to the architecture mean that a lot of open issues are no longer relevant because they are talking about concepts that no longer exist.

#3022
#3050
#3061
#3013
#3012
#3006
#2886
#2932
#2829
#2328
#2856
#2634
#2472
#2742
#2744
#2549
#2672
#2673
#2640
#2296
#826
#2330
#1915
#2331
#1749
#2289
#2082
#2078
#1843
#1703
#1794
#1821
#1652
#1464
#803
#1367
#651
#873
#1023
#784
#1756
#1626
#1827
#2280
#2410
#2448
#2660
#2602
#2505
#2674
#2928
#3003
#3092

@seanlaff

This comment has been minimized.

Copy link

seanlaff commented Nov 29, 2019

Awesome! Everything sounds great- and stoked to see it in typescript 👍

@sherwinyu

This comment has been minimized.

Copy link
Contributor

sherwinyu commented Nov 29, 2019

Will there be a migration guide (or any other documentation on how to upgrade) coming?

If not, I can try to contribute to one , if that would be helpful for others (will probably take detailed notes when I attempt this upgrade).

Also, this is amazing. I'm so excited for so many of these changes! Thank you!

@sherwinyu

This comment has been minimized.

Copy link
Contributor

sherwinyu commented Nov 29, 2019

Oh, just kidding there's a guide here! https://docs.slatejs.org/concepts/xx-migrating (in case other people read this comment and are looking).

@wmertens

This comment has been minimized.

Copy link
Contributor

wmertens commented Dec 2, 2019

Note for posterity: this was merged in 4ff6972 but GitHub somehow missed that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.