ホームページ >ウェブフロントエンド >jsチュートリアル >Google Cloud 開発者向けの SvelteKit の穏やかな入門書

Google Cloud 開発者向けの SvelteKit の穏やかな入門書

PHPz
PHPzオリジナル
2024-07-17 19:39:17638ブラウズ

 A gentle introduction to SvelteKit for Google Cloud developers

導入

このシリーズの以前の投稿 (とても優しい React の紹介) では、Web アプリ開発のための優れた React フレームワーク システムを読者に紹介しました。 SvelteKit は代替フレームワークです。 React とどう違うのですか?

機能的には、それほど大きな違いはないと思います。 React で実行できるほとんどのことは、SvelteKit でも実行できます。そしてその逆も同様です。しかし、細部に至ると、「事後対応」の目標を達成しやすいという点で SvelteKit の方が優れていると多くの人が感じています。 Svelte とは「エレガント」という意味ですが、まさにその通りで、細身で適応性が高く、実用的なツールです。

個人的に、私が SvelteKit に惹かれたのは、SvelteKit がサーバー側の設計、つまりユーザーの Web ブラウザーではなく Web アプリのクラウド サーバー上で実行されるコードを推進する傾向があるためです。もともと私が Web アプリ開発に夢中になったのは、クライアント側のコードを簡単に作成してデバッグできるからです。これは皮肉なことです。しかしその後、インデックス作成スパイダーがクライアント側コードの「ハイドレート」に労力を費やすことをいかに躊躇しているかに気づき、ここにはさらに労力を費やす必要があることに気づきました (何が必要かを確認するには、以下の SvelteKit でのデバッグを参照してください)。ただし、サーバー側コードの使用を検討する理由は他にもあります。ここにいくつかあります:

  • Postmark (電子メールの発送) や Paypal (支払いの回収) などのサードパーティ サービスを使い始めると、クライアント側のコードにセキュリティ コードを含めるのは得策ではないことがわかります。 あなたは、「インスペクター」を使用してこれらを閲覧できるため、他の人も閲覧できます。サーバー側で実行されるコードにアクセスできません。

  • サーバー側のコードはデータの近くに存在し、クライアントのラップトップよりも高速に実行されます。

SvelteKit を使用すると、Web アプリのどの部分をローカルで実行するか、どの部分をリモートで実行するかを指定して、簡単に曲を再生できます。

  • 場合によっては、ページが完全にサーバー側でレンダリングされることがあります。ページに静的な情報のみが含まれている場合、Sveltekit を使用してページを「事前レンダリング」できます。事前レンダリングされたページはビルド時に構築され、純粋な HTML のスラブとしてダウンロードされます。
  • あるいは、完全にクライアント側でレンダリングすることもできます。
  • または、両方で実行することもできます。最適な応答時間を提供することを目的とした SvelteKit Web アプリは、最初はサーバーから提供された「プレースホルダー」画面だけを表示して、何かを表示することができます (どうやら、ここでは Google のインデックス作成ボットが大いに貢献しているようです)。これは、ユーザー インスタンスに固有の情報を使用してクライアント側のコードによって「ハイドレート」されます。

もう少し具体的な話に移りましょう。

Svelte でのルーティング

Sveltekit Web アプリは、外部的には従来のブラウザ アプリケーションとまったく同じように見えます (mywebapp/dosomethingwithmyfiles などの「ページ」の階層)。これは、クライアント ユーザーがこの種の取り決めを期待し、依存しているためです。しかし、表面下では、SvelteKit Web アプリは、React Web アプリとはまったく異なる方法でこの配置を提供します。 React では、これらのページはすべて 1 つの巨大なコード スラブの一部であり、リクエストは Web インターフェイスで動作するリダイレクトによってそこにルーティングされます (この文が意味を理解できない場合は、「シングルとは何か」を参照してください)。ページの Web アプリ?)。 SvelteKit は、プロジェクト構造を使用してページ構造を定義することでこれを実現します。したがって、mywebapp/dosomethingwithmyfiles ページを作成したい場合は、dosomethingwithmyfiles という名前のフォルダーを作成し、その中に +page.svelte ファイルを含める必要があります。この取り決めが完了すると、デプロイされたアプリは URL ごとに個別の物理ページを配信します。

SvelteKit プロジェクトのサンプル ソース フォルダー構造は次のとおりです:

私のプロジェクト
§───src
│ └───ルート
│ └────私のファイルで何かをする

SvelteKit (新規開発者向けの Svelte を参照) をインストールすると、この構造は大量の複雑な構成ファイルやビルド フォルダーなどによって強化されます。ただし、現時点では、ルート フォルダーに焦点を当てています。 ここはページ コードを保存する場所です。SvelteKit が自分にとって正しいものかどうか疑問に思うかもしれません。ここからが少し複雑になるため、しっかりと把握してください。

SvelteKit では、ページ フォルダーのコンテンツに対して非常に厳密な命名規則に従う必要があります。 dosomethingwithmyfiles フォルダーに表示される可能性のあるファイル名のリストは次のとおりです:

  • dosomethingwithmyfiles/+page.svelte。このファイルには、URL myproject/dosomethingwithmyfile のページをブラウザ画面に表示するコードのソースが含まれます。おっと、ちょっと考えてみましょう。 VSCode エディターで 6 個の異なるページを含む SvelteKit プロジェクトを作業している場合、ファイルバーにはすべて +page.svelte という名前の 6 個のタブが表示されることがあります。紛らわしいですか?はい、同意します。

一見すると、これはまったく受け入れられないと感じるかもしれません。ただし、各 +page.svelte ファイルは、フォルダー所有者の名前 (dosomethingwithmyfiles など) によってエディター バー上で修飾されることに注意してください。編集を開始する前に、+page.svelte の所有者を確認するように自分を律することは、それほど難しいことではありません。そして、SvelteKit プロジェクトを 1 つか 2 つ開発すると、その取り決めの 目的 を宣言する規約の価値を理解し始めるでしょう (すぐにわかるように、かなりの数のバリエーションがあります) )

あなたがこのショックを吸収している間、少し励ましてあげましょう。 +page.svelte ファイルのには、同等の React ファイルにあるのと同じ種類のコードが見つかると予想されるかもしれません。これは、ページ状態を操作するための珍しい useState 呼び出しと、「反応」するための JSX の組み合わせです。これを実行して HTML を生成します。 +page.svelte ファイルも確かに同じ仕事をしますが、「エキゾチック」な部分をなんとか破棄し、プレーンな JavaScript と、特別なキーワードを散りばめた純粋な希釈されていない HTMl を使用します。新鮮に感じられるかもしれません。

dosomethingwithmyfiles フォルダーで見つかる可能性のある標準的なファイル名をさらにいくつか示します。

  • dosomethingwithmyfiles/+page.js、これには data を +page.svelte ファイル (つまり、React useEffect と同等) に配信するファイルのソースが含まれます。ここのコードは、ページが最初に読み込まれるときにサーバー上で実行されます。その後、ページが再参照されると、+page.js コードがブラウザーで実行され、前述の利点が得られます。

    興味深いことに、ブラウザで実行する Web API コードの記述と、Firebase 関数でサーバーサイドで実行する Node.js スタイルを切り替えるたびに、JavaScript 脳を「再プログラム」しなければならないことに過去に悩まされたことがある場合は、次のようになります。 Sveltekit では、Web API バージョンがサーバー側でも問題なく実行できるようになったと聞いて、とても嬉しく思います。

    当然のことながら、+page.js ファイルによって読み取られたデータが関連付けられた +page.svelte に格納されるように、どのように整理するかを知りたいと思うでしょう。現時点では、これは SvelteKit の魔法によって実現したと言わせてください。正確なメカニズムは、「リアクティブ」変数を定義するための SvelteKit の仕組みを説明した後でのみ明らかになります。とりあえず帽子をかぶってください。

  • dosomethingwithmyfiles/+page.server.js。ここには、サーバー上でのみ実行するコードを配置します (通常はセキュリティまたはパフォーマンス上の理由から)。前述したように、これを事前レンダリングしてビルド時に構築するようにリクエストできます。この場合のパフォーマンスは驚くべきものです。

  • dosomethingwithmyfiles/+layout.svelte。ここには、他のページのセット全体に共通するページの部分 (たとえば、ツールバー ヘッダー) を設定するコードを配置します。 +layout.svelte ファイルは、すべての子ルートと兄弟の +page.svelte に適用されます。レイアウトを任意の深さまでネストできます。繰り返しますが、共通のレイアウトを受信者のページに挿入するための正確な配置は、後ほど残されます - より洗練された魔法です。

    +layout.svelte ページにデータが必要な場合は、付随する +layout.server.js ファイルを含めることができます。

  • dosomethingwithmyfiles/+server.js。ここには、myProject/dosomethingwithmyfiles?type="pdf" などのパラメーター化された URL を介して「API エンドポイント」として使用できるようにするコードを配置します。この取り決めについては後ほど詳しく説明します。

SvelteKit の「リアクティブ変数」と「リアクティブ HTML」

「リアクティブ変数」とは、変更されたときにブラウザー ページの再レンダリングを引き起こすデータ項目を意味します。 「リアクティブ 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.

Inputs: Local Functions, Actions and API endpoints

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.

Components

  • 1-way bindings

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