构建
从 React 移植
把现有的 React 界面带到 NoWayOS:用 Screen Compiler 的覆盖率报告衡量它,看清哪些照原样转换、哪些需要修改、哪些移到您的应用中,并读懂它可能给出的每一种错误。
您不必从头再来。一个 React 屏幕的大部分照写的样子就能转换:布局、文本、按钮和字段、条件和列表,还有它自己的小组件。其余的要么是简短的改写,要么是移到您的应用中的工作;在只做一件事的计算机上,那里本来就是它该在的地方。
先测量
改动任何一行之前,先问问 Screen Compiler 您的代码已经能走多远。把您的应用克隆到用 React 制作屏幕中那两个仓库的旁边,让开发容器能看到它,然后对它的源代码运行覆盖率报告:
cd nowayos-work # holds nowayos and screen-compiler
git clone https://example.com/your-app.git my-app
cd screen-compiler
make run ARGS="audit ../my-app/src"
报告读取该文件夹下的每个 .tsx 文件,并统计找到的每种语法结构:元素、props、样式属性、hooks、列表、条件、运算符和导入。每一种都会得到一个判定:
- 在子集内:按子集允许的方式使用时即可转换;
- 在路线图上:暂时还不能转换,报告会指出将来转换它的步骤;
- 按设计排除:永远不会转换,报告会说明原因;
- 未知:Screen Compiler 无法识别。未知的结构从不算作已转换。
接着列出路线图的各个步骤以及每一步被需要的次数,然后是每个文件的结果。只有 check 通过的文件才算"可以转换",所以顶部的数字就是真实的数字。报告只列出结构的名称,从不引用您的代码,因此可以放心分享。与编译器本身一样,只在您信任的代码上运行它。
什么对应什么
| 在 React DOM 中 | 在子集中 |
|---|---|
用 flexbox 布局的 <div> |
<Column> 或 <Row>,配合 gap、padding 和声明过的 style |
<h1>、<p>、<span>、<label> |
带角色的 <Text>:title、heading、body、label、caption 或 display |
<button onClick={…}> |
<Button onClick={props.onSave}>:回调 prop 会变成一个动作 |
<input>、复选框、单选按钮、<select> |
<TextInput>、<Checkbox>、<RadioGroup>、<Select>,各有一个 id,应用通过它读取和设置值 |
{ready && <X/>}、? :、!ready、step === "review" |
由应用设置的组和开关 |
items.map(…) |
行:文件中所含的列表,或截取到上限的 prop 列表,props.items.slice(0, 5) |
Hello, {name}! |
把固定文字编译进去,围在应用填充的插槽两侧 |
| 您自己的组件和片段,在屏幕的文件中或其旁边的文件中 | 在构建时展开,如同把屏幕平铺写出 |
style={{ padding: "16px" }}, color: "var(--text-muted)" |
声明过的样式属性,长度以布局单位计,颜色使用主题颜色 |
用 React 制作屏幕中的表格准确列出了每个组件接受什么。这些表格来自 Screen Compiler 自己的表,因此不会与它实际接受的内容脱节。
哪些移到您的应用中
设备上没有 JavaScript。屏幕是一棵固定的树,由您的应用通过编号的动作、字段、插槽、组和开关来驱动。所以有些东西按设计排除在外,各有原因:
- 状态和 hooks(
useState、useEffect、context)。状态由应用持有,并由应用设置屏幕显示的内容。 - 字段的
value、checked和onChange。 应用通过字段的id读取和设置它。 - 展开(spread)的 props。 其中有什么,要到代码运行时才知道。
- 计算出来的样式、颜色值和全局样式表。 样式是静态的;颜色使用主题颜色,这样大字主题才能为每个屏幕重新配色,对比度也会被检查;而且没有层叠。
- 动画。
- 没有上限的列表。 用
.slice(0, 5)截取它,让屏幕知道最多能显示几行。 - 除"prop
===字符串"以外的比较,以及屏幕函数中的if或switch。 在应用中算出结果,再作为 prop 传入。 - 来自软件包的组件,以及屏幕文件夹之外的文件。 屏幕只读取它自己的文件夹及其中的内容:把您的组件放在它旁边,
./parts/header。 - 除了调用一个 prop 还做别的事的处理函数。
onClick={() => props.onSave()}可以转换;其余的都是应用的工作。
路线图接下来带来什么
当您的代码需要时,覆盖率报告会指出以下计划中的步骤:
- 更多 CSS 布局:flex 伸展、
alignSelf、最小和最大高度、各边的内边距以及外边距; - 常见的 HTML 元素,每一种按一条固定规则对应;
- CSS 模块,每个元素一个类;
- 分层:彼此叠放的元素;
- 图片和遮蔽输入。
在某个步骤落地之前,它所涉及的结构会被拒绝,而不是被猜测。每一步都遵守同一条规则:要么精确,要么不做。
读懂错误
错误会给出文件、行和列,一个代码,出了什么问题,以及一行帮助:
web-search.tsx:16:28: error[unknown-name]: `query` is not a prop of the component
help: text from the application must be a prop: take it as one, function Screen({ query }) { … }
只要有错误,就什么也不会写出。这些代码是:
| 代码 | 含义 | 怎么做 |
|---|---|---|
syntax |
文件不是有效的 TSX,或违反了每个模块都遵守的规则。 | 在给出的位置修正代码。 |
unsupported |
子集之外的结构。 | 按帮助操作:在子集内改写它,或把这项工作移到应用中。 |
unknown-element |
不属于套件、或没有导入的元素。 | 从 "nowayos:kit" 导入它,或改用套件的元素。 |
unknown-prop |
元素不接受的 prop 或样式属性。 | 使用表格为它列出的那些。 |
invalid-value |
元素接受的 prop,却给了它不接受的值。 | 给出表格所列类型的值。 |
missing-prop |
缺少元素必需的 prop。 | 补上它:表格中以粗体显示这些 prop。 |
invalid-children |
元素包含了它不能包含的内容,例如 <Screen> 中有两个子元素,或 <Column> 中有文本。 |
把它们包起来,或把文本放进 <Text>。 |
unknown-name |
既不是 prop、设计令牌,也不是导入的名称。 | 把它作为 prop 接收,或声明它。 |
duplicate-name |
两样东西在生成的代码中会得到同一个名称,例如 isReady 和 is_ready。 |
重命名其中一个。 |
reserved-name |
Rust 或生成的代码为自己保留的名称,例如 type。 |
重命名它。 |
limit |
超出了大小、深度或数量的限制。 | 缩短它,或拆分成组件。 |
no-screen |
文件中没有屏幕组件,即返回 <Screen> 的函数。 |
导出一个。 |
internal |
Screen Compiler 自身的缺陷。 | 附上引发它的输入,报告它。 |
如果您需要的结构还在路线图上、尚未实现,请附上报告告诉我们:它能显示哪些步骤最重要。