Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@starbeam/renderer

Package Overview
Dependencies
Maintainers
3
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@starbeam/renderer

| Framework | Renderer Status | Spec Compatibility | | --------- | --------------- | ------------------ | | React | _released_ | _next release_ | | Preact | _released_ | _next release_ | | Vue | _next release_ | _next relea

  • 0.8.10-unstable.3e1af4d
  • npm
  • Socket score

Version published
Maintainers
3
Created
Source

Starbeam Renderers

FrameworkRenderer StatusSpec Compatibility
Reactreleasednext release
Preactreleasednext release
Vuenext releasenext release
Sveltedesigning-
Emberdesigning-
Solidroadmap-

"Spec compatibility" means compatibility with the API design in this document.

Core API

These APIs exist in all renderers.

APIParameterReturns
setupReactive() => Reactive<T>Native<T>
setupResourceIntoResourceBlueprintNative<T> React1
getServiceIntoResourceBlueprintNative<T>

Framework-Native Reactive Values (Native<T>)

  • In React, these methods return Reactive<T>.
  • In all other renderers, these methods return a framework-native reactive value.
  • Renderers for React-style frameworks also have hook versions of these APIs that return a T.

setupResource

The setupResource function takes a resource blueprint and returns a framework-native reactive value.

Lifecycle

getService

The getService function takes a resource blueprint and gets a service instance for the current app as a framework-native reactive value.

If the blueprint has already been instantiated for this app, the same instance is returned.

Lifecycle
  • The resource is disposed when the component's application is cleaned up.

Hook-Style Renderers

A hook-style component is a function that runs on both initial render and update. In this situation, hooks provided by Starbeam set up resource and services on the initial render. These hooks also return the current value of the resource on all renders.

React and Preact are hook-style renderers. Solid is not.

API Summary

Hook-style renderers include the core APIs, which return reactive values.

In addition, they include idiomatic hooks that return bare values.

PurposeCore APIHook API
ReactivesetupReactive(ReactiveBlueprint<T>) => Native<T>useReactive(ReactiveBlueprint<T>) => T
ResourcesetupResource(ResourceBlueprint<T>) => Native<T>useResource(ResourceBlueprint<T>) => T
ServicesetupService(ResourceBlueprint<T>) => Native<T>useService(ResourceBlueprint<T>) => T

In addition, hook-style renderers include a hook that runs during Starbeam's setup phase: useInstance.

function Counter() {
  const counter = useResource(Counter);

  const localCount = useInstance(() => Cell(0));
  // localCount returns the cell instance. The count will
  // always be zero after `resource` is initially created
  // (i.e. for each setup phase of Counter)

  return <>
    <p>{counter}</p>
    <button
      onClick={() => localCount.current++}
    >
      Increment
    </button>
  </p>
}

All of these hooks take a dependency array that behave idiomatically.

If the dependencies to useResource invalidate, the resource will be cleaned up and reinstantiated. Otherwise, the function passed to the hook will be called again on the next render.

Instance-Style Idioms

Applies to renderers that have explicit setup code that runs only once per component.

  • Vue
  • Svelte
  • Ember
  • Solid
useReactive()

Note: Preact does not require the useReactive function, because its plugin API allows us to automatically track values consumed by each component.

The useReactive function is called in the setup code of a component. It turns the component into a reactive component by registering appropriate lifecycle hooks that allow Starbeam to track all values consumed by the component during initial render and update.

Framework-Native Reactive Values

For a JavaScript value of type T.

FrameworkReactive TypeRenderer Status
ReactTreleased
PreactSignal<T>released
VueRef<T>next release
SvelteStore<T>designing
EmberReactive<T>designing
SolidSignal<T>roadmap

Definitions

Component Phases

You can think of the component phases as a universal lifecycle for components in all supported frameworks.

This universal lifecycle is not a lowest-common denominator subset. Instead, it aims to support a universal API that is rich enough to support advanced features in supported frameworks (such as Vue's KeepAlive) while avoiding gratuitous differences that make it difficult to write universal frontend code.

The Primary Phases

These phases are meaningful in all supported frameworks and idiomatic usage of Starbeam's universal APIs will interact with them.

PhasePurpose
SetupThe component's setup code is run once per component.
RenderingThis code is run after the setup phase and has access to the state created in the setup phase.
Before PaintThis phase is no earlier than the resource setup phase and no later than browser paint. Code that runs in this phase block the browser's painting process.
RenderedThis phase is after the Before Paint phase and after the browser paint. If the cleanup phase happens quickly, the Rendered phase may not happen at all.
CleanupThe final phase of a component's lifecycle. During this phase, any registered cleanup handlers are evaluated.
Special Phases

These phases are supported by Starbeam's universal APIs, but are equivalent to one of the primary phases in most frameworks.

PhasePurposeFramework(s)
Resource SetupThis phase is guaranteed to be paired with a future cleanup phase. This phase happens after rendering in React. In all other frameworks, Setup is guaranteed to be paired with a future cleanup phase.React
DeactivateA component is removed from the tree with the possibility of returning in the future. Deactivate must be followed by Reactivate or Cleanup.Vue
ReactivateA component that was previously deactivated is restored.Vue

Component Lifetime and Lifecycle

In Starbeam, a component's lifetime starts with the component's setup phase and ends when the component's cleanup phase.

Because React has interesting deactivation behavior, make sure to read React's Component Lifetime and Lifecycle appendix for the full scoop.

The Cleanup Phase vs. The Deactivate Phase

In most frameworks, there is a single cleanup phase that runs exactly once for each time a component is instantiated and rendered.

This is not always exactly true:

  • React: The cleanup phase may run any number of times during the lifetime of a component (zero or more).
  • Vue: A special deactivation phase may run any number of times during the lifetime of a component. Deactivation is always followed by a cleanup phase or a reactivation phase.

In practice, this means that resources that register cleanup handlers are cleaned up when the component is cleaned up.

These handlers may run multiple times during a single React component instance, which aligns with React's lifecycle design.

Other Renderer Requirements

Current App Instance

During the evaluation of setup code, a stable value that represents the current application instance.

An application instance has a 1:1 correspondence with the root component of a render tree.

  • It must remain stable across the lifetime of the application
  • It must be available to all components in the render tree during their setup phase.
  • It must expose a way to register cleanup code that should run when the application is unmounted.

Frameworks don't typically expose something like this directly, but it's reasonably easy to synthesize with features like "context" or by requiring the user to install a framework plugin.

In practice, this means that most renderers require the user to use a context provider component or install a plugin in order to use the service feature.

Summary of APIs for All Official Renderers

RendererType
ReactHook-Style
PreactHook-Style
SolidInstance-Style
VueInstance-Style
SvelteInstance-Style
EmberInstance-Style

Framework Styles

Hook-Style

A hook-style API is a function that runs on both initial render and update.

In these frameworks, there is no separation between the code that runs on initial render and the code that runs on update, but the primitive hooks supplied by the framework provide tools that you can use to implement behavior that only runs on initial render.

Instance-Style

An instance-style API is an API that has explicit setup code that runs only once per component. These APIs also have some sort of render function that runs on each render (both initial render and udpate), and this code has access to the values created during setup.

Some instance-style frameworks, such as Solid, attempt to use an API style that mimics hook-style APIs. Others, such as Ember, primarily use JavaScript classes to distinguish between setup code and rendering. Still others, such as Vue, draw a strong distinction between setup code and rendering using framework-specific API patterns.

In addition, instance-style frameworks can support render functions (Solid), templates (Ember, Svelte), or a mix of both (Vue).

While these distinctions can make these APIs seem very different from each other, they are fundamental very similar:

All instance-style frameworks expose an explicit place to run setup code and a separate way to express render logic. The setup code runs only once per component, and the state that it sets up is accessible to the render logic.

APIs

Resources
RendererSetup APIHook API
ReactsetupResource() => Reactive<T>useResource() => T
PreactsetupResource() => Signal<T>useResource() => T
SolidsetupResource() => Signal<T>N/A
VuesetupResource() => Ref<T>N/A
SveltesetupResource() => ReadonlyStore<T>N/A
EmbersetupResource() => Reactive<T>N/A
Services
RendererSetup APIHook API
ReactgetService() => Reactive<T>useService() => T
PreactgetService() => Signal<T>useService() => T
SolidgetService() => Signal<T>N/A
VuegetService() => Ref<T>N/A
SveltegetService() => ReadonlyStore<T>N/A
EmbergetService() => Reactive<T>N/A

Appendix: React Nitty-Gritty

The Setup Phase

Since React calls cleanup callbacks multiple times, you might have expected React to support deactivation and reactivation phases.

However, remember that "Deactivate must be followed by Reactivate or Cleanup". While React runs cleanup callbacks multiple times, each run might be the last one.

Mounting
When React calls a component's render function for the first time, we say that the component is "mounting".
Unmounting
When React calls useEffect and useLayoutEffect cleanup callbacks, even when the dependency array hasn't changed, we say that the component is "unmounting".
Remounting
When React calls useEffect and useLayoutEffect again, even when the dependency array hasn't changed, we say that the component is "remounting".

Each time React unmounts a component, its cleanup phase runs. If React remounts the same component, its setup phase runs again.

From the perspective of Starbeam's lifecycle, a component's lifetime starts when a component is mounting or remounting and ends when a component is unmounting.

A single React component can have multiple Starbeam lifetimes.

Most users will encounter this when using React strict mode. Because Starbeam is going with the React grain and cleaning up resources when a component is unmounted, setupResource and useResource work transparently in React strict mode.

Resources in React

In other frameworks, the Setup Phase is guaranteed to be paired with a future cleanup phase.

However, React's Setup Phase may run multiple times before a cleanup phase is run, or a cleanup phase may not run at all.

As a result, Starbeam resources cannot be instantiated until React's special Resource Setup Phase.

In practice, this means that resources are undefined during the initial render of a React component. If undefined is not desirable, React's setupResource has an initial option that you can use to specify what the initial value of the resource should be during initial render.

Note that this is a fundamental consequence of React's decision to disallow render functions from registering cleanup handlers at the top level.

Unmount and Deactivation Are Equivalent

In React, there is no meaningful distinction between the cleanup phase and the deactivate phase. When React calls cleanup callbacks, it is impossible to determine whether the component is eligible for reactivation in the future. Components that are never reactivated don't receive any future cleanup callbacks, so cleanup code has to fully clean up the component.

In contrast, Vue calls onDeactivated callbacks when the component is deactivated, but not onUnmounted. If the component is subsequently removed entirely (and will never be reactivated), Vue calls onUnmounted at that point.

As a result, the Vue renderer has a meaningful deactivation phase, while the React renderer treats deactivation and unmounting as equivalent.

This means that deactivation handlers registered in universal Starbeam code will run during Vue deactivation, but React deactivation results in full cleanup.

Unless you have a very specific reason to support a deactivation/unmount distinction in universal code, you should register cleanup handlers and not worry about deactivation handlers.

Component Lifetime and Lifecycle

In React, each time a component is reactivated, it gets a new component lifetime. This means that setup handlers run again, and any per-instance state is reinitialized.

🚧 TODO: Consider Supporting Reactivate in React

Unlike Vue, this hook cannot be used to persist resources (because we we can't differentiate between deactivations and final unmounting), but it may be useful to support persisting in-memory state on an opt-in basis.

From a usage perspective, this means that resources get cleaned up when a component is unmounted or deactivated in React.

This is what React's design wants us to do: React intentionally calls cleanup handlers when a component is deactivated, and intentionally does not give us a way to run cleanup handlers when a deactivated component is finally disposed.

React Strict Mode intentionally calls cleanup handlers during initial render (deactivating the component) and then runs effects again (reactivating the component) to teach users that cleanup might happen multiple times, and every cleanup might be the last one.

Footnotes

  1. React returns Reactive<T | undefined> from setupResource (see React Resources).

FAQs

Package last updated on 04 Jan 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc