Svelte触ってみた
こんにちはkirigayaです
JS系よく知らないですがSvelte触ってみようと思います
この記事は環境構築から恒例の挨拶までです
それでは早速
Svelteの特徴
- コンパイル時フレームワーク
- 高速:仮想DOMがないので動作が軽い
- コードが少ない:宣言的でシンプル
- ビルド後はバニラJSになるので軽量
- 学習コストが低い:ほぼHTML/CSS/JSの延長
仮想DOMとは?
UI全体のスナップショットを毎回作り差分計算してから更新する仕組み
ふむふむ...それでは早速
devコンテナ使って開発していきます
{
"name": "streamlit_component",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"workspaceFolder": "/workspaces/streamlit_component",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "22"
}
},
"postCreateCommand": "sh -c \"curl -fsSL https://claude.ai/install.sh | bash || true; pip install uv || true; mkdir -p app; cd app; uv sync || true; uv add streamlit || true\"",
"portsAttributes": {
"5173": {
"label": "Streamlit_component",
"onAutoForward": "notify"
}
}
}
プロジェクト作成
web上で.svelteを動かすこともできます
フォルダ構成
プロジェクトを作成するとデフォルトである程度作成されます
my-svelte-app/
├─ index.html
├─ package.json
├─ vite.config.js
└─ src/
├─ main.js ← エントリーポイント(App.svelte を読み込む)
└─ hello.svelte
プロジェクトの作成
npm create vite@latest my-svelte-app --template svelte
解説
分解すると:
npm create
→ npm(Node のパッケージ管理ツール)に「新しいプロジェクトを作って」と依頼
vite@latest
→ Vite(ビルドツール)の一番新しいバージョンを使う
(Vite は Svelte プロジェクトを動かすエンジン)
my-svelte-app
→ 作成するフォルダの名前(好きな名前で OK)
--template svelte
→ 「Svelte 用のテンプレートを使ってください」
実行すると色々訊かれるので選んでいきます
Need to install the following packages:
create-vite@8.2.0
Ok to proceed? (y) y
> npx
> create-vite my-svelte-app svelte
│
◇ Select a framework:
│ Vanilla
│
◇ Select a variant:
│ JavaScript
│
◇ Use rolldown-vite (Experimental)?:
│ No
│
◇ Install with npm and start now?
│ Yes
│
◇ Scaffolding project in /workspaces/streamlit_meetup/my-svelte-app...
│
└ Done. Now run:
cd my-svelte-app
npm install
npm run dev
-
Use rolldown-vite (Experimental)?:
“No” で OK(安全・安定)rolldown とは?
Vite の新しいビルドエンジン(内部で使われる“コンパイラ的なもの”)
Rust で書かれていて とても速い
まだ実験的(Experimental)なので 完全に安定していない -
Install with npm and start now?
noを選択します。コンテナ使ってない場合はyesで問題ないです
自動で npm install と npm run dev をやってくれます。
「Yes」を選んだ場合:npm install
→ プロジェクト内の依存パッケージを全部インストール
イメージとしては
Python の pip install -r requirements.txt と同じ
必要なモジュールをまとめて準備してくれる
Vite や Svelte 本体などがここでインストールされます。 -
npm run dev
→ 開発サーバーを起動
→ ブラウザで http://localhost:5173 が開ける
→ Svelte の画面が表示される
今回はコンテナ環境を使っているので以下のコマンドを実行します
npm install
npm run dev -- --host
npm run dev -- --host を付けると Vite のサーバーがコンテナ内の「すべてのネットワークインターフェース(0.0.0.0)」で待ち受けるようになります。
これにより、コンテナ外(ホストOS / ブラウザ)からアクセスできるようにります。
ポートフォワードだけではダメな理由と設定方法
状況整理
- DevContainer 内で Vite サーバーを起動
- VSCode がポップアップで「Port 5173 を Forward しますか?」と出た
- そのまま Yes を押したがブラウザで表示されなかった
- npm run dev -- --host で動いた
ポートフォワードだけではダメな理由
VSCode のポップアップでのポートフォワードは、あくまで コンテナ内の指定ポートをホストに開通させる仕組み です。
例:コンテナの 5173 → ホストの 5173 にマッピング
しかし Vite サーバー自体が localhost (127.0.0.1) にしかバインドされていない場合、外部(ホスト側)から接続できません
[ホストブラウザ] → [ホストのポート5173] → [コンテナの127.0.0.1:5173]
- 127.0.0.1 は「コンテナ内部だけ」のアドレスなので、外部から見えない
- ポートフォワードはしているが「到達できる場所がない」状態
--host を付けるとどう変わるか
npm run dev -- --host は、Vite サーバーを 0.0.0.0 にバインドします
[ホストブラウザ] → [ホストのポート5173] → [コンテナの0.0.0.0:5173] ○
ポートフォワードは「道を作るだけ」
サーバーがその道を通れるように開いていないと意味がない
だから --host が必要だった
全開放ではなく特定の道(IP)だけを用意する方法
全インターフェース(0.0.0.0)ではなく、特定のネットワークや IP にだけ接続を許可することが可能です
状況整理
- 0.0.0.0 → 全てのネットワークから接続可能(便利だけど全開放)
- 127.0.0.1 → 自分のコンテナ内だけ
- 特定の IP / インターフェース に限定
Vite 側でホスト指定
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
server: {
host: '192.168.1.100', // この IP だけアクセス可能
port: 5173
}
})
コンテナ内からホストの IP を調べる
ip route
- ここで指定する IP は コンテナ内から見えるホスト側 IP です
- この IP 以外からはアクセスできません
OS/コンテナ側でファイアウォールを使う方法
sudo iptables -A INPUT -p tcp -s 192.168.1.50 --dport 5173 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 5173 -j DROP
- 0.0.0.0 → 家の全てのドアと窓を開放
- 特定 IP 指定 → 家の玄関だけを特定の友達に開ける
- ファイアウォール → 家の外壁に番人を置いて、許可した人だけ通す
開発中は簡単に --host で全開放してもOK
Hello Worldを作成
my-svelte-app/src/hello.svelteファイルを作成
<script>
let name = "World";
</script>
<h1>Hello {name}!</h1>
my-svelte-app/src/main.js
import { mount } from 'svelte';
import Hello from './hello.svelte';
const app = mount(Hello, {
target: document.getElementById('app')
});
export default app;
my-svelte-app/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Svelte Hello</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
my-svelte-app/package.json
{
"name": "my-svelte-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"svelte": "^5.45.2",
"vite": "^7.2.4"
}
}
my-svelte-app/vite.config.js
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
plugins: [svelte()],
server: {
host: true,
port: 5173
}
});
解説
ブラウザが最初に読むファイル
index.html
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
- ブラウザはまず HTML を読み込みます
- <script type="module" src="/src/main.js"> があるので、最初に main.js をモジュールとして実行します
- <div id="app"></div> が Svelte コンポーネントをマウントする場所になります
main.js が呼ばれる
import { mount } from 'svelte';
import Hello from './hello.svelte';
const app = mount(Hello, {
target: document.getElementById('app')
});
export default app;
- main.js は エントリーポイント(入口)
- ここで hello.svelte を import します
- mount(Hello, { target: ... }) によって、Hello コンポーネントが div#app に描画されます
- 注意: Svelte 5 では mount を使いSvelte 4では new Hello({ target: ... }) をつかう
hello.svelte が呼ばれる
<script>
let name = "World";
</script>
<h1>Hello {name}!</h1>
- main.js が import するタイミングでコンパイル済み JS に変換される
- <script> 内の変数 name を準備
- <h1> タグの中に name の値を挿入
- これが div#app 内に描画されます
vite.config.js の役割
export default defineConfig({
plugins: [svelte()],
server: { host: true, port: 5173 }
});
- Vite がサーバーを起動する際の設定
- plugins: [svelte()] によって .svelte ファイルをコンパイル可能にする
- server.host / server.port は DevContainer 外部からアクセスできるようにする設定
- ブラウザ側で実行される順序には直接関係ない(コンパイルと開発サーバーの設定)
package.json の役割
- scripts.dev → npm run dev で Vite サーバーを立ち上げ
- devDependencies → プロジェクトに必要なパッケージ(svelte, vite, vite-plugin-svelte)
呼ばれる順序 図
index.html
└─> main.js
└─> hello.svelte (コンパイル + インスタンス化)
└─> #app に描画
今回はここまでです。なかなか挨拶文が表示されず苦戦しました...特に通信の部分...
お疲れ様でした!次はStreamlitのカスタムコンポーネントを作っていきます
Discussion