2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Svelteのチュートリアルをお試しでTypeScriptにしてみた

Posted at

はじめに

Svelte は、ReduxやVueのようなJavascriptフレームワークですが、以下のような点が異なるようです。いろいろ記事はあるようなので簡単に。

  • コードの記述量が減る: その分バグが少なくなる
  • 仮想DOMを使わない、ただのJavascriptとして動作する: ファイルサイズが小さくなり、構文解析や実行が速い
  • フレームワーク自体にストアのサポートがある

Svelteのチュートリアル

公式のチュートリアル にいろいろと書いてあります。
今回は、チュートリアル内<svelte:self>でのフォルダ階層表示をTypeScriptにしてみようと思います。
ただ、そもそもTypescriptに慣れていないためいろいろおかしいところがあると思います。

環境

Node.js: v14.15.3 (nvmで入れています)

プロジェクトの準備

公式のブログ Svelte <3 TypeScript に従って準備します。
npxは(恒久的な)インストールをせずに実行するnpmみたいなものっぽいです。npm v5.2.0以降で増えたらしい。そうなのか。
新しめのNode.jsをインストール済みであれば、ターミナルでプロジェクトを作成したいディレクトリを表示して、以下を実行すればSvelte+TypeScriptのプロジェクト作成は完了です。

npx degit sveltejs/template svelte-typescript-app
cd svelte-typescript-app
node scripts/setupTypeScript.js

npm install時になんか表示されるのが嫌なので、package.jsonを編集しておきます。

{
  "name": "svelte-app",
  "version": "1.0.0",
  "private": true, // <- この行を追加
  (略)
}

次に、もろもろインストールします。ここまでで、Svelte+TypeScriptが動作できるようになっています。

npm install

せっかくなので、Sassの準備もしておきます。今回の範囲では最終的に不要でしたが...
(こちらを参考にさせていただきました: Svelteとは?Reactの比較 / TypeScriptと Sassの導入方法 )
ちなみに、TypeScriptの準備でいいかんじになっているようなので、rollup.config.jsの編集は不要でした。

npm install -D sass

最後に、VSCodeであればこちらの拡張機能を入れておくと便利そうです: Svelte for VS Code

ここまででもろもろインストールされたバージョン

  • Svelte: 3.31.1
  • Typescript: 3.9.7
  • Sass: 1.32.0

コーディング

これ以降、パスはsvelte-typescript-app/srcをルート扱いとします。
公式のチュートリアルIntroductionのセクション(現時点で7ページ分)と、LogicのセクションのうちIf blocksElse blocksEach blocks、を先に読んでおくとよいと思います。

1. ファイルのデータ型を準備

ただの型定義TypeScriptファイルです。

repositories/Files.ts
// ファイル種類の列挙型
export enum FileType {
    // フォルダ
    folder,
    // ファイル
    file,
};

// ファイル情報1件
export type FileItem = {
    // ファイル名
    name: string;
    // ファイル種類
    type: FileType;
    // 子階層(フォルダの時用)
    children?: Array<FileItem>;
};

2. ファイルアイコン(コンポーネント)の準備

SVGファイルは、マテリアルデザインのアイコンをいただきました。
folder, folder_open, text_snippetです。

components/icons/FileIcon.svelte
<script lang="ts">
export let size: number = 24; // アイコンのサイズ
</script>

<style lang="scss">
svg {
    vertical-align: text-bottom;
}
</style>
    
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="{size}" viewBox="0 0 24 24" width="{size}">
  <g>
    <rect fill="none" height="24" width="24"/>
    <path d="M20.41,8.41l-4.83-4.83C15.21,3.21,14.7,3,14.17,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V9.83 C21,9.3,20.79,8.79,20.41,8.41z M7,7h7v2H7V7z M17,17H7v-2h10V17z M17,13H7v-2h10V13z"/>
  </g>
</svg>
components/icons/FolderIcon.svelte
<script lang="ts">
export let size: number = 24; // アイコンのサイズ
export let open: boolean = false; // 開閉(true=開いている)
</script>

<style lang="scss">
svg {
    vertical-align: text-bottom;
}
</style>

<svg xmlns="http://www.w3.org/2000/svg" height={size} viewBox="0 0 24 24" width={size}>
  <path d="M0 0h24v24H0z" fill="none"/>
  {#if open}
  <path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z"/>
  {:else}
  <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
  {/if}
</svg>

3. ファイル表示のコンポーネント作成

components/files/File.svelte
<script lang="ts">
import FileIcon from '../icons/FileIcon.svelte';

export let name: string; // ファイル名
</script>

<FileIcon size={18}/>
<span>{name}</span>

4. フォルダ表示のコンポーネント作成

開閉の処理があるのでやや長いです。

components/files/Folder.svelte
<script lang="ts">
import FolderIcon from "../icons/FolderIcon.svelte";
import File from "./File.svelte";
import type { FileItem } from "../../repositories/Files";
import { FileType } from "../../repositories/Files";
import { slide } from 'svelte/transition';

export let folder: FileItem; // ファイル情報
export let expanded: boolean = false; // 開閉の状態(true=開いている)

// 開閉の切り替え
function toggle() {
    expanded = !expanded;
}
</script>

<style lang="scss">
div {
  cursor: pointer;
  display: inline-block;
}
ul {
  list-style-type: none;
  padding-inline-start: 20px;
}
li {
  margin-block-start: 5px;
}
li:first-child {
  margin-block-start: 0;
}
p {
  margin-block: 0;
  padding-inline-start: 20px;
}
</style>

<div on:click={toggle}>
  <FolderIcon size={18} open={expanded} />
  <span class:expanded>{folder.name}</span>
</div>

{#if expanded}
{#if folder.children && folder.children.length > 0}
<ul transition:slide>
  {#each folder.children as item}
    <li>
      {#if item.type == FileType.folder}
      <svelte:self folder={item} />
      {:else}
      <File {...item}/>
      {/if}
    </li>
  {/each}
</ul>
{:else}
<p transition:slide>空っぽだよ</p>
{/if}
{/if}

5. App.svelte作成

components/App.svelte
<script lang="ts">
import Folder from './files/Folder.svelte';
import type { FileItem } from '../repositories/Files';
import { FileType } from '../repositories/Files';

// 表示するフォルダ階層の内容
const root: FileItem = {
    name: 'root',
    type: FileType.folder,
    children: [
        {
            name: 'file1',
            type: FileType.file,
        },
        {
            name: 'folder2',
            type: FileType.folder,
        },
        {
            name: 'folder3',
            type: FileType.folder,
            children: [
                {
                    name: 'file2',
                    type: FileType.file,
                },
                {
                    name: 'folder4',
                    type: FileType.folder,
                    children: [],
                },
            ],
        },
    ],
};
</script>

<h1>Explorer</h1>
<Folder folder={root} />

6. main.ts修正

main.ts
//import App from './App.svelte'; // 元のApp.svelte
import App from './components/App.svelte'; // 新しいApp.svelte

const app = new App({
	target: document.body,
	props: {
		name: 'world'
	}
});

export default app;

最終的なみため

ターミナルから起動します。Svelte+TypeScript+SassがJavascriptとCSSにコンパイルされ、ブラウザで表示可能となります。

cd svelte-typescript-app
npm run dev

localhostの5000番ポートで起動するので、ブラウザで http://localhost:5000 にアクセスすると、以下のように表示されます(フォルダを開閉できます)。
また、ソースコードの変更を保存すると自動で表示が変わります。変わらなくなった場合はブラウザでリロードしてみてください。

image.png

npm run buildすれば、難読化されたJSファイルが出力されます。
出力先は public/build です。npm run devと同じ場所なので、互いに上書きされます。(rollup.config.jsを編集すればbuldとdevで出力先を変えられるとは思います)

はまったところ

TypeScript 3.8以降で、import typeが増えたみたいです。
ただのimportだとコンパイルのエラーになりました。

今回は以上です。続くかも。

参考まとめ

Svelte: Svelte公式トップ
Svelte <3 TypeScript: Svelte公式のTypescript導入方法
Svelteとは?Reactの比較 / TypeScriptと Sassの導入方法: Sass導入参考
Svelte for VS Code: VSCodeのSvelte拡張機能
Icons - Material Design: マテリアルデザインのアイコン一覧

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?