本系列的前一篇文章(對 React 的非常溫和的介紹)向讀者介紹了用於開發 Web 應用程式的優秀 React 框架系統。 SvelteKit 是一個替代框架。它與 React 有什麼不同,有什麼更好的地方嗎?
從功能上來說,我想沒有太大差別。在 React 中可以做的大多數事情也可以在 SvelteKit 中完成。反之亦然。但當你深入細節時,很多人認為 SvelteKit 在輕鬆實現「響應式」目標方面具有優勢。 Svelte 的意思是「優雅」——這正是它的本質——一種纖細、適應性強且實用的工具。
就我個人而言,我被SvelteKit 所吸引,因為它還傾向於推動您進行伺服器端設計- 即在Web 應用程式的雲端伺服器上運行的程式碼,而不是在用戶的Web 瀏覽器中運行。這很諷刺,因為編寫和調試客戶端程式碼的便利性最初讓我對 Web 應用程式開發著迷。但後來我發現索引蜘蛛是多麼不願意投入精力來「滋潤」客戶端程式碼,並意識到我只需要在這裡投入更多的精力(請參閱下面的SvelteKit 中的調試,看看會帶來什麼) 。但您也可能考慮使用伺服器端程式碼還有其他原因。這裡有一些:
一旦您開始使用 Postmark(電子郵件發送)或 Paypal(收款)等第三方服務,您就會意識到將其安全代碼包含在客戶端程式碼中並不是一個好主意。如果您可以使用「檢查器」來查看這些內容,那麼其他人也可以。運行伺服器端的程式碼無法存取。
伺服器端程式碼距離您的資料更近,並且在這裡比在客戶端筆記型電腦上運行得更快。
SvelteKit 可以輕鬆地播放音樂,指定 Web 應用程式的哪些部分要本地運行,哪些部分要遠端運行。
讓我們開始討論更具體的事情。
從外部來看,Sveltekit Web 應用程式看起來與任何經典瀏覽器應用程式完全相同 - “頁面”的層次結構,例如 mywebapp/dosomethingwithmyfiles。之所以會這樣,是因為客戶端使用者期望並依賴這種類型的安排。但在表面之下,SvelteKit Web 應用程式以與 React Web 應用程式完全不同的方式提供這種安排。在React 中,這些頁面實際上是一大堆程式碼的所有部分,並且請求透過在Web 介面上操作的重定向來路由到那裡(如果這句話對您來說沒有任何意義,請看看什麼是「單-」)頁的網頁應用程式? )。 SvelteKit 透過使用專案結構來定義頁面結構來實現這一點。因此,如果您想要一個 mywebapp/dosomethingwithmyfiles 頁面,您需要有一個名為 dosomethingwithmyfiles 的資料夾,其中包含一個 +page.svelte 檔案。一旦這種安排到位,您部署的應用程式就會為其每個 URL 提供一個單獨的實體頁面。
這是 SvelteKit 專案的範例來源資料夾結構:
我的專案
├────src
│ └────路線
│ └───用我的文件做一些事
一旦安裝了 SvelteKit(請參閱 Svelte for New Developers),此結構將透過大量複雜的設定檔和建置資料夾等來增強。但是,目前,重點是在路由資料夾上。 這是您儲存頁面程式碼的地方 - 在這裡您可能會開始懷疑 SvelteKit 是否適合您。現在要抓緊,因為這就是事情變得有點複雜的地方。
SvelteKit 要求您對頁面資料夾的內容遵循非常嚴格的命名約定。以下是 dosomethingwithmyfiles 資料夾中可能出現的檔案名稱清單:
乍一看,你可能會覺得這根本無法接受。但請注意,每個 +page.svelte 檔案在編輯器列上都透過其資料夾擁有者的名稱、dosomethingwithmyfiles 或其他名稱進行限定。在開始編輯之前,訓練自己檢查 +page.svelte 的擁有者並不是那麼困難。一旦您開發了一兩個 SvelteKit 項目,您就會開始欣賞約定在聲明安排的目的方面的價值(正如您稍後會看到的,有很多變體) )
當你承受這種衝擊時,讓我給你一點鼓勵。 在 +page.svelte 檔案中,您可能會期望找到與在等效React 檔案中看到的相同類型的程式碼- 混合了用於操作頁面狀態的外來useState 呼叫和用於“反應”的JSX到此並產生HTML。雖然 +page.svelte 檔案確實可以完成相同的工作,但它設法放棄「異國情調」的部分,並使用純 JavaScript 和純粹的、未稀釋的 HTMl,並添加了一些特殊關鍵字。您可能會發現這令人耳目一新。
以下是您可能會在 dosomethingwithmyfiles 資料夾中找到的一些標準檔案名稱:
有趣的是,如果您過去在編寫Web API 程式碼以在瀏覽器中運行和Node.js 風格在Firebase 函數中在伺服器端運行之間切換時,必須「重新編程」您的javascript 大腦,那麼您會我們會很高興聽到,在Sveltekit 中,Web API 版本現在也非常樂意在伺服器端運作。
當然,您會想知道如何組織事物,以便 +page.js 檔案讀取的資料最終出現在關聯的 +page.svelte 中。我想說的是,就目前而言,這是透過 SvelteKit 魔法實現的。只有在我描述了 SvelteKit 定義「反應性」變數的安排後,確切的機制才會變得清晰。暫時戴上你的帽子。
如果 +layout.svelte 頁面需要一些數據,它可以有一個附帶的 +layout.server.js 文件
「反應變數」是指當資料項目改變時導致瀏覽器頁面重新渲染的資料項。我所說的「反應式 HTML」是指 HTML 能夠回應這些變化。
在 React 中,您會記得,反應式變數是使用 useState 表達式來宣告的,該表達式將變數定義為狀態物件的屬性。該聲明還指定了初始屬性值和更改它們的函數。
這是一個範例 - 一個 React Web 應用程序,它顯示一個彈出窗口,當您單擊它時該彈出窗口就會消失:
import React, { useState } from "react"; const [screenState, setScreenState] = useState({popupVisible: true,}); return ( <div> <h1 style={{textAlign: "center"}} onClick = {() => {setScreenState({popupVisible: !screenState.popupVisible})}}> Main Page - Click to toggle popup </h1> {screenState.popupVisible && <div style={{ textAlign: "center", marginLeft: "auto", marginRight: "auto", height: "2rem", width: "25rem", backgroundColor: "gainsboro" }} onClick = {() => {setScreenState({popupVisible: !screenState.popupVisible})}}> <h2> Popup Window - Click to Hide popup</h2> </div> } </div> )
在Svelte 中(我現在談論的是語言,而不是它運行的框架),你可以在src/routes/demo/+ 中實現這種效果page .svelte 文件,只要將popupVisible 宣告為javascript 變數
<script> let popupVisible = false; </script> <div> <h1 style="text-align: center" on:click={() => (popupVisible = !popupVisible)}> Main Page - Click to toggle popup </h1> {#if popupVisible} <div style="text-align: center; margin-left: auto; margin-right: auto; height: 2rem; width: 25rem; background-color: gainsboro" on:click={() => (popupVisible = !popupVisible)} > <h2>Popup Window - Click to Hide popup</h2> </div> {/if} </div>
以下是主要差異的摘要:
Svelte uses a standard Javascript let declaration to introduce state variables instead of the strange React useState expression
Svelte uses a down to earth #if 'logical expression' keyword to replace the awkward JSX {'logical expression' &&syntax. This makes your code much more readable. Svelte also provides associated else and each keywords.
Svelte uses plain CSS to define HTML classes rather than the perplexing JSX style objects (eg {{textAlign: "center"}}).
Note also that the demo/+pagesvelte file defined above will run directly in the browser as /demo. To run the React version you would have to put some code into an associated src/main.jsx file to define the new route.
Keyboard input in React generally uses the following pattern:
const [myState, setMyState] = useState({myProperty: "",}); function handleChange({ target }) { setMyState({ ...myState, [target.name]: target.value }); }; return ( <input name="myProperty" value={myState.myProperty} onChange={handleChange} /> )
Here, an input labelled as "myProperty" fires a general-purpose handleChange function every time you press a key. In handleChange its value is extracted and applied to the page's state to trigger a re-render.
Svelte thinks this is too complicated and introduces a "bind" keyword to its input syntax. This automatically transmits changes to an associated state variable. A Svelte version of the above thus looks like this:
<script> let myProperty = ""; </script> <input bind:value={myProperty} />
The bind keyword is also used to enable you to create two-way communication between parent and child components. This is a powerful feature.
An interesting feature of Svelte is that it encourages you to use forms and server-side processing for input handling. Thus it's perfectly permissible in Svelte to launch a client-side function like this:
<script> let myProperty = ""; function commitChange() { // Use the global myProperty variable to update server storage } </script> <span>myProperty = </span><input bind:value={myProperty} /> <button on:click={commitChange}>Commit Change</button> />
Svelte docs correctly insist that interactions like this are better handled by forms and server-side processing in a +page.server.js file. Here the validation and submission of the user input can be safely protected from the sort of interference possible in client-based code. Here also, any subsequent processing can be performed with maximum efficiency.
To implement this view, Svelte provide a neat automatic link between a form reading data on a +page.svelte and a function handling the processing of that data in the associated +page.server.js file. Here's an example:
src/routes/login/+page.svelte <form method="POST"> <span>myProperty = </span><input name="myProperty"> <button>Commit Change</button> </form> src/routes/login/+page.server.js export const actions = { default: async (event) => { // TODO handle the processing for the input read by the form on +page.svelte } };
Note that no Javascript has been used in the form - no "on click" or "on submit", for example. The linkage has been established entirely through "Svelte magic".
In practice, of course, a +page.svelte file is likely to want to be the source of multiple "actions". See Svelte Form Actions for details of how Svelte manages this. (Note that Svelte docs are organised under two URLs: kit.svelte.dev for framework topics like routing and svelte.dev for elements of the language itself)
Finally, to conclude this section, suppose you wanted users to be able to call on the service of an action by referencing it directly through a javascript "fetch" (or, at its simplest by launching a parameterised url via the browser - eg https:// mySite/myPage?param1=3 etc). This is where you would use a +server.js file to create an API "endpoint" function. Firebase users might well use such an arrangement where they had previously used a Firebase function. Not the least advantage of this would be that testing and debugging could be done in the Sveltekit server rather than the Firebase emulator.
Each +page.svelte file defines a component, and you mark variables declared here as "props" - ie make them accessible to "consumers" of the component - by adding the export keyword to their declarations. So, if you're still wondering how a +page.svelte file gets its data from +page.server.js - this is how it's done. A +page.svelte file wanting to receive "load" data from its +page.server.js (or +page.js) file just needs to put something like the following in its