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

View Backend v2! #669

Closed
wants to merge 26 commits into from
Closed

View Backend v2! #669

wants to merge 26 commits into from

Conversation

lukechu10
Copy link
Collaborator

@lukechu10 lukechu10 commented Apr 3, 2024

Closed in favor of #679


Finally, after having gone through a v3 version of our reactivity system with #612, it is time we rework the view system.

This PR eliminates GenericNode that was introduced all the way back in #67 to support both SSR and CSR. Both SSR and CSR are still supported via a different mechanism.

Unlike Leptos, Dioxus, and many other up-and-coming Rust web frameworks, I choose not to use feature flags to differentiate between SSR and CSR mode. This is primarily because doing so would make features non-additive, meaning we cannot enable both at the same time.

In this PR, I have implemented SSR support by introducing a new HtmlNode type that acts a little like a virtual DOM node. Don't let that fool you, however, Sycamore still uses fine-grained reactivity for all DOM updates. Instead, what happens is that our view components constructs a static tree out of these HtmlNodes that describes the initial state of the UI. We then pass this tree to either DomRenderer which will upgrade our tree into actual DOM nodes which can then be modified using reactivity, or SsrRenderer which will directly serialize the tree to an HTML string.

Closes #542

New builder API

Despite having re-worked the builder API in #373 for v0.7 and further small changes for v0.8, the builder API was still not very ergonomic to use. The builder API was always more of a second-class citizen relative to the view! macro.

Before this PR, the builder API was an after-though. Now it is crucial. All HTML attributes are now fully type-checked (incidentally solving #556) via the builder API. The view! macro has also been dramatically simplified to just generating builder methods.

For a taste, here is a comparaison between the old and the new builder API.

// Old
div()
    .c(h1()
        .t("Hello ")
        .dyn_if(
            move || !name.with(String::is_empty),
            move || span().dyn_t(move || name.get_clone()),
            move || span().t("World"),
        )
        .t("!"))
    .c(input().bind_value(name))
    .view();

// New
div()
    .children((
        h1().children((
            "Hello ",
            move || {
                if !name.with(String::is_empty) {
                    span().children(move || name.get_clone())
                } else {
                    span().children("World")
                }
            },
            "!",
        )),
        input().bind(bind::value, name),
    ))
    .into();

Closes #466, #556

Possibly resolved: #604

Hydration

We have DomRenderer for rendering to DOM nodes, we have SsrRenderer for rendering to a static string. And we also have DomHydrateRenderer for hydrating existing DOM nodes. This works differently from the existing implementation by first querying all the nodes with data-hk and storing them inside a list. This gives us a massive performance boost compared to querying every node seperately.

Supersedes #537

Fixes #512 (needs confirmation)

Migration

The main change required is to remove all the pesky <G: Html>s and replace View<G> with simply View. This can easily be accomplished via a simple find-and-replace.

Users of the builder API will need to migrate over to the new syntax. Unfortunately, there isn't much of a mechanical way of doing this other than following the new API,

Some smaller things involve changing iterable to list for Keyed and Indexed components.

Finally, since attributes are now type-checked, invalid uses of attributes will now give a hard error. Another consequence is that since all attributes must be valid Rust identifiers, attributes such as type are now r#type. The special ref attribute is still the same since it is specially handled by the macro.

Remaining tasks:

The core work of implementing this new rendering model has already been done so these tasks may be left for other PRs to speed up iteration time.

Also possibly fixed by this PR: #595

@lukechu10 lukechu10 added C-enhancement Category: new feature or improvement to existing feature BREAKING CHANGE Breaking changes introduced in this PR A-SSR Area: Server Side Rendering (SSR) and Static Site Generation (SSG) labels Apr 3, 2024
@lukechu10 lukechu10 added the A-hydration Area: client-side hydration label Apr 3, 2024
@lukechu10 lukechu10 added performance Performance related and removed performance Performance related labels Apr 4, 2024
Copy link

github-actions bot commented Apr 4, 2024

Benchmark Report

  • wasm-bindgen: the performance goal
  • baseline: performance of sycamore-baseline (typically latest master)
  • update: performance of sycamore (typically recent changes)
  • diff: measures the improvement of update over the baseline
@@                         Performance Diff                          @@

##                       | wasm-bindgen | baseline |  update |  diff ##
#######################################################################
- 01_run1k               |         8.92 |    19.17 |   32.01 |  +66.99%
- 02_replace1k           |        14.49 |    30.41 |   45.12 |  +48.36%
+ 03_update10th1k_x16    |         1.60 |     3.18 |    2.99 |   -6.08%
- 04_select1k            |         0.44 |     5.12 |    5.68 |  +10.77%
- 05_swap1k              |         0.61 |     1.78 |    2.06 |  +15.73%
- 06_remove-one-1k       |         0.27 |     1.13 |    1.28 |  +13.61%
- 07_create10k           |       102.57 |   213.02 |  345.21 |  +62.05%
- 08_create1k-after1k_x2 |         8.62 |    19.49 |   35.14 |  +80.27%
- 09_clear1k_x8          |        23.69 |    27.51 |   39.28 |  +42.80%
- 21_ready-memory        |         1.66 |     1.65 |    1.70 |   +3.17%
  22_run-memory          |         2.82 |     4.92 |    5.05 |   +2.69%
- 23_update5-memory      |         2.86 |     4.93 |    5.15 |   +4.50%
- 25_run-clear-memory    |         1.76 |     3.53 |    3.85 |   +9.06%
+ 26_run-10k-memory      |        13.38 |    41.70 |   33.19 |  -20.41%
+ 41_size-uncompressed   |        47.00 |   276.70 |  267.90 |   -3.18%
+ 42_size-compressed     |        14.50 |    66.60 |   64.50 |   -3.15%
+ 43_first-paint         |       119.80 |   506.60 |  488.10 |   -3.65%

Workflow: 8547975018
Adding new commits will generate a new report

@lukechu10 lukechu10 added this to the v0.9 milestone Apr 8, 2024
@lukechu10 lukechu10 mentioned this pull request Sep 4, 2024
7 tasks
@lukechu10 lukechu10 closed this Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-hydration Area: client-side hydration A-SSR Area: Server Side Rendering (SSR) and Static Site Generation (SSG) BREAKING CHANGE Breaking changes introduced in this PR C-enhancement Category: new feature or improvement to existing feature
Projects
None yet
1 participant