Skip to content

Latest commit

 

History

History
253 lines (181 loc) · 11.4 KB

File metadata and controls

253 lines (181 loc) · 11.4 KB

Migrating from previous versions

FASTGlobal version tracking (v2 → v3)

Removed API

Removed Replacement
FAST.versions No replacement. Multiple FAST versions on the same page are unsupported in v3.

Migration steps

  1. Remove any runtime checks that read FAST.versions.
  2. Fix duplicate FAST installs in your bundler or dependency graph instead of relying on version tracking at runtime.

Native globalThis requirement (v2 → v3)

Changed behavior

  • Native globalThis required: @microsoft/fast-element no longer installs a globalThis polyfill as a side effect. The package only keeps the requestIdleCallback / cancelIdleCallback fallback for environments that still lack those APIs.

Migration steps

  1. Verify that the browsers and JS runtimes you support provide native globalThis.
  2. If you still target an older runtime without globalThis, load that polyfill before importing @microsoft/fast-element.

Declarative HTML moved into fast-element (v3)

Declarative HTML APIs now ship from @microsoft/fast-element instead of the removed @microsoft/fast-html package.

Import changes

Before After
@microsoft/fast-html @microsoft/fast-element/declarative.js
@microsoft/fast-html/utilities.js @microsoft/fast-element/declarative/utilities.js

Migration steps

  1. Update declarative runtime imports to @microsoft/fast-element/declarative.js.
  2. Update declarative utility imports such as deepMerge to @microsoft/fast-element/declarative/utilities.js.
  3. Keep importing core FAST Element APIs (for example FASTElement, attr, observable) from @microsoft/fast-element.
  4. Do not switch to the root @microsoft/fast-element barrel for declarative APIs; the declarative entrypoint owns the debug-message and hydratable-view side effects.

Export path cleanup (v3)

Optional binding and hydration helpers remain on their dedicated public sub-entrypoints:

  • @microsoft/fast-element/binding/two-way.js
  • @microsoft/fast-element/binding/signal.js
  • @microsoft/fast-element/element-hydration.js
  • @microsoft/fast-element/install-element-hydration.js
  • @microsoft/fast-element/install-hydratable-view-templates.js

Removed exports

Import Replacement
@microsoft/fast-element/metadata.js No public replacement
@microsoft/fast-element/pending-task.js No public replacement

Migration steps

  1. Keep optional binding and hydration imports on their dedicated subpaths.
  2. Remove any direct imports from metadata.js or pending-task.js.

Prerendered Content Optimization (v2 → v3)

Removed exports

Export Replacement
HydratableElementController ElementController (prerendered path built in)
HydrationControllerCallbacks ElementHydrationCallbacks via ElementController.configHydration()
needsHydrationAttribute ElementController.isPrerendered
deferHydrationAttribute Template-pending guard in ElementController.connect()

Removed side-effect imports

Import Replacement
@microsoft/fast-element/install-hydration.js No replacement needed — prerendered path is built into ElementController

The install-hydratable-view-templates.js side-effect import is still available and is applied automatically by @microsoft/fast-element/declarative.js for hydration marker support.

Changed behavior

  • attributeChangedCallback during upgrade: When isPrerendered is true and the element has not yet connected, attribute change callbacks are suppressed. After connection, all attribute changes are processed normally.
  • connect() with deferred template: When templateOptions is "defer-and-hydrate" and no template is available, connect() returns early automatically. The Observable subscription on "template" retriggers connection when the template arrives. No defer-hydration attribute is needed.
  • Binding evaluation with existing shadow root: When an existing shadow root is detected, attribute and booleanAttribute bindings skip their initial DOM update. All other binding types (event, content, property, tokenList) run normally.

New APIs

  • ElementController.isPrerendered (Promise<boolean>): Resolves to true after prerendered content has been hydrated, or false when the component is client-side rendered. Component authors can await this to know when the element is fully interactive.
  • ViewController.isPrerendered (Promise<boolean> | undefined): Available to custom directives. Resolves to true when the view's content was prerendered, false otherwise.

Migration steps

  1. Remove HydratableElementController.install() calls.
  2. Remove import "@microsoft/fast-element/install-hydration.js" side-effect imports.
  3. Replace element.$fastController instanceof HydratableElementController checks with await element.$fastController.isPrerendered.
  4. Remove defer-hydration and needs-hydration attributes from server-rendered markup.

Hydration Marker Format (v3)

Changed format

The hydration markers embedded in SSR output have been simplified from verbose, index-embedded comment markers to compact, data-free sequential markers.

Comment markers

Marker type Old format New format
Content binding start <!-- fe-b$$start$$<index>$$<scopeId>$$fe-b --> <!--fe:b-->
Content binding end <!-- fe-b$$end$$<index>$$<scopeId>$$fe-b --> <!--fe:/b-->
Repeat item start <!-- fe-repeat$$start$$<itemIndex>$$fe-repeat --> <!--fe:r-->
Repeat item end <!-- fe-repeat$$end$$<itemIndex>$$fe-repeat --> <!--fe:/r-->
Element boundary start <!-- fe-eb$$start$$<elementId>$$fe-eb --> <!--fe:e-->
Element boundary end <!-- fe-eb$$end$$<elementId>$$fe-eb --> <!--fe:/e-->

Attribute binding markers

Old format New format
data-fe-b="0 1 2" (space-separated indices) data-fe="N" (binding count)
data-fe-b-0 (enumerated, one per factory) data-fe="N"
data-fe-c-0-3 (compact, start index + count) data-fe="N"

Removed APIs

Export Replacement
HydrationMarkup.contentBindingStartMarker(index, scopeId) HydrationMarkup.contentBindingStartMarker()
HydrationMarkup.contentBindingEndMarker(index, scopeId) HydrationMarkup.contentBindingEndMarker()
HydrationMarkup.isContentBindingStartMarker(data) HydrationMarkup.isContentBindingStartMarker(data) (unchanged signature, new implementation)
HydrationMarkup.isContentBindingEndMarker(data) HydrationMarkup.isContentBindingEndMarker(data) (unchanged signature, new implementation)
HydrationMarkup.parseAttributeBinding(element) HydrationMarkup.parseAttributeBindingCount(element)
HydrationMarkup.parseRepeatStartMarker(data) HydrationMarkup.isRepeatViewStartMarker(data)
HydrationMarkup.parseRepeatEndMarker(data) HydrationMarkup.isRepeatViewEndMarker(data)
HydrationMarkup.parseElementBoundaryStartMarker(content) HydrationMarkup.isElementBoundaryStartMarker(node)
HydrationMarkup.parseElementBoundaryEndMarker(content) HydrationMarkup.isElementBoundaryEndMarker(node)

Impact

This is a breaking change for SSR output format. Any system that produces or parses hydration markers must be updated to use the new format. The @microsoft/fast-build Rust crate and WASM binary have been updated accordingly.

  • Marker parsing uses string equality checks (data === "fe:b") instead of regex
  • Start/end pairing uses balanced depth counting instead of embedded IDs
  • The hydration walker uses a sequential factory pointer instead of index-based lookup
  • SSR and client versions must match — mixing old SSR output with new client code (or vice versa) will fail

Async define/compose/register API (v3)

Removed APIs

Removed Replacement
FASTElement.defineAsync() FASTElement.define() (now returns Promise<TType>)
FASTElementDefinition.composeAsync() FASTElementDefinition.compose() (now returns Promise<FASTElementDefinition>)
FASTElementDefinition.registerAsync() FASTElementDefinition.register() (same Promise<Function> return type)

Changed behavior

  • FASTElement.define() now returns Promise<TType>. When a template is provided at definition time, the Promise resolves immediately. When templateOptions is "defer-and-hydrate" and no template is provided, the Promise resolves after a template is supplied (e.g. via <f-template>).
  • FASTElement.compose() now returns Promise<FASTElementDefinition>. The Promise always resolves immediately.
  • FASTElementDefinition.compose() now returns Promise<FASTElementDefinition>. The Promise always resolves immediately.
  • @customElement decorator calls define() internally but does not return the Promise (fire-and-forget). For complete definitions with a template, the element is registered via a microtask.

Migration steps

  1. Replace defineAsync() calls with define():

    // Before
    MyElement.defineAsync({
        name: "my-element",
        templateOptions: "defer-and-hydrate",
    });
    
    // After
    MyElement.define({
        name: "my-element",
        templateOptions: "defer-and-hydrate",
    });
  2. Replace composeAsync() calls with compose() and add await:

    // Before
    const def = await FASTElementDefinition.composeAsync(MyElement, name);
    
    // After
    const def = await FASTElementDefinition.compose(MyElement, name);
  3. Replace registerAsync() calls with register():

    // Before
    const el = await FASTElementDefinition.registerAsync(name);
    
    // After
    const el = await FASTElementDefinition.register(name);
  4. Add await to compose() calls that chain .define():

     // Before
     FASTElementDefinition.compose(MyElement, options).define();
    
     // After
     (await FASTElementDefinition.compose(MyElement, options)).define();

Dynamic stylesheet behaviors (v3)

Removed API

Removed Replacement
ElementStyles.withBehaviors() Move the runtime condition into the element and call this.$fastController.addStyles() / this.$fastController.removeStyles() directly.
ElementStyles.behaviors Move any runtime behavior out of the stylesheet and into the element or controller lifecycle.
CSS bindings in css (for example ``css`color: ${x => x.color}```) Move the dynamic value into the element and update classes, attributes, or inline styles from element code.
CSSDirective.createCSS(add) Update directives to implement createCSS() and return only static CSS content.

Changed behavior

  • css and css.partial() no longer compose HostBehaviors.
  • css no longer accepts function or Binding interpolations.
  • ElementStyles is now a fully static style container.

Migration steps

  1. Keep the conditional ElementStyles in a separate css value.
  2. Move the external listener or condition (for example matchMedia() or an app event subscription) into the element lifecycle.
  3. Call this.$fastController.addStyles(styles) when the condition is active and this.$fastController.removeStyles(styles) when it is inactive or during cleanup.
  4. If you previously interpolated bindings or behavior-producing directives into css, replace them with element state and standard DOM or controller updates.