这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情
solid 是一个重编译的开发库,使用到了很多编译时的技巧,但是实际上 solid 对编译的使用也是有限度的,编译时期的转化都集中在了 jsx 的处理上,jsx 之外的东西还是使用了标准的 js 语法,通过提供 API 的方式实现的功能,这部分并没有创建新语法,这些代码放在普通的 js 环境下仍然适用。这里可以对比同样基于编译的框架 svelte,svelte 中使用 行为,这里实际上就相当于创建了一个新的语法,$ 本身在 js 中是没有特殊语义的,这部分代码逻辑就只有在 svelte 的编译上下文中才有意义,脱离了 svelte 之后这是一段无效代码。不过这也看出来一点,一旦你深入掌握编译原理,你完全有可能通过原创语法让代码变成自己想要的样子。在 solid 社区中也出现了一些这类工具,如果你对这方面感兴趣可以了解一下下面这些插件。不过个人还是比较倾向自定义语法使用要适度,否则写出来的语法和 js 就没什么关系了,这样自己舒服对其他人很不友好。
首先是 babel-plugin-solid-labels
,仓库地址位于 github.com/LXSMNSYC/so… ,它的效果就是简化 solid 的写法:
function Counter() {
signal: x = 0;
effect: effectLog: {
console.log('Count', x);
}
computed: computedLog: {
console.log('Count', x);
}
renderEffect: renderEffectLog: {
console.log('Count', x);
}
}
大概可以猜测到对应的功能,在此基础之上还有更精简的:
let x = $signal(0);
$: var y = x + 10;
$: x = compute();
$: {
console.log(x);
}
如果说上面的对象还在 js 的范围内,这里直接就使用 $ 来标记了,这种标签的写法 js 语法中也有,但是几乎没人用,这里也不是用它的本意,说到底就完全可以理解为一种全新的原创语法,写出来的效果确实简洁,是否真的有必要就见仁见智了,这个插件还有很多其他的语法,可以在 readme 中查询到。如果你真的喜欢这样的代码风格可以尝试一下,这种 label 风格的写法更多的应该参考了 svelte 的设计。
接下来是 babel-plugin-solid-undestructure
,可以查看仓库 github.com/orenelbaum/… ,如果说前一个插件更多的只是写起来舒服,这个插件相对就务实很多,他解决的是 solid 中 props 不能结构的问题,前面看过这部分源码,props 本身要作为一个对象适应响应式能力,如果对其直接结构赋值操作会使其失去响应式能力,因此在 solid 开发时操作 props 要格外注意。这个插件旨在通过编译的手段解决这个问题,具体的做法就是在编译期间把我们写的解构赋值语法转回常规取值,对于一些拆分合并操作会编译成 splitProp 和 mergeProps 的调用。使用这个插件倒是可以减轻开发负担,不过前提还是要理解清楚响应式原理,这里是编译器帮忙处理了而不是真的可以这样运行。
下一个看一下 babel-plugin-solid-if-component
,仓库地址 github.com/orenelbaum/… ,这个插件为 babel提供了一个 IF - ELSE 的 jsx 标签,在 solid 中条件是这样写的:
<Show when={hello} fallback={<div>Goodbye</div>}>
<div>Hello</div>
</Show>
这里一部分在子节点里一部分在 fallback 属性中就很不和谐,于是就有人开发了这样的写法:
<If cond={hello}>
<div>Hello</div>
</If>
<Else>
<div>Goodbye</div>
</Else>
至于是否有必要,就看自己的需求了,语法上面的问题没有对与错,这个插件本身不难理解。
最后来看 solid-sfc
,github.com/LXSMNSYC/so… ,这个插件是在 solid-labels
基础之上开发的,这个绝对是一个 svelte 的爱好者开发的,这里直接把原创语法和组件编译发挥到了极致,简单来说就是把 solid 变成 svelte 的写法,感受一下:
// Required for files that do not end in `.solid.(t|j)sx?`
'use solid-sfc';
let count = $signal(0);
let message = $memo(`Count: ${count}`);
effect: {
console.log(message);
};
// Export default is synonymous to "return".
export default <h1>{message}</h1>;
也许会有人更喜欢这种写法吧,毕竟编译的东西想怎么操作就怎么操作,感兴趣可以尝试一下,当然如果你有哪里有自己的想法,不妨也自己去写一套编译工具,自己发明一组语法。
本文介绍的一些插件只是说明充分发挥编译能力是可以有很多可能的,至于如何选择大家自行把握。