在2021年11月20日,Svelte 召开了第四次虚拟会议。

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_数据驱动

而会议中最令我眼前一新的当然是 轮子哥 ​Rich-Harris​ 带来的 ​Svelte Cubed​ 了。

科普:轮子哥 Rich-Harris:Svelte、Rollup 作者

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_函数式_02

这个项目亮眼的地方,并不是因为其他的演讲者不好,也并不是因为轮子哥是 Svelte 作者的原因。而是因为他带来的 ​Svelte-Cubed​ 和我目前在公司负责项目的技术栈有非常相似的感觉。在公司由于需要开发一个 新 的 H5 项目,因此我采用了较为激进的 Svelte + Aframe/Three.js + Tailwind.css + Vite 的组合。整套组合下来,无论是开发体验还是最后生产包的体积都非常的美妙~  因此当我看到 ​轮子哥​发布这个 ​新轮子​ 的时候,我无比激动,居然把我想要的组合直接集成到了 ​Svelte​ 。

然后我们来看看 ​Svelte-Cubed​ 面貌:

打开 https://svelte-cubed.vercel.app/ ,目前官网没有用自定义的域名,直接用了 vercel 的域名,猜测和 轮子哥去了 vercel  工作有关系。

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_数据驱动_03

我们来看看 cubed 官方的一些示例:

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_数据驱动_04

实战

我们来尝试一下自己写一个项目,首先初始化一个 svelte 项目

npm init svelte@next my-new-app
cd my-new-app
npm install
npm run dev

安装 Three.js 和 svelte-cubed

npm install three svelte-cubed

如果使用 TypeScript ,还需要引入 Three.js 的 ts 声明

npm install -D @types/three

打开 ​​src/routes/index.svelte​

<script>
import * as THREE from 'three';
import * as SC from 'svelte-cubed';
</script>

<SC.Canvas>
<SC.Mesh geometry={new THREE.BoxGeometry()} />
<SC.PerspectiveCamera position={[1, 1, 3]} />
</SC.Canvas>

然后运行 ​​npm run dev​

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_数据驱动_05

然后就报错了,通过查询,大概是因为没有设置一个 vite 选项。

打开 ​​svelte.config.js​​ ,加入关旭 vite ssr 的选项即可解决。

import adapter from '@sveltejs/adapter-auto';

/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter(),

// hydrate the <div id="svelte"> element in src/app.html
target: '#svelte',
vite: {
ssr: {
noExternal: ["three"]
}
}
}
};

export default config;

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_twitter_06

我们的项目就被运行起来了。

官方也明确说了,不会对 Three.js 对象进行包装,而是直接使用 Three.js 去创建并设置对象,因此需要在代码中引入 Three.js ,(个人感觉这样的好处是能够让我们没有成本地从其他非数据驱动的 Three.js 项目中,迁移到 Svelte-cubed 中)。

可以看到如果用 纯 Three.js 去写代码,将会比用​​Svelte-Cubed​​ 多出好几倍的内容。随着时间的推移,命令式代码也会变得不太容易维护。

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_数据驱动_07


通过添加控制器,我们可以轻松进行交互。

打开 ​​src/routes/index.svelte​

<SC.Canvas antialias background={new THREE.Color('papayawhip')}>
<SC.Mesh geometry={new THREE.BoxGeometry()} />
<SC.PerspectiveCamera position={[1, 1, 3]} />
+ <SC.OrbitControls enableZoom={false} />
</SC.Canvas>

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_函数式_08

利用 Svelte 的数据驱动轻松修改 Three.js Objects.

<script>
import * as THREE from 'three';
import * as SC from 'svelte-cubed';
+
+ let width = 1;
+ let height = 1;
+ let depth = 1;
</script>

<SC.Canvas antialias background={new THREE.Color('papayawhip')}>
<SC.Mesh
geometry={new THREE.BoxGeometry()}
material={new THREE.MeshStandardMaterial({ color: 0xff3e00 })}
+ scale={[width, height, depth]}
/>
<SC.PerspectiveCamera position={[1, 1, 3]} />
<SC.OrbitControls enableZoom={false} />
<SC.AmbientLight intensity={0.6} />
<SC.DirectionalLight intensity={0.6} position={[-2, 3, 2]} />
</SC.Canvas>

+<div class="controls">
+ <label><input type="range" bind:value={width} min={0.1} max={3} step={0.1} /> width</label>
+ <label><input type="range" bind:value={height} min={0.1} max={3} step={0.1} /> height</label>
+ <label><input type="range" bind:value={depth} min={0.1} max={3} step={0.1} /> depth</label>
+</div>
+
+<style>
+ .controls {
+ position: absolute;
+ }
+</style>

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_函数式_09

利用数据驱动,动画也可以快速添加。

<script>
import * as THREE from 'three';
import * as SC from 'svelte-cubed';

let width = 1;
let height = 1;
let depth = 1;
+
+ let spin = 0;
+
+ SC.onFrame(() => {
+ spin += 0.01;
+ });
</script>

<SC.Canvas antialias background={new THREE.Color('papayawhip')}>
<SC.Mesh
geometry={new THREE.BoxGeometry()}
material={new THREE.MeshStandardMaterial({ color: 0xff3e00 })}
scale={[width, height, depth]}
+ rotation={[0, spin, 0]}
/>
<SC.PerspectiveCamera position={[1, 1, 3]} />
<SC.OrbitControls enableZoom={false} />
<SC.AmbientLight intensity={0.6} />
<SC.DirectionalLight intensity={0.6} position={[-2, 3, 2]} />
</SC.Canvas>

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_数据驱动_10

总结

不过随着 Svelte-Cubed 的发布,也有不少的质疑,也有人认为这个东西并没有是真正意义上的"创造新事物",而只是编写了一些胶水层代码。

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_函数式_11

RH 也亲自进行了回复

Rollup作者新作: Svelte Cubed!VR/AR 指日可待?_数据驱动_12


简而言之,你使用Svelte Cubed的原因与你使用Svelte(或任何组件框架)本身的原因相同:声明性代码往往比指令性代码更健壮、更易读、更易维护。直接使用Three绝对没有错,但这相当于直接使用DOM。在某种程度上,很难跟踪没有被表达为层次结构的层次关系,而且管理整个应用程序的状态也成为一种负担。

此外,由于组件有一个可管理的生命周期,如果你使用Vite(或使用Vite的SvelteKit)这样的框架,你可以 "免费 "获得热模块重载这样的东西。一旦你尝试过用这种方式构建场景(例如,在你调整你所放大的物体的属性时保持你的相机位置),Cmd-R驱动的开发就会感觉很苍白了。  ——由 deepl.com 翻译



额外说明:声明式与函数式的区别,创建 div为例:​1.声明式写法​​<div></div>​​​2.函数式写法 ​​document.createElement('div');​

不过个人感觉,Svelte-Cubed 带来了以下优点

1.声明式带来的层级清晰

2.数据驱动能够带来遍历(写起来比 Three.js 快很多)

3.组件没有非常庞大的情况下,它的体积还非常的小(相比 React、Vue 需要引入一整个运行时就小很多)

既然 Svelte-Cubed 已经融合了 Three.js ,在 meta 概念崛起的年代,离 VR/AR 还会远吗?(事实上只要融合了 Three.js ,使用 Three.js 的生态来写 VR 就已经非常容易了)

最后再列几个在VR/AR 领域比较优秀的框架吧(如果大家对这方面感兴趣),aframe(与 Svelte 异曲同工之妙的声明式),react-three-fiber、babylon.js 。

参考

https://twitter.com/opensas/status/1464457228581326848

https://twitter.com/SvelteSociety/status/1463248727942971396

https://svelte-cubed.vercel.app/docs/getting-started

https://github.com/Rich-Harris/svelte-cubed

https://news.ycombinator.com/item?id=29310150