DarkLogo

TypeScript on SvelteKit学習メモ3

· Kishimoto
※この記事は私の学習が進むにつれ内容が更新されていく想定の記事です。

Q: svelteのlifecycleを教えてください

Svelteには、以下のライフサイクルフックがあります。

onMount: コンポーネントがDOMにマウントされた後に呼び出されます。 onDestroy: コンポーネントが破棄される前に呼び出されます。 beforeUpdate: コンポーネントが更新される前に呼び出されます。 afterUpdate: コンポーネントが更新された後に呼び出されます。 onCreate: コンポーネントが作成されたときに呼び出されます。 これらのライフサイクルフックは、Svelteコンポーネントが異なる状態にあるときに自動的に呼び出されます。これらを使用することで、コンポーネントの状態に基づいて動作を変更することができます。


Q: 上記の使用方法をサンプルを交えて教えて下さい

<script>
  import { onMount, onDestroy } from 'svelte';

  let message = 'Hello, world!';

  onMount(() => {
    console.log('Component mounted!');
  });

  onDestroy(() => {
    console.log('Component destroyed!');
  });
</script>

<div>{message}</div>

上記の例では、onMountフックで無名関数を定義しています。これにより、コンポーネントがDOMにマウントされた後に無名関数が実行されます。同様に、onDestroyフックで無名関数を定義しています。これにより、コンポーネントが破棄される前に無名関数が実行されます。

また、letキーワードを使用して、message変数を定義しています。これは、コンポーネントの状態を表します。この変数は、コンポーネントが再レンダリングされるたびに更新されます。

最後に、

要素を使用して、message変数の値を表示しています。これにより、コンポーネントのUIが表示されます。


Q: TypeScriptを採用したプロジェクトでよく使われるアーキテクチャ

TypeScriptを採用したプロジェクトでよく使われるアーキテクチャには、以下のようなものがあります。

Clean Architecture(クリーンアーキテクチャ) Domain-Driven Design(ドメイン駆動設計) Model-View-Controller(モデル・ビュー・コントローラー) Model-View-ViewModel(モデル・ビュー・ビューモデル) Layered Architecture(レイヤードアーキテクチャ) これらのアーキテクチャは、それぞれ異なる考え方や原則に基づいています。どのアーキテクチャが最適かは、プロジェクトの規模や目的、チームのスキルなどによって異なります。ただし、TypeScriptを使用する場合は、クリーンアーキテクチャやドメイン駆動設計など、より型安全性を高めるアーキテクチャが好まれることがあります。


Q: SvelteKitで使う場合上記を適用するとそれぞれどう言ったディレクトリ構成と意味になるか教えて下さい

SvelteKitでのアーキテクチャは、通常のSvelteアプリケーションとは異なり、SvelteKitが提供するフォルダ構成に基づいています。以下に、SvelteKitで採用されるアーキテクチャと、それに基づくフォルダ構成を説明します。

Clean Architecture Clean Architectureでは、アプリケーションを以下の層に分割します。

Domain: ビジネスロジックを表す層 Application: ユースケースを表す層 Infrastructure: 外部システムとのやりとりを行う層 SvelteKitにおけるディレクトリ構成は以下のようになります。

src/
├── lib/
│   ├── domain/
│   ├── application/
│   ├── infrastructure/
├── routes/
│   ├── index.svelte

libディレクトリ以下には、それぞれの層に対応するディレクトリを作成します。routesディレクトリには、各ページのルーティングに対応するSvelteコンポーネントを配置します。

Domain-Driven Design Domain-Driven Designでは、アプリケーションを以下の層に分割します。

Presentation: UIを表す層 Application: ユースケースを表す層 Domain: ビジネスロジックを表す層 Infrastructure: 外部システムとのやりとりを行う層 SvelteKitにおけるディレクトリ構成は以下のようになります。

src/
├── components/
│   ├── Presentation/
├── lib/
│   ├── application/
│   ├── domain/
│   ├── infrastructure/
├── routes/
│   ├── index.svelte

componentsディレクトリには、Presentation層に属するSvelteコンポーネントを配置します。libディレクトリ以下には、それぞれの層に対応するディレクトリを作成します。routesディレクトリには、各ページのルーティングに対応するSvelteコンポーネントを配置します。

Model-View-Controller Model-View-Controllerでは、アプリケーションを以下の層に分割します。

Model: ビジネスロジックを表す層 View: UIを表す層 Controller: ユーザー入力を処理する層 SvelteKitにおけるディレクトリ構成は以下のようになります。

src/
├── components/
│   ├── Views/
├── lib/
│   ├── Models/
├── routes/
│   ├── index.svelte

componentsディレクトリには、View層に属するSvelteコンポーネントを配置します。libディレクトリ以下には、Model層に属するクラスや関数を配置します。routesディレクトリには、各ページのルーティングに対応するSvelteコンポーネントを配置します。Controller層は、SvelteKitでは主にページコンポーネント内で処理されることが多く、フォルダ構成としてはあまり意識されません。

Model-View-ViewModel Model-View-ViewModelでは、アプリケーションを以下の層に分割します。

Model: ビジネスロジックを表す層 View: UIを表す層 ViewModel: ビューロジックを表す層 SvelteKitにおけるディレクトリ構成は以下のようになります。

src/
├── components/
│   ├── Views/
│   ├── ViewModels/
├── lib/
│   ├── Models/
├── routes/
│   ├── index.svelte

componentsディレクトリには、View層に属するSvelteコンポーネントと、ViewModel層に属するクラスを配置します。libディレクトリ以下には、Model層に属するクラスや関数を配置します。routesディレクトリには、各ページのルーティングに対応するSvelteコンポーネントを配置します。

Layered Architecture Layered Architectureでは、アプリケーションを以下の層に分割します。

Presentation: UIを表す層 Application: ユースケースを表す層 Domain: ビジネスロジックを表す層 Infrastructure: 外部システムとのやりとりを行う層 SvelteKitにおけるディレクトリ構成は以下のようになります。

src/
├── components/
│   ├── Presentation/
├── lib/
│   ├── Application/
│   ├── Domain/
│   ├── Infrastructure/
├── routes/
│   ├── index.svelte

componentsディレクトリには、Presentation層に属するSvelteコンポーネントを配置します。libディレクトリ以下には、それぞれの層に対応するディレクトリを作成します。routesディレクトリには、各ページのルーティングに対応するSvelteコンポーネントを配置します。

上記のディレクトリ構成は、アーキテクチャに基づいてフォルダを分割する一例です。実際のプロジェクトにおいては、より複雑な構造になることもあります。


Q: 詳細な説明は省いていいのでそれぞれより詳細な下層までの考えうるディレクトリ構成を教えてください

それぞれのアーキテクチャに対して、より詳細なディレクトリ構成の例を示します。以下の例はあくまで一例であり、実際のプロジェクトによって異なる場合があります。

Clean Architecture

src/
├── lib/
│   ├── domain/
│   │   ├── entities/
│   │   ├── repositories/
│   ├── application/
│   │   ├── usecases/
│   ├── infrastructure/
│   │   ├── database/
│   │   ├── apis/
├── routes/
│   ├── index.svelte

Domain-Driven Design

src/
├── components/
│   ├── Presentation/
│       ├── HomePage/
│           ├── HomePage.svelte
│           ├── HomePage.css
│   ├── Shared/
│       ├── Header/
│           ├── Header.svelte
│           ├── Header.css
│   ├── Layout/
│       ├── DefaultLayout/
│           ├── DefaultLayout.svelte
│           ├── DefaultLayout.css
├── lib/
│   ├── application/
│   │   ├── usecases/
│   │   ├── services/
│   ├── domain/
│   │   ├── models/
│   │   ├── repositories/
│   ├── infrastructure/
│   │   ├── database/
│   │   ├── apis/
├── routes/
│   ├── index.svelte

Model-View-Controller

src/
├── components/
│   ├── Views/
│       ├── HomePage/
│           ├── HomePage.svelte
│           ├── HomePage.css
│   ├── Shared/
│       ├── Header/
│           ├── Header.svelte
│           ├── Header.css
│   ├── Layout/
│       ├── DefaultLayout/
│           ├── DefaultLayout.svelte
│           ├── DefaultLayout.css
├── lib/
│   ├── Models/
│       ├── User.ts
│       ├── Post.ts
│   ├── Services/
│       ├── AuthService.ts
│       ├── PostService.ts
├── routes/
│   ├── index.svelte

Model-View-ViewModel

src/
├── components/
│   ├── Views/
│       ├── HomePage/
│           ├── HomePage.svelte
│           ├── HomePage.css
│       ├── LoginPage/
│           ├── LoginPage.svelte
│           ├── LoginPage.css
│   ├── ViewModels/
│       ├── HomeViewModel.ts
│       ├── LoginViewModel.ts
│   ├── Shared/
│       ├── Header/
│           ├── Header.svelte
│           ├── Header.css
│   ├── Layout/
│       ├── DefaultLayout/
│           ├── DefaultLayout.svelte
│           ├── DefaultLayout.css
├── lib/
│   ├── Models/
│       ├── User.ts
│       ├── Post.ts
│   ├── Services/
│       ├── AuthService.ts
│       ├── PostService.ts
├── routes/
│   ├── index.svelte

Layered Architecture

src/
├── components/
│   ├── Presentation/
│       ├── HomePage/
│           ├── HomePage.svelte
│           ├── HomePage.css
│   ├── Shared/
│       ├── Header/
│           ├── Header.svelte
│           ├── Header.css
│   ├── Layout/
│       ├── DefaultLayout/
│           ├── DefaultLayout.svelte
│           ├── DefaultLayout.css
├── lib/
│   ├── Application/
│   │   ├── usecases/
│   │   ├── services/
│   ├── Domain/
│   │   ├──
│   │   ├── models/
│   │   ├── repositories/
│   ├── Infrastructure/
│   │   ├── database/
│   │   ├── apis/
│   │   ├── services/
│   │   ├── utilities/
├── routes/
│   ├── index.svelte

上記の例では、各層に属するクラスやファイルを、更に細かい粒度で分割しています。例えば、Clean Architectureの場合、domain層にはentitiesディレクトリとrepositoriesディレクトリがあり、それぞれにビジネスロジックやデータアクセスのためのクラスが配置されています。また、Layered Architectureの場合、Infrastructure層にはdatabaseディレクトリやapisディレクトリがあり、それぞれにデータベースやAPIとのやりとりに必要なクラスが配置されています。

ただし、このように細かい粒度でディレクトリを分割する場合、それぞれの層が密接に結合することで、依存性が複雑化する可能性があります。そのため、実際のプロジェクトでは、必要最小限のディレクトリ分割で開発を進めることも多く、このような細かい分割は必ずしも必要ではありません。