SvelteでWeb Componentsを作成し、CDNから配布して使う
モチベーション
- SvelteでWeb Componentsを作りたい
- 作ったWeb ComponentsをCDNで配布して、ブラウザから読み込んで使えるようにしたい
サードパーティーのスクリプトを作るのにSvelteが適している理由は以下の記事にわかりやすくまとめられています。
SvelteでWeb Componentsをつくる
CounterコンポーネントとClockコンポーネントの計2つのコンポーネントを作ります。
まずはViteでアプリケーションの雛形をつくります。
yarn create vite svelte-web-components-example --template svelte-ts
lib/Counter.svelte
のファイル先頭に<svelte:options tag="my-counter" />
を追加してコンポーネントをカスタム要素としてコンパイルするようにします。
tag
で指定した文字列が、Web Componentsの名前となります。
<svelte:options tag="my-counter" />
<script lang="ts">
let count: number = 0
const increment = () => {
count += 1
}
</script>
<button on:click={increment}>
Clicks: {count}
</button>
<style>
button {
font-family: inherit;
font-size: inherit;
padding: 1em 2em;
color: #ff3e00;
background-color: rgba(255, 62, 0, 0.1);
border-radius: 2em;
border: 2px solid rgba(255, 62, 0, 0);
outline: none;
width: 200px;
font-variant-numeric: tabular-nums;
cursor: pointer;
}
button:focus {
border: 2px solid #ff3e00;
}
button:active {
background-color: rgba(255, 62, 0, 0.2);
}
</style>
Clockコンポーネントを作ります。同様にファイル先頭に<svelte:options tag="my-clock" />
を含めます。
<svelte:options tag="my-clock" />
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
let date = new Date().toLocaleTimeString();
let interval;
onMount(() => {
interval = setInterval(() => {
date = new Date().toLocaleTimeString()
}, 1000);
});
onDestroy(() => {
clearInterval(interval);
});
</script>
<span>{date|| '' }</span>
<style>
span {
font-family: inherit;
font-size: inherit;
padding: 1em 2em;
color: #ff3e00;
background-color: rgba(255, 62, 0, 0.1);
border-radius: 2em;
border: 2px solid rgba(255, 62, 0, 0);
outline: none;
width: 200px;
font-variant-numeric: tabular-nums;
cursor: pointer;
}
span:active {
background-color: rgba(255, 62, 0, 0.2);
}
</style>
main.ts
は2つのコンポーネントをexportするようにしておきます。
今回はApp.svelte
は使用しないので削除してしまって大丈夫です。
export * from './lib/Clock.svelte';
export * from './lib/Counter.svelte';
index.html
で先程作成したWeb Componentsを読み込んで表示するようにします。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Svelte + TS + Vite App</title>
</head>
<body>
<my-counter></my-counter>
<my-clock></my-clock>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
最後にvite.config.js
でコンパイルオプションを設定します。
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
svelte({
compilerOptions: {
customElement: true,
},
}),
],
});
ここまでできたらyarn dev
で起動すると以下のように、SvelteコンポーネントとしてではなくHTML上でWeb Componentsを読み込んで表示できているはずです。
作ったWeb Componentsをnpmに公開してCDNから配布する
今回は2つのコンポーネントを作成しました。
それを1つのファイルにバンドルするようビルドのオプションをvite.config.js
に指定します。
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
build: {
lib: {
entry: './src/main.ts',
name: 'MyLibrary',
fileName: (format) => `svelte-web-components-example.${format}.js`,
},
},
plugins: [
svelte({
compilerOptions: {
customElement: true,
},
}),
],
});
次にnpmにライブラリとして公開するにあたって、package.json
に以下を追加します。
"main": "dist/svelte-web-components-example.umd.js",
"module": "dist/svelte-web-components-example.es.js",
"unpkg": "dist/svelte-web-components-example.umd.js",
"files": [
"dist"
],
最後に、npmに公開します。
※パッケージの名前が既に存在している名前だと公開できないので注意してください。
npm login
npm publish
ブラウザ上からCDNでWeb Componentsを読み込んで使う
作ってnpmに公開したWeb Componentsをブラウザから読み込んで使います。
npmに公開したライブラリはunpkgというCDNで配布されるので、それを利用します。
https://unpkg.com/パッケージ名@バージョン/ファイル名
で読み込むことができます。
.es
と.umd
の形式の2種類で配布するようにしましたが、ブラウザからscriptタグで読み込む場合は.umd
の方を使えば良いです。
以下のHTMLだけでWeb Componentsを読み込んで動かすことができます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Svelte Web Components Example</title>
</head>
<body>
<my-counter></my-counter>
<my-clock></my-clock>
<script src="https://unpkg.com/svelte-web-components-example@0.0.0/dist/svelte-web-components-example.umd.js"></script>
</body>
</html>
まとめ
Svelteで2つのWeb Componentsを作って単一のファイルにバンドルし、npmに公開してそれをCDNからscriptタグで読み込んで素のHTML上でWeb Componentsを動かすことができました。
SvelteはSPAを作るだけでなく、Web Componentを作る際にも利用することができます。
似た選択肢として、LitやStencilなどがあると思いますが、これに並ぶ選択肢なのではないかと個人的には思っています。
・Lit
・Stencil
今回作成したリポジトリ
参考
Discussion