A Fine-Grained Runtime for Performant DOM Rendering
MIT License
Published by ryansolid about 4 years ago
Published by ryansolid over 4 years ago
Published by ryansolid over 4 years ago
This release represents a complete restructure of the project. Both for handling multiple render targets for the Babel plugin, and to move away from EJS for building the runtime. Instead using Babel to rewrite the entry. This drastically simplifies the process of using it.
forwardRef
and merged the functionality with ref
.Published by ryansolid over 4 years ago
on____
events handled the same. If they are not non-composable or non-bubbling they will be delegated by default otherwise level 1 events.events
binding as the on
binding. This adds typical level 3 event handlers for irregular events or events you do not wish to delegate.[handler, boundValue]
where the handler takes the boundValue as the first parameter and the event as the second.@once
indicator to force not wrapping expressions.Published by ryansolid almost 5 years ago
A lot of updates and tweaks since the last minor version:
renderToString
methodclassList
binding performancechildren
in spreadsPublished by ryansolid about 5 years ago
Change template cloning to support rehydration of SVG partials
Published by ryansolid about 5 years ago
The new heuristic for how bindings will be reactive will work as follows:
There are certain types of syntax that will never be reactive like function declarations, literal values.
// these bindings never need to be wrapped
<div onClick={() => setState({clicked: true})} name={"mydiv"} />
Similarly since reactivity requires access only function calls or property accesses can be reactive. So simple variables will never need to be wrapped
// also never needs to be wrapped
<div name={myName} maxlength={count * 2} />
So we can limit wrapping to only expressions that could be reactive like:
// wrap because they could be reactive
<div name={props.name} title={getTitle()} />
Also for Component props that take Components like fallback
or children
we will wrap any expression with a tag to allow deferred evaluation.
// these will be wrapped
<Show when={state.accepted} fallback={<Denied />}>
<Accepted />
</Show>
What if you wish for these things to be static? Hoist the value access. Since normal variables aren't reactive just assign it to a variable. This is JSX so we have all the power of JavaScript at our side and do not need a special syntax.
const name = props.name;
// not wrapped as simple variable
<div name={name} />
Published by ryansolid about 5 years ago
This release adds experimental hydration support for Server Side Rendering and basic (non-namespaced) SVG support.
Published by ryansolid over 5 years ago
This release removes several features by taking a fundamental architecture switch. Overall this is a huge simplification and code reduction.
Instead of hard compiling Control Flows, the library is putting the work on Components in userland. This is infinitely more flexible and opens up different solutions to fit the library that uses it. It meant beefing up the core reconciler to be able to handle pretty much whatever gets thrown at it.
Document Fragments have this pesky characteristic of losing their child nodes. Using arrays is a must if you wish to retain references and pass them around. Which is necessary change if control flow is outside of the main library. This reduces the Node creation in many places, but it also means multi-nested fragments end up getting reconciled all at the same time on update. So there are some performance characteristic changes.
insert
at entryWith these changes, the returned code from JSX is no longer guaranteed to be a DOM node. It may be an array or a function. In so if you use top-level child components or fragments your mount method should use insert
to ensure different inputs are handled properly.
props.children
changesNow when you pass a single child you get a single value and multi-children are represented as arrays. This is consistent with how React handles children and allows a lot of different capacities for Component design. JSX element children by default are handled as dynamic and are lazily evaluated. Allowing for more powerful templating with Components.
Also, custom directives have been removed. They were a confusing alternative way to do things and did not play well with Typescript. Using forwardRef
can achieve the same thing. The naming is under consideration and whether the library should be concerned with multiple instances on the same element (technically it works).
Removal of Control Flow, Custom Directives, and consistent handling of JSX Children all improve TypeScript support.
While on the surface many of these changes may seem like detractors this widely opens up the ecosystem. Components or custom methods can benefit from all the performance capable here. The reactive system feeds into the renderer instead of being so closely entwined. It makes custom logic much simpler to write in the libraries without having to worry about markers and node ranges.
Look forward to updates in related Libraries over the coming weeks.
Published by ryansolid over 5 years ago
Published by ryansolid over 5 years ago
Updates DOM Expressions to support Context API. This includes new Provide control flow and improved implicit Suspend control flow. To support these changes more methods are required by the library implementation, but it is completely opt in. This is a first version so anticipate improvements as we get feedback.
Published by ryansolid over 5 years ago
Breaking Change
This release is a big one. This library no longer provides a factory function to create your runtime. Instead it generates your runtime from the cli. The reason for this change was the runtime could never be optimized for its consumer's purpose. Most notably returning an object from a factory could never be statically analysed. Now the runtime is Tree Shakeable meaning it is possible to only include the features you wish to use. Don't need Suspense or Portals, your Rollup or Webpack bundle doesn't need to include them. This means smaller bundles.
The way this works is automatically handled for the developer when used with Babel Plugin JSX DOM Expressions which compiler will analyse what runtime methods are used and only import those.
In addition, this release has reduced the insert code sharing more between basic expressions and control flow addressing some edge cases on normal insertion around Fragments.
Published by ryansolid over 5 years ago
Converted codebase to TypeScript.
Published by ryansolid over 5 years ago
Breaking Change This release moves HyperScript out of the main package.
Published by ryansolid over 5 years ago
Initial release of runtime separated from the Babel Plugin JSX DOM Expressions. This opens up potential for different Rendering APIs (JSX, HyperScript, Tagged Template Literal, etc..)