- 前端
- UI组件
【免费下载链接】fast
The adaptive interface system for modern web experiences.
本文基于 packages/fast-element/docs/migration/fast-html.md 编写,全面讲解从
@microsoft/fast-htmlv1-alpha 迁移到 v1 时涉及的 hydration 标记格式变更、预渲染内容优化、声明式 API 重组(Schema / ObserverMap / AttributeMap)以及@microsoft/fast-build配套工具的行为调整。读者将掌握:新旧标记格式对照表、删除prepare()/RenderableFASTElement等废弃 API 的替换写法、declarativeTemplate()+attributeMap()+observerMap()的函数式声明式 API 用法,以及attribute-name-strategy等配置项的迁移要点。
一、迁移背景与文档定位
@microsoft/fast-html是 FAST(The adaptive interface system for modern web experiences)生态中负责声明式 HTML(declarative HTML)运行时的早期实验包。进入 v1 阶段后,其声明式能力被正式收编进@microsoft/fast-element的模块化架构中:声明式运行时发布在@microsoft/fast-element/declarative.js,hydration(水合)能力独立为@microsoft/fast-element/hydration.js,映射扩展拆分为@microsoft/fast-element/attribute-map.js与@microsoft/fast-element/observer-map.js。本迁移指南(fast-html.md)记录的就是这一整合过程中的所有破坏性变更与替代方案。
适用前提:以下所有 API 与行为均以当前仓库(FAST v3 分支)的实际源码为准,适用于从@microsoft/fast-htmlv1-alpha 升级到 v1 的开发者;若你的工具链还在解析旧版 hydration 标记或仍在使用RenderableFASTElement、TemplateElement等已移除导出,则本文的迁移步骤直接可落地。
二、Hydration 标记格式(v1-alpha → v1)
2.1 标记格式对照表
v1 简化了 SSR 输出中的 hydration 标记格式。任何检查或生成 hydration 标记的工具都必须更新为使用新格式。新旧格式对照如下(迁移指南原文表格):
| 旧标记 | 新标记 |
|---|---|
<!-- fe-b$$start$$...$$fe-b --> | <!--fe:b--> |
<!-- fe-b$$end$$...$$fe-b --> | <!--fe:/b--> |
<!-- fe-repeat$$start$$...$$fe-repeat --> | <!--fe:r--> |
<!-- fe-repeat$$end$$...$$fe-repeat --> | <!--fe:/r--> |
data-fe-b="0 1 2"/data-fe-b-0/data-fe-c-0-3 | data-fe="N" |
迁移时需注意:
- 新标记不再内嵌索引与 scopeId,SSR 输出体积更小、格式更稳定;
data-fe="N"中的N表示属性绑定数量,取代了旧版以空格分隔的索引列表、逐 factory 枚举、以及"起始索引 + 计数"三种写法;- SSR 与客户端版本必须匹配——旧版 SSR 输出配新版客户端代码(或反之)都会导致解析失败(详见
fast-element-3.md中 "Hydration Marker Format (v3)" 一节,该节记录了fe-eb/fe-eb元素边界标记以及HydrationMarkup.*系列 API 的重命名,如parseAttributeBinding→parseAttributeBindingCount)。
2.2@microsoft/fast-build的配套行为
@microsoft/fast-build的 WASM 二进制会自动产出新格式标记。升级后必须重新构建所有 fixtures 与 SSR 输出。从源码结构看,microsoft-fast-convert(crates/microsoft-fast-convert)承担了声明式模板的语法转换与校验工作:它支持webui-prerelease与fast-v3-ts两个输出目标,并校验输入必须包含恰好一个带非空name的<f-template>与恰好一个内层<template>——这保证了由构建工具产出的 SSR 标记始终符合新格式。
三、预渲染内容优化(v1-alpha → v1)
3.1 已移除导出与概念
| 移除的导出 | 替代方案 |
|---|---|
RenderableFASTElement | 直接继承扩展FASTElement |
| 移除的概念 | 替代方案 |
|---|---|
prepare()生命周期钩子 | 在connectedCallback中设置状态,由响应式系统更新 DOM |
渲染标记中的defer-hydration属性 | ElementController.connect()中的模板待定保护(template-pending guard) |
渲染标记中的needs-hydration属性 | ElementController中的hasExistingShadowRoot检测 |
waitForAncestorHydration() | 不再需要——预渲染内容与连接顺序无关,始终正确 |
这里值得注意的是:从源码看,defer-hydration并未被完全删除,而是以deferHydrationAttribute常量保留在enable-hydration.ts中,用于视口相交(Intersection Observer)场景下的按需 hydration 渲染(源码注释标注为@beta)。而needs-hydration的职责则由ElementController的hasExistingShadowRoot标志接管:当元素带着既有 shadow root 连接时,控制器据此判定走 hydrate 路径而非重新渲染(见element-controller.ts中hasExistingShadowRoot = true的设置与isPrerenderedPromise 的 resolve 逻辑)。
3.2 迁移步骤
步骤 1:RenderableFASTElement→MyComponent.define()+declarativeTemplate()
将RenderableFASTElement(MyComponent).defineAsync({...})替换为MyComponent.define({...}),并在声明式模板场景下使用declarativeTemplate()。如果代码显式观察define()返回的 Promise,它会在匹配的<f-template>提供具体模板之后 resolve:
// 迁移前 import { RenderableFASTElement } from "@microsoft/fast-html"; RenderableFASTElement(MyComponent).defineAsync({ name: "my-component", templateOptions: "defer-and-hydrate", }); // 迁移后 MyComponent.define({ name: "my-component", template: declarativeTemplate(), });步骤 2:移除prepare()方法
将所有初始化逻辑迁移到connectedCallback:
// 迁移前 class MyComponent extends FASTElement { async prepare() { this.data = await fetchData(); } } // 迁移后 class MyComponent extends FASTElement { connectedCallback() { super.connectedCallback(); this.loadData(); } async loadData() { this.data = await fetchData(); } }步骤 3:从服务端渲染标记中移除defer-hydration与needs-hydration
<!-- 迁移前 --> <my-component defer-hydration needs-hydration text="Hello"> <template shadowrootmode="open">...</template> </my-component> <!-- 迁移后 --> <my-component text="Hello"> <template shadowrootmode="open">...</template> </my-component>步骤 4:用$fastController.isPrerendered检测预渲染组件
isPrerendered是一个Promise<boolean>,在连接时若元素带有声明式 shadow root(DSD)则 resolve 为true(无论 hydration 是否实际运行):
connectedCallback() { super.connectedCallback(); this.$fastController.isPrerendered.then(prerendered => { if (!prerendered) { this.fetchData(); } }); }3.3 预渲染优化带来的运行时行为
当 hydration 启用(调用enableHydration())且 FAST 元素连接时带有既有 shadow root,ElementController会检测到并执行 hydrate 而非重新渲染。这带来若干优化(与迁移指南配套的 README 与源码相互印证):
- 用 hydrate 替代 re-render:模板调用
hydrate()将既有 DOM 节点映射到绑定目标,而不是克隆新 DOM; - 声明式模板解析:
declarativeTemplate()会在define()完成前等待匹配的<f-template>,因此已连接的预渲染元素能用具体模板进行 hydrate; - 属性跳过:
onAttributeChangedCallback()在元素预渲染的初次 upgrade 期间跳过处理——服务端已渲染出的属性值是正确的; - 绑定跳过:
HTMLBindingDirective.bind()在视图预渲染时,对attribute与booleanAttribute两种 aspect 跳过updateTarget。
四、Schema、ObserverMap、AttributeMap 模块化
4.1 导入路径变更
配置类型从template.ts迁移到各自所属模块。如果你直接从内部路径导入类型,请更新导入:
| 迁移前 | 迁移后 |
|---|---|
import type { ObserverMapConfig } from "./template.js" | import type { ObserverMapConfig } from "./observer-map.js" |
import type { AttributeMapConfig } from "./template.js" | import type { AttributeMapConfig } from "./attribute-map.js" |
公开的声明式导入现在统一走以下路径:
- 声明式 API:
@microsoft/fast-element/declarative.js(替代@microsoft/fast-html); - 声明式工具函数:
@microsoft/fast-element/declarative-utilities.js(如deepMerge); - 映射扩展:
@microsoft/fast-element/attribute-map.js与@microsoft/fast-element/observer-map.js。
从declarative/index.ts的导出清单可以看到,declarative.js入口汇聚了declarativeTemplate、TemplateParser、Schema、schemaRegistry、各类CachedPath/JSONSchema类型,以及FASTElementDefinition、AttributeDefinition等核心类型。
4.2 Schema 变更
Schema.jsonSchemaMap(静态属性)被替换为:
- 每个
Schema实例上的实例级schemaMap(私有); - 模块级的
schemaRegistry导出,用于跨元素查找。
| 迁移前 | 迁移后 |
|---|---|
Schema.jsonSchemaMap.get('my-element') | import { schemaRegistry } from "@microsoft/fast-element"; schemaRegistry.get('my-element') |
源码印证:在schema.ts中,schemaRegistry被定义为CachedPathMap(Map<string, Map<string, JSONSchema>>),每个Schema实例在构造时将自己注册进该 registry,从而实现跨元素$ref解析(例如嵌套元素的 schema 引用)。
4.3 公开导出一览
公开入口导出函数式声明式 API:
| 导出 | 用途 |
|---|---|
declarativeTemplate() | 为 FAST 元素定义解析<f-template>标记 |
attributeMap() | 定义扩展,自动注册@attr属性 |
observerMap() | 定义扩展,自动深度观察 |
Schema | JSON schema 构建器类 |
schemaRegistry | 跨元素 schema 查找的模块级注册表 |
JSONSchema | JSON Schema 类型接口 |
CachedPathMap | Schema 注册表映射类型 |
4.4declarativeTemplate()的底层行为
从源码看,declarativeTemplate()(template.ts)返回一个FASTElementTemplateResolver,其核心逻辑为:
ensureTemplateElementDefined(definition.registry)——在目标 registry 中惰性定义内部的<f-template>元素(若 registry 中已存在同名元素且不是 FAST 的实现,会抛出错误);- 通过
declarativeTemplateBridge.requestTemplate(definition)等待匹配的<f-template name="...">连接并发布模板; <f-template>在connectedCallback中注册为 publisher;发布时校验内层<template>数量(多于 1 个抛moreThanOneTemplateProvided,0 个抛noTemplateProvided);- 解析 schema(
definition.schema ?? new Schema(name)并回写definition.schema),经TemplateParser解析出strings与values,最终创建ViewTemplate。
如果多个匹配的<f-template>连接,第一个连接的提供模板,后续重复项不会重新赋值。
五、简化后的 ObserverMap 与 AttributeMap 默认行为
显式的ObserverMapOption.all与AttributeMapOption.all常量已移除。现在:
- 无参调用
observerMap()→ 观察所有发现的根属性; - 无参调用
attributeMap()→ 映射所有发现的叶子绑定。
| 迁移前 | 迁移后 |
|---|---|
observerMap(ObserverMapOption.all) | observerMap() |
attributeMap(AttributeMapOption.all) | attributeMap() |
源码层面,ObserverMapConfig与AttributeMapConfig的默认值逻辑如下:
observerMap(observer-map.ts):ObserverMap.defineProperties()遍历schema.getRootProperties(),对每个根属性定义Observable属性与${propertyName}Changed处理器;配置中的properties字段可逐根属性控制观察范围(布尔值或ObserverMapPathNode,$observe控制节点自身是否被观察,缺省时继承最近祖先的取值,根级默认为true)。当属性值从undefined变为对象时,处理器会用代理(Proxy)包装对象并递归注入 observable 访问器;若目标已被代理包装过,则通过deepMerge深合并新值到既有代理中(见observer-map-utilities.ts的assignObservables/deepMerge);attributeMap(attribute-map.ts):AttributeMap.defineProperties()只对叶子属性创建@attr式访问器——即 schema 条目没有嵌套properties、没有type、没有anyOf的属性(如纯{{foo}}绑定)。已存在访问器(来自@attr或@observable装饰器)的属性会被跳过,避免重复定义。
两个扩展在解析顺序上:当二者同时存在时,attribute mapping 先于 observer mapping 运行(源码中attributeMapSchemaTransformPriority = 0,observerMapSchemaTransformPriority = 1,优先级数值越小越先执行)。
六、属性名策略默认值变更
声明式属性映射的默认attribute-name-strategy现在是"camelCase"(此前为"none")。例如绑定键{{firstName}}默认映射到firstName属性与first-nameHTML 属性。若你的模板依赖字面属性名,可以显式恢复旧行为:
import { attributeMap } from "@microsoft/fast-element/attribute-map.js"; MyElement.define( { name: "my-element", template: declarativeTemplate(), }, [attributeMap({ "attribute-name-strategy": "none" })], );源码实现印证:camelToKebab将fooBar转为foo-bar;"none"策略下属性名与属性名均按绑定键原样使用({{foo-bar}}→ 属性foo-bar、属性foo-bar)。属性定义通过AttributeDefinition写入 class prototype 的访问器,并同步更新observedAttributes数组、definition.attributeLookup/propertyLookup与definition.attributes;若定义已注册(isDefined),还会调用trackLateAttributeDefinition追踪迟到的属性定义。
使用@microsoft/fast-build时,请保持服务端与客户端设置一致:
fast build --attribute-name-strategy=none七、声明式 TemplateElement API 移除
公开的声明式 API 已切换为函数式 API。<f-template>的实现变为内部细节,由declarativeTemplate()自动定义,使用者不应直接导入或定义它。
| 移除项 | 替代方案 |
|---|---|
TemplateElement公开导出 | 每个 FAST 元素定义上的declarativeTemplate() |
TemplateElement.define({ name: "f-template" }) | 无需手动定义;declarativeTemplate()在目标 registry 中定义内部 publisher |
TemplateElement.config(callbacks)/HydrationLifecycleCallbacks | enableHydration().whenHydrated(tagName)(按标签等待 hydration)与enableHydration().whenHydrated()(等待当前活跃 hydration 批次) |
TemplateElement.options({ "my-el": { attributeMap, observerMap } }) | 定义扩展:MyElement.define(definition, [attributeMap(...), observerMap(...)]) |
ElementOptions/ElementOptionsDictionary | 无替代 |
旧声明式公开面中的AttributeMap/ObserverMap类导出 | attributeMap()/observerMap()扩展辅助函数及其配置类型 |
Hydration 也不再由@microsoft/fast-element自动安装。当需要复用预渲染的声明式 Shadow DOM 时,必须在 FAST 元素连接之前调用enableHydration()(从@microsoft/fast-element/hydration.js导入)。源码印证(enable-hydration.ts):enableHydration()通过ElementController.installHydrationHook安装 hook,hook 会调用模板的hydrate()映射既有 DOM 节点,并设置isPrerendered/isHydrated两个 Promise;函数可被多次安全调用,后续调用会把 options 合并进共享的 tracker,且默认在初始批次完成后停止对新的预渲染元素进行 hydration——对于流式追加 DSD 的场景,可用stopHydration: StopHydration.never保持 hook 活跃(此模式下whenHydrated()会因 hydration 永无全局完成点而有意保持 pending)。
八、Schema 驱动的映射与可选定义 Schema
attributeMap()与observerMap()现在是由 schema 驱动的扩展,且与声明式模板解耦,声明式与非声明式场景均可从@microsoft/fast-element导入:
import { attributeMap } from "@microsoft/fast-element/attribute-map.js"; import { observerMap } from "@microsoft/fast-element/observer-map.js";FASTElementDefinition.schema现在是可选的。declarativeTemplate()在解析<f-template>标记时会自动为其赋值。手动使用 schema 的开发者可以在元素定义中传入 schema,observerMap()也可以在配置中直接接收 schema:
import { FASTElement, Schema } from "@microsoft/fast-element"; import { observerMap } from "@microsoft/fast-element/observer-map.js"; class MyElement extends FASTElement {} const schema = new Schema("my-element"); schema.addPath({ rootPropertyName: "user", pathConfig: { type: "default", parentContext: null, currentContext: null, path: "user.name", }, childrenMap: null, }); MyElement.define({ name: "my-element" }, [observerMap({ schema })]);源码印证:Schema.addPath(schema.ts)根据pathConfig.type(default/access/repeat/event)与childrenMap(子元素引用,生成anyOf的$ref)在根属性 schema 中构建properties、$defs与上下文信息。observerMap扩展在无 template resolver 时直接消费config.schema ?? definition.schema定义观察者;若两者都缺失则抛出错误,提示使用observerMap({ schema })、在元素定义上提供 schema 或改用declarativeTemplate()。
九、迁移检查清单
完成@microsoft/fast-htmlv1-alpha → v1 迁移后,建议逐项核对:
- hydration 标记:所有 SSR fixtures 与输出均由
@microsoft/fast-build重新生成,标记为<!--fe:b-->/<!--fe:r-->与data-fe="N"格式;SSR 与客户端版本一致; - 导出替换:
RenderableFASTElement→ 继承FASTElement;TemplateElement/ElementOptions不再使用;Schema.jsonSchemaMap→schemaRegistry; - 生命周期:
prepare()逻辑迁移至connectedCallback;不再调用waitForAncestorHydration(); - 标记清理:SSR 标记中移除
defer-hydration与needs-hydration(defer-hydration仍保留为deferHydrationAttribute常量,仅用于视口相交按需渲染场景); - 扩展默认行为:
observerMap(ObserverMapOption.all)→observerMap();attributeMap(AttributeMapOption.all)→attributeMap(); - 属性名策略:确认
attribute-name-strategy期望为camelCase(默认)还是none,并保持@microsoft/fast-build与客户端配置一致; - hydration 显式启用:需要复用预渲染 DSD 时,在元素连接前调用
enableHydration();流式场景使用StopHydration.never,诊断场景可传入hydrationDebugger()。
十、进一步阅读
- 迁移指南:
@microsoft/fast-elementv2 → v3(含 v3 hydration 标记格式的完整 API 变更) - README:FAST Element v3 的声明式 HTML、预渲染优化与 define 扩展用法
- 声明式模板语法与实现细节
- 声明式运行时源码入口
declarativeTemplate()与<f-template>实现- Schema 构建与
schemaRegistry - ObserverMap 扩展实现
- AttributeMap 扩展实现与属性名策略
enableHydration()与 hydration hook 安装@microsoft/fast-build的语法转换工具microsoft-fast-convert
- 前端
- UI组件
【免费下载链接】fast
The adaptive interface system for modern web experiences.
相关推荐
nnU-Net V1 迁移指南(TLDR):从 Task 到 Dataset、从 `nnUNet_` 到 `nnUNetv2_` 的完整升级路径
nnU Net V1 迁移指南(TLDR):从 Task 到 Dataset、从 nnUNet_ 到 nnUNetv2_ 的完整升级路径 导读 本文是 nnU
人工智能深度学习计算机视觉医疗健康@microsoft/fast-element v3 迁移指南:从导入路径、声明式模板到水合标记的完整升级路线
@microsoft/fast element v3 迁移指南:从导入路径、声明式模板到水合标记的完整升级路线 本篇指南系统讲解 @microsoft/fast
前端UI组件node-fetch API版本迁移终极指南:从v1到v3的完整升级路径
node fetch API版本迁移终极指南:从v1到v3的完整升级路径 node fetch作为将浏览器Fetch API引入Node.js的轻量级模块,在v
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考