Skip to content

0.6

Compare
Choose a tag to compare
@maciejhirsz maciejhirsz released this 28 Mar 13:00
· 122 commits to master since this release
bd39ad5

License change to MPL

Mandatory disclaimer: I am not a lawyer and this is not legal advice.

After some discussion this release has switched from LGPL-3.0 to the Mozilla Public License version 2.0. LGPL is the GNU License intended for libraries that's not as restrictive as the actual GPL, however its wording makes it problematic to use when a library is statically linked as commonly happens in Rust.

In practice the switch to MPL-2.0 means that you can freely use Kobold in projects that themselves use different licenses, including closed-source proprietary projects, as long as any changes to Kobold itself are made open-source under MPL-2.0.

Keywords

The big breaking1 change in this release is the introduction of keywords for { expressions } in the view! macro. The keyword is always the first token inside the curly braces, currently 4 of them are defined:

  • for makes an iterator into a View. Replaces the ListIteratorExt::list method.
  • ref turns on diffing by reference (rather than value) for strings. Replaces the StrExt::fast_diff method.
  • static disables diffing and prevents updates to the DOM after initial render of the value. Replaces the Stringify::no_diff method.
  • use disables diffing and eagerly sets the value in the DOM on every render. This is a new functionality mostly intended to work with the fence function.

All keywords are defined as raw-identifier functions in the new kobold::keywords module (e.g.: the static keyword maps to kobold::keywords::r#static) for discoverability. In addition to the documentation in the module itself, they are properly spanned and interact nicely with rust-analyzer:

image

The fence function

This release adds the kobold::diff::fence function that guards some inner View-producing closure against renders unless its guard value has changed. Signature:

pub const fn fence<D, V, F>(guard: D, render: F) -> Fence<D, F>
where
    D: Diff,
    V: View,
    F: FnOnce() -> V;

Example:

Fencing a view can be a great optimization, especially when combined with the previously mentioned use keyword:

use kobold::prelude::*;
use kobold::diff::fence;

struct User {
    id: usize,
    name: String,
    email: String,
}

#[component]
fn UserRow(user: &User) -> impl View + '_ {
    fence(user.id, || view! {
        // This row is only re-rendered if `user.id` has changed
        <tr>
            <td>{ user.id }</td>

            // Assuming that `name` and `email` are always different
            // for different users, we can disable diffing here.
            <td>{ use &user.name }</td>
            <td>{ use &user.email }</td>
        </tr>
    })
}

Note: while the use keyword is always safe (it won't cause UI bugs), the performance trade-off only makes sense when used with another mechanism that prevents superfluous renders, such as fence here.

Internals

There has been a substantial refactoring done to the internals of Kobold, few things have moved around and the way attributes are rendered and how elements are mounted has changed. These are mostly implementation details.

In practice everything is more type-safe and extendable while reducing the size of the produced Wasm file even further. The gzipped Wasm file of the TodoMVC example is now down to 17.16kb (was 18.08kb).

Footnotes

  1. The old methods added by extension traits are still supported with deprecation warnings and will be removed in the 0.7 release.