跑分方面,這款 JavaScript 庫在全球框架榜單中的表現比 React 要好得多
2021 年 11 月 左右,Strve 第一個版本發布,社區的反饋大部分是支持,也有少部分小伙伴提出了質疑,這都正常。你只要在社區發布一些作品,就必須接受其他人對你的作品的評價。
當初,開發 Strve 的初衷只是受到 JSX 語法的影響,覺得在 JavaScript 中編寫 HTML 很酷,所以想能不能自己也開發一個前端框架。我最初給自己的目標就是能在 JavaScript 中寫 HTML,然后通過編寫 JavaScript 來改變頁面狀態。經過兩個多周的調研,發現自己在原地打轉。JSX 語法不能直接在瀏覽器運行,你必須通過類似 Babel 這種編譯工具編譯才能運行。所以,我就打算在模版字段串內編寫 HTML。但是,又遇到了另一個問題,如何精確更新 DOM。當時,第一個想法就是利用虛擬 DOM,所以就抽時間來學習前端框架中都是怎么利用虛擬 DOM 來精確更新。不懂得就去網上查資料,然后就記下來。可能有些小伙伴就會問,是什么力量讓你去做可能完成了也沒什么意義的事情。怎么說呢!當時,我就是想要做出點東西來,覺得自己能做出來。至于做出來有什么意義,我沒有多想。有時候我們做一件事情之前,考慮很多未必是好事,這往往會阻礙了我們做事情的腳步。
就這樣,靠著自己的熱情,第一個版本就這么問世了。
有很多小伙伴感覺 Strve 寫法很像lit-html。說實話,開發 Strve 之前,我并不知道這個框架。后來看社區反饋,才到網上查看了有關的資料。雖然寫法像,但并不是它的復制品。就比如 Strve 內部使用的是虛擬 DOM,這時的虛擬 DOM 還只是一個初版,只能說是簡單的比對。
全新的認識
之前有看過我的文章的小伙伴,多多少少會知道 Strve。但是可能也只是停留在知道這個層面上,現在我通過幾點來重新介紹下 Strve。
Strve 是一個易用、快速、靈活且輕量級的 JavaScript 庫,用于構建用戶界面。基于 tagged template 的 HTML 模板引擎,利用 ES6 的模板字符串來進行模板的書寫,利用瀏覽器的原生的能力進行模板渲染。
- 更容易上手:只要你對 HTML、CSS 和 JavaScript 已經基本熟悉,就可以直接上手。
- 聲明式渲染:我們可以聲明式地描述最終輸出的 HTML 和 JavaScript 狀態之間的關系,開發者可以更加專注于業務邏輯的開發,不需要過多地關心 DOM 操作的細節。
- 順滑的用戶體驗:模板字符串來進行模板的書寫,在一些場景中代碼智能提示、代碼格式化方面不是特別友好。所以,我們提供了新的一種編碼方式,我們可以使用 JSX 語法編寫 Strve,提升用戶開發體驗。
- 性能出色:采用了虛擬 DOM 的模式,虛擬 DOM 使用 diff 算法的方法來計算出真正需要更新的節點,最大限度地減少了 DOM 操作以及 DOM 操作帶來的排版與重繪損耗,從而顯著提高了性能。另外,我們的 JavaScript 庫在全球知名的測評榜單(js-framework-benchmark)上贏得了優秀的成績。
- 組件化:一個函數就是一個組件,可以根據應用規模任意組合。并且組件特有的 “孤島特性”,使得將虛擬 DOM 樹計算的級別控制在組件級別。
- 靈活的應用場景:有無構建工具都可以使用,并且可以適配到其他前端框架開發的應用項目中去。
- 輕量級:壓縮后的文件大小不足 10k。另外,可以根據不同應用場景,選擇不同類型的文件。
想要了解更多關于 Strve 的特性,可以到官方中文文檔中去探索。
https://strvejs.gitee.io/strve-doc-zh。
貼心的優化
2023 年我陸續發布了幾個大的版本,大部分時間都是在優化底層代碼。包括虛擬 DOM 的算法優化、減輕使用 API 時 心智負擔等等優化措施。
下面我們來展開看下。
如果你不打算使用構建打包工具開發項目,而是直接開發。推薦使用全局構建版本,通過 CDN 使用 Strve 時,不涉及“構建步驟”,這使得設置更加簡單。
<script src="https://cdn.jsdelivr.net/npm/strve-js@6.6.6/dist/strve.full.prod.js"></script>
<script>
const { html, defineComponent } = Strve;
defineComponent(
{
mount: '#app',
},
({ setData }) => {
let count = 0;
function add() {
setData(() => {
count++;
});
}
return () => html`<h1 onClick=${add}>${count}</h1>`;
}
);
</script>
模板字符串來進行模板的書寫,在一些場景中代碼智能提示、代碼格式化方面不是特別友好。所以,我們提供了一種新的編碼方式,我們可以使用 JSX 語法編寫 Strve 應用,這樣就大大提升了用戶開發體驗。
defineComponent(() => {
const state = {
msg: 'Hello',
};
return () => h1>{state.msg}</h1>;
});
另外,我們底層采用了虛擬 DOM 的模式,虛擬 DOM 使用 diff 算法的方法來計算出真正需要更新的節點,最大限度地減少了 DOM 操作以及 DOM 操作帶來的排版與重繪損耗,從而顯著提高了性能。
Strve 應用程序是由 組件 組成的。一個組件是 UI(用戶界面)的一部分,它擁有自己的邏輯和外觀。組件可以小到一個按鈕,也可以大到整個頁面。
在 Strve 中,組件就是一個函數。
const MyComponent = defineComponent(({ setData }) => {
let count = 0;
function add() {
setData(() => {
count++;
});
}
return () => (
<div class='MyComponent'>
<p>{count}</p>
<button onClick={add}>MyComponent</button>
</div>
);
});
// 復用組件
defineComponent(
{
mount: '#app',
},
({ setData }) => {
let count = 0;
const add = () => {
setData(() => {
count++;
});
};
return () => (
<div class='App'>
<p>{count}</p>
<button onClick={add}>App</button>
<component $is={MyComponent} />
</div>
);
}
);
Strve 內部的渲染系統是基于虛擬 DOM 構建的,虛擬 DOM (Virtual DOM,簡稱 VDOM) 是一種編程概念,意為將目標所需的 UI 通過數據結構“虛擬”地表示出來,保存在內存中,然后利用 Diff 算法來比對新老數據,將真實的 DOM 與之保持同步。
如何虛擬 DOM 樹過于龐大,使得 Diff 計算時間大于 16.6ms,那么就可能造成性能的卡頓。組件有一個特性就是 ”孤島“。何為“孤島”,孤島就是在 Strve 應用中我們可以理解成一個獨立的模塊。將一個龐大的虛擬 DOM 樹分解成很多獨立的模塊,這樣 Diff 計算時間就會控制在組件級別,大大縮減了計算的時間,提高了性能。
從 API 層面,我們盡可能的貼合易用的特性,將核心 API 縮減為 2 個。分別為defineComponent和setData。框架是需要容易使用的,太多繁瑣的設置或者操作很容易增重心智負擔。
豐富的生態
開發框架單單只有一個核心庫肯定是不夠的,你還需要其他生態工具來加以輔助。
你要有一套用于快速構建項目的命令行工具,也就是說用戶可以通過輸入命令快速搭建項目。CreateStrveApp 是一套用于快速構建 Strve 項目的命令行工具。CreateStrveApp 是使用 Vite 構建的,這是一個新的前端構建工具,可以顯著提升前端開發體驗。它有幾個模版可供選擇:strve、strve-apps、strve-jsx、strve-jsx-apps。
我們開發項目需要跳轉多個頁面,那么就需要路由管理器。StrveRouter 是 Strve 的官方路由管理器。它與 Strve 的核心深度集成,輕松構建單頁應用程序。
另外,我們介紹兩款編譯時工具。BabelPluginStrve是一款 babel 插件,將 HTML 模板字符串轉化為 Virtual Dom。從之前的運行時轉移到編譯時,大幅度提高渲染性能。如果你想使用 JSX 語法,BabelPluginJsxToStrve這款插件是必不可少的,它是一款 babel 插件,將 JSX 轉換為與 Strve 一起使用的標記模板。CreateStrveApp 項目腳手架工具已默認安裝,選擇 strve-jsx 或者 strve-jsx-apps 模版即可。我們使用 CreateStrveApp 搭建完 Strve 項目你會發現,同時安裝了 BabelPluginStrve、BabelPluginJsxToStrve,這是因為我們需要使用 BabelPluginJsxToStrve 將 JSX 轉換為標簽模版,之后再使用 BabelPluginStrve 將標簽模版轉換為 Virtual DOM。
我們最后壓軸的一款生態工具可以說是近期更新力度最大的了。它被稱為獨立運行的可響應性 Strve,由 @vue/reactivity和 strve-js 提供支持的自定義元素 JavaScript 庫。
主要特性有以下幾個:
- Web Components
- Hooks
- Reactivity API
- Props
- Emit
- Slot
- Styles
- Automatic registration component
- Virtual DOM
Strve 結合 Vue 組合式 API 形成了一款新的 JavaScript 庫。只要你熟悉組合式 API,就可快速上手。
// MyComponent.jsx
import { ref, defineComponent, reactive } from 'strve-reactivity';
const MyComponent = defineComponent(() => {
const items = reactive([
{
id: 1,
tit: 'A',
},
{
id: 2,
tit: 'B',
},
]);
const count = ref(4);
const increase = () => {
items.unshift({
id: count.value++,
tit: 'C',
});
};
return () => (
<fragment>
<button onclick={increase}>increase</button>
<ul>
{items.map((item) => (
<li key={item.id}>
<span>{item.id}</span>
<span>-</span>
<span>{item.tit}</span>
</li>
))}
</ul>
</fragment>
);
});
出色的跑分
我們只是口頭說 Strve 性能是非常不錯的,沒有真憑實據那是說不過去的。跑分方面,Strve 在 js-framework-benchmark 中的表現比 React 要好得多。
https://krausest.github.io/js-framework-benchmark/current.html。
巨人的肩膀
前端框架最近幾年來層出不窮,出現這種情況好嗎?我覺得是個好現象。大家都在為前端社區貢獻自己的力量,使得前端的生態生機勃勃。
大家可能非常討厭跟知名框架比較,可能有些人會說蹭熱度。其實不妨換個角度想想,為什么會比較,是因為要更好。怎么樣才能更好,那只能不斷地優化。那么在這優化的過程中你不光是做出一個 JavaScript 庫或者前端框架,更多的是你可以從中獲得你在平時工作中得不到的東西。比如,對設計一款框架需要考慮哪些方面。作者在設計 API 時為什么會這么設計等等一些非工作業務上的事情。
我開發這款 JavaScript 庫,我是另辟蹊徑嗎?我感覺并不是,我只是學習其他優秀框架中可以借鑒的思想,并按照自己想要的方式去展現它。只有站在巨人的肩膀上才能望得更遠!