solid-start - ソリッドスタート、ソリッドアプリフレームワーク

(SolidStart, the Solid app framework)

Created at: 2021-03-30 11:42:11
Language: TypeScript
License: MIT

ソリッドドキュメント

ソリッドスタート

これは、Solidアプリフレームワークの本拠地です。これはまだ進行中の作業です。多くの機能が欠落しているか不完全です。実験ステータスはベータステータスを意味するものではありません。パッチリリースはすべてを壊します。

  • ファイル・システム・ベースのルーティング
  • すべてのレンダリングモードをサポート:サーバーサイドレンダリング(SSR)、クライアント側レンダリング(CSR)、静的サイト生成(SSG)
  • ストリーミング
  • コード分割、ツリーシェイキング、デッドコード除去によるビルドの最適化
  • API ルート
  • ウェブ標準に基づいて構築:フェッチ、ストリーム、ウェブクリプト
  • すべての一般的なプラットフォームに展開するためのアダプター
  • CSS モジュール、SASS/SCSS サポート
  • タイプスクリプトファースト

はじめ

mkdir my-app
cd my-app
npm init solid
npm install
npm run dev

発達

モノレポはパッケージマネージャーとして使用します。インストールするには、ターミナルで次のコマンドを実行します。

pnpm
pnpm

npm install -g pnpm

実行モノリポジトリ内のパッケージと例のすべての依存関係をインストールします。

pnpm install

モノレポとサポート
project.json
"workspace"

ホイストされた依存関係(糸のデフォルト)を持つプロパティ(糸ワークスペースなど)を利用するモノレポ内でソリッドスタートを使用している場合は、オプション内に含める必要があります(yarn v2以降の場合、手順についてはさらに下を参照してください)workspacesプロパティ。

package.json
"workspaces"
solid-start
"nohoist"

  • 以下では、「ワークスペースルート」はリポジトリのルートを指し、「プロジェクトルート」はリポジトリ内の子パッケージのルートを指します

たとえば、ワークスペースルート(つまり、すべてのパッケージ)のオプションを指定する場合:

"nohoist"

// in workspace root
{
  "workspaces": {
    "packages": [
      /* ... */
    ],
    "nohoist": ["**/solid-start"]
  }
}

指定する場合、以下を使用して特定のパッケージのオプション:

"nohoist"
solid-start

// in project root of a workspace child
{
  "workspaces": {
    "nohoist": ["solid-start"]
  }
}

nohoist オプションを指定する場所に関係なく、子に devDependency として含める必要もあります。

solid-start
package.json

これが必要な理由は、(プロジェクトルートのパス)にあるスクリプトをロードすることを期待するプロジェクト内のファイルを作成します。既定では、依存関係をワークスペースのルートにホイストすると、そのスクリプトはパッケージのフォルダー内で使用できなくなります。

solid-start
index.html
/node_modules/solid-start/runtime/entry.jsx
/
solid-start
node_modules

糸v2以上

このオプションは、Yarn v2 +では使用できなくなりました。この場合、(ワークスペースパッケージまたは特定のプロジェクトパッケージのいずれか)のプロパティを使用して、depsが吊り上げられていないことを確認できます。

nohoist
installConfig
package.json

// in project root of a workspace child
{
  "installConfig": {
    "hoistingLimits": "dependencies"
  }
}

変更履歴

[0.1.6]

名前が変更されました API ルートは、小文字から大文字のメソッド名にエクスポートして、仕様や使用法でこれらの関数をどのように見ているかに厳密に一致します。

- export function get() {
+ export function GET() {
  return new Response();
}

- export function post() {
+ export function POST() {

  return new Response();
}

- export function patch() {
+ export function PATCH() {
  return new Response();
}

- export function del() {
+ export function DELETE() {
  return new Response();
}

[0.1.0-アルファ104]

グループ化されたルートを構文からに変更しました。

__name
(name)

[0.1.0-アルファ103]

次のような特別なコンパイル済み関数を変更しました,,,.接尾辞を持つ彼らの特別なコンパイル(巻き上げられた動作)を示すために。

server
createServerData
createServerAction$
createServerMultiAction$
$

また、オプションの最初の引数を移動しましたアンダーオプション。これは非常に重要なオプションを隠しますが、シグネチャをより類似させるので、サーバー上で実行されているメイン(最初の)関数であることは明らかです。

createServerData$
key

const data = createServerData$(
  async pathname => {
    let mod = mods[`./docs${pathname}.mdx`] ?? mods[`./docs${pathname}.md`];
    return mod.getHeadings().filter(h => h.depth > 1 && h.depth <= 3);
  },
  {
    key: () => path.pathname
  }
);

[0.1.0-アルファ。- ベータ版への移行

vite.config.ts

- import solid from 'solid-start';
+ import solid from 'solid-start/vite';
import { defineConfig } from 'vite';
export default defineConfig({
  plugins: [solid()]
})

なぜでしょうか。

  • メインエントリポイントを使用したかったほとんどの時間を費やしているアプリ内で使用するため。そしてのために構成、私たちは使用しますエントリポイント。
    solid-start
    vite
    solid-start/vite

entry-server.tsx

import { createHandler, renderAsync, StartServer } from "solid-start/entry-server";

- export default createHandler(renderAsync(context => <StartServer context={context} />));
+ export default createHandler(renderAsync(event => <StartServer event={event} />));

なぜでしょうか。

  • によって受け取られ、あなたに与えられた小道具 by東 呼ばれる代わりに。それは表しますこれはサーバーがコンポーネントによってレンダリングする必要があると決定したこと。サーバーハンドラーが受け取った入力を表す用語を採用しました。たとえば、最上位のサーバー ハンドラーへの入力は a です。その後、サーバー関数にルーティングし、aor として API エンドポイントに an として渡すことができます。この用語は、ServiceWorker APIおよびCloudflare Workers APIから採用されています。
    StartServer
    createHandler
    event
    context
    PageEvent
    FetchEvent
    Page
    event
    FetchEvent
    ServerFunctionEvent
    ApiEvent

entry-client.tsx

SSR を使用していた場合:

- import { hydrate } from "solid-js";
- import { StartClient } from "solid-start/entry-client";
+ import { mount, StartClient } from "solid-start/entry-client";

- hydrate(() => <StartClient />, document);
+ mount(() => <StartClient />, document);

SSR を使用せず、アプリをクライアント側でレンダリングしなかった場合:

- import { render } from "solid-js";
- import { StartClient } from "solid-start/entry-client";
+ import { mount, StartClient } from "solid-start/entry-client";

- render(() => <StartClient />, document.body);
+ mount(() => <StartClient />, document);

なぜでしょうか。

  • 以前、あなたは電話しましたまたはここで、選択したレンダリングモードの種類とSSRがオンになっているかどうかに基づいています。モードを切り替えたい場合はこれを変更するのは少し面倒だと感じ、注意しないとエラーが発生しやすくなります。

    hydrate(document)
    render(document.body)
    document
    render

    私たちはまだ公開したかったユーザーに、必要に応じてここで引き継いで自分のことをできるようにしました。というヘルパー関数を作成しましたこれは、サーバーから取得したアプリとの対話方法を決定するためのロジックを埋め込みます。

    entry-client.tsx
    mount
    hydrate
    render

ルート.tsx

// @refresh reload
import { Suspense } from "solid-js";
- import { Meta, Link, Routes, Scripts } from "solid-start/root";
+ import { FileRoutes, Scripts, Html, Head, Body, Routes, Meta, ErrorBoundary, A } from "solid-start";

export default function Root() {
  return (
-    <html lang="en">
+    <Html lang="en">
-      <head>
+      <Head>

-        <meta charset="utf-8" />
+        <Meta charset="utf-8" />
-        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <Meta name="viewport" content="width=device-width, initial-scale=1" />

-        <Meta /> // already exists inside `Head`
-        <Links /> // already exists inside `Head`

-      </head>
+      </Head>
-      <body>
+      <Body>
         <Suspense>
           <ErrorBoundary>
             <A href="https://github.com/solidjs/solid-start/blob/master//">Index</A>
             <A href="https://github.com/solidjs/solid-start/blob/master//about">About</A>
-            <Routes />
+            <Routes>
+              <FileRoutes />
+            </Routes>
           </ErrorBoundary>
         </Suspense>
         <Scripts />
-     </body>
+     </Body>
-   </html>
+   </Html>
  );
}

なぜでしょうか。

  • ルートの宣言方法を変更して、より柔軟にしました。以前、私たちはあなたに与えましたコンポーネントからそれはレンダリングすることと同等でした から (はい、紛らわしいことはわかっているので、変更しています)、ファイルシステムからのルートで埋めます。ファイルシステムルーティングへのオプトインは、オールインまたはゼロでした。あなたはモアを追加する機会がありませんでした。ここからエクスポートします これは、ファイルシステムに基づくルート構成を表します。これは、からコンポーネントに渡されることを意図していますまたは、ファイルシステムのルート設定を使用する場所。

    Routes
    solid-start
    Routes
    @solidjs/router
    Route
    FileRoutes
    solid-start
    Routes
    solid-start

    • 他のコンポーネントと一緒に使用できます。
      Route
      <Routes>
        <FileRoutes />
        <Route path="/somewhere" component={SomeComponent} />
      </Routes>
    • また、大量のファイルを作成せずにアプリをすばやく起動するために、単一のファイルでルートを定義できます。ルートに沿ってアプリをコード分割することをお勧めしますが、これは巧妙なトリックであるため、通常はお勧めしません。
      <Routes>
        <Route path="/somewhere" component={SomeComponent} />
      </Routes>
  • SSRとクライアント側のレンダリングモードの一貫性を保つために、ドキュメント全体をクライアント側でレンダリングできないため、takeandtagsを単にコンポーネントツリーの一部にすることはできませんでした。私たちは本当に引き継ぐことができるだけです。特別な、および使用するコンポーネント小文字の対応物の代わりに出荷する必要がありました。これらのドキュメントフローコンポーネントは、SSRモードがオンかオフかに関係なく、何をすべきかを認識しています。

    root.tsx
    <html></html>
    <head></head>
    document.body
    Html
    Head
    Body
    root.tsx

  • 私たちはあなたが含める必要を避けることができますそしてあなたのからデフォルトでそれを行うので。

    Meta
    Links
    solid-start/root
    head

  • アプリ全体で一貫性を保つために、常に使用されているタグのタイトルケースのバリエーション(例:>,>,>)を使用します

    head
    Link
    link
    Style
    style
    Meta
    meta

  • solid-meta
    に名前が変更されました
    @solidjs/meta

  • solid-app-router
    に名前が変更されました
    @solidjs/router

  • solid-start
    アプリで使用するすべてのコンポーネントをエクスポートし、これらのコンポーネントはクライアントとサーバーで動作します。両方で同じ場合もあれば、2つの間で調整される場合もあります。

  • さて、私たちのさらに厳密には、あなたがあなたのものを書く方法をより厳密に再現します。これは、SSRモードと同じコードを使用するSPAモードを何も変更せずに有効にするために意図的に行われました。これをどのように行いますか?SPAモードのビルド時に、viteサーバーをすばやく実行し、アプリのインデックスを要求し、何もレンダリングしないようにコンポーネントに指示します。したがって.html私たちが得るインデックスは、あなたが書いたであろうものです。次に、それをエントリポイントとして使用します。あなたはまだあなた自身を書くことができますこの機能を使用したくない場合は。

    root.tsx
    index.html
    Body
    index.html
    index.html

createServerResource -> createServerData$

export function routeData() {
-  return createServerResource(async (_, { request }) => {
+  return createServerData$(async (_, { request }) => {
    const user = await getUser(request);

    if (!user) {
      throw redirect("/login");
    }

    return user;
  });
}
  • 名前の変更後、および:名前を変更しました署名を使用していなかったため、混乱を招き、関数がコンパイルされたことを示す必要がありました。から1つのシグナルを返すだけですタプルの代わりに好きです。そして、ソースをオプションに移動しました。
    createServerResource
    createServerData$
    createRouteResource
    createRouteData
    createServerResource
    createServerData$
    createResource
    createServerData$
    createResource
    key

createServerAction$, createServerMultiAction$

- const logoutAction = createServerAction(() => logout(server.request));
+ const [logginOut, logOut] = createServerAction$((_, { request }) => logout(request));

サーバーアクションの2番目の引数としてフィールドを持っています。これを使用して、アクションに対して送信されたHTTPリクエストにアクセスし、authなどのヘッダーを取得できます。

ServerFunctionEvent
request

最初の引数が現在の送信であり、2番目の引数が送信関数であるタプルを返しますが、プログレッシブ拡張可能形式もアタッチされています。

logout.Form

🆕 HttpStatusCode, HttpHeader

export default function NotFound() {
  return (
    <div>
      <HttpStatusCode code={404} />
      <HttpHeader name="my-header" value="header-value" />
    </div>
  );
}

クレジット

フォームとセッションに関する作業のすべてのクレジットは、@remix運営チーム、MITライセンス、Copyright 2021 Remix Software Inc.に帰属します。