Rollup作者新作: Svelte Cubed, 擁抱 Three.js !

程式設計師秋風發表於2021-12-13

在2021年11月20日,Svelte 召開了第四次虛擬會議。

image-20211130233913710

而會議中最令我眼前一新的當然是 輪子哥 Rich-Harris 帶來的 Svelte Cubed 了。

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

image-20211130234212172

這個專案亮眼的地方,並不是因為其他的演講者不好,也並不是因為輪子哥是 Svelte 作者的原因。而是因為他帶來的 Svelte-Cubed 和我目前在公司負責專案的技術棧有非常相似的感覺。在公司由於需要開發一個 新 的 H5 專案,因此我採用了較為激進的 Svelte + Aframe/Three.js + Tailwind.css + Vite 的組合。整套組合下來,無論是開發體驗還是最後生產包的體積都非常的美妙~ 因此當我看到 輪子哥釋出這個 新輪子 的時候,我無比激動,居然把我想要的組合直接整合到了 Svelte

然後我們來看看 Svelte-Cubed 面貌:

開啟 https://svelte-cubed.vercel.app/ ,目前官網沒有用自定義的域名,直接用了 vercel 的域名,猜測和 輪子哥去了 vercel 工作有關係。

image-20211201000056451

我們來看看 cubed 官方的一些示例:

2021-12-01-13.24.37

實戰

我們來嘗試一下自己寫一個專案,首先初始化一個 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

image-20211201134014871

然後就報錯了,通過查詢,大概是因為沒有設定一個 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;

image-20211201135911003

我們的專案就被執行起來了。

官方也明確說了,不會對 Three.js 物件進行包裝,而是直接使用 Three.js 去建立並設定物件,因此需要在程式碼中引入 Three.js ,(個人感覺這樣的好處是能夠讓我們沒有成本地從其他非資料驅動的 Three.js 專案中,遷移到 Svelte-cubed 中)。

可以看到如果用 純 Three.js 去寫程式碼,將會比用 Svelte-Cubed 多出好幾倍的內容。隨著時間的推移,命令式程式碼也會變得不太容易維護。

image-20211201135223933

通過新增控制器,我們可以輕鬆進行互動。

開啟 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>

2021-12-01-13.55.11

利用 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>

2021-12-01-13.59.53

利用資料驅動,動畫也可以快速新增。

<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>

2021-12-01 14.01.35

總結

不過隨著 Svelte-Cubed 的釋出,也有不少的質疑,也有人認為這個東西並沒有是真正意義上的"創造新事物",而只是編寫了一些膠水層程式碼。

image-20211201140408397

RH 也親自進行了回覆

image-20211201140446689

簡而言之,你使用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/s...

https://twitter.com/SvelteSoc...

https://svelte-cubed.vercel.a...

https://github.com/Rich-Harri...

https://news.ycombinator.com/...

結語

❤️關注+點贊+收藏+評論+轉發❤️ ,原創不易,鼓勵筆者創作更好的文章

關注公眾號秋風的筆記,一個專注於前端面試、工程化、開源的前端公眾號

相關文章