【Svelte】Typescriptで入門する
はじめに
ViteでVueのプロジェクトをビルドするたびにSvelteが気になっていたのと、Svelteのコード量の少なさに魅かれたので試していきます
Svelte
Svelte公式
Svelte公式 日本語訳 <-最近できた
Svelteの特徴は
コード量が少ない
仮想DOMじゃない
Reactive
Svelteで書いたコードはフレームワークではないシンプルなJavascript(VanillaJS)に出力される
ReactやVueと大きく違うところは仮想DOMではないってところだと思う
仮想DOMは早いぞ!って謳われているのを聞いてきたので差分取らないから遅いんじゃないの!って思った
どれくらい少ないか
一番シンプルなカウンターで比べてみる
React
import React, { useState } from 'react';
export default function Counter() {
const [count, counter] = useState(0);
return (
<div>
<button onClick={() => counter(count + 1)}>count:{count}</button>
</div>
);
}
Vue
<template>
<button v-on:click="counter">count:{{count}}</button>
</template>
<script>
export default {
data: () => ({
count: 0,
}),
methods: {
counter() {
this.count++;
}
}
}
</script>
Svelte
<script>
let count = 0;
function counter() {
count++;
}
</script>
<button on:click={counter}></button>
確かにかなりコード量は少ない(フレームワークとして見たら...)
仮想DOMとは
小さいDOMツリーを作って差分ロードしますよって仕組み
Virtual DOMのことでShadow DOM(CSSをスコープ化する技術)ではない
svelteの開発者によると仮想DOMは早いが余計な処理が増えるとのこと
そして仮想DOMを使わなくても同じプログラミングモデルが実現できるよう
規模が大きくなればその分差分も増えるってことで、その方法以外にあるならそっちの方が良い
インストールと起動
環境
Node v15.14.0
インストール
npx degit sveltejs/template [プロジェクトの名前]
フォルダができたら
cd [プロジェクトの名前]
yarn
yarnのとこはnpm installでも良い
起動
yarn dev
or
npm run dev
...はっや
まあ、起動だけなら変化もないし仮想DOMの比較にはならないけど
svelteでTypescriptを使う
公式で設定ファイルを書き換えてくれるスクリプトがあるので使います
公式を見に行く
node scripts/setupTypescript.js
scripts/setupTypescript.jsの中身
// @ts-check
/** This script modifies the project to support TS code in .svelte files like:
<script lang="ts">
export let name: string;
</script>
As well as validating the code for CI.
*/
/** To work on this script:
rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template
*/
const fs = require("fs")
const path = require("path")
const { argv } = require("process")
const projectRoot = argv[2] || path.join(__dirname, "..")
// Add deps to pkg.json
const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"))
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
"svelte-check": "^2.0.0",
"svelte-preprocess": "^4.0.0",
"@rollup/plugin-typescript": "^8.0.0",
"typescript": "^4.0.0",
"tslib": "^2.0.0",
"@tsconfig/svelte": "^2.0.0"
})
// Add script for checking
packageJSON.scripts = Object.assign(packageJSON.scripts, {
"check": "svelte-check --tsconfig ./tsconfig.json"
})
// Write the package JSON
fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " "))
// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too
const beforeMainJSPath = path.join(projectRoot, "src", "main.js")
const afterMainTSPath = path.join(projectRoot, "src", "main.ts")
fs.renameSync(beforeMainJSPath, afterMainTSPath)
// Switch the app.svelte file to use TS
const appSveltePath = path.join(projectRoot, "src", "App.svelte")
let appFile = fs.readFileSync(appSveltePath, "utf8")
appFile = appFile.replace("<script>", '<script lang="ts">')
appFile = appFile.replace("export let name;", 'export let name: string;')
fs.writeFileSync(appSveltePath, appFile)
// Edit rollup config
const rollupConfigPath = path.join(projectRoot, "rollup.config.js")
let rollupConfig = fs.readFileSync(rollupConfigPath, "utf8")
// Edit imports
rollupConfig = rollupConfig.replace(`'rollup-plugin-terser';`, `'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';`)
// Replace name of entry point
rollupConfig = rollupConfig.replace(`'src/main.js'`, `'src/main.ts'`)
// Add preprocessor
rollupConfig = rollupConfig.replace(
'compilerOptions:',
'preprocess: sveltePreprocess({ sourceMap: !production }),\n\t\t\tcompilerOptions:'
);
// Add TypeScript
rollupConfig = rollupConfig.replace(
'commonjs(),',
'commonjs(),\n\t\ttypescript({\n\t\t\tsourceMap: !production,\n\t\t\tinlineSources: !production\n\t\t}),'
);
fs.writeFileSync(rollupConfigPath, rollupConfig)
// Add TSConfig
const tsconfig = `{
"extends": "@tsconfig/svelte/tsconfig.json",
"include": ["src/**/*"],
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
}`
const tsconfigPath = path.join(projectRoot, "tsconfig.json")
fs.writeFileSync(tsconfigPath, tsconfig)
// Add global.d.ts
const dtsPath = path.join(projectRoot, "src", "global.d.ts")
fs.writeFileSync(dtsPath, `/// <reference types="svelte" />`)
// Delete this script, but not during testing
if (!argv[2]) {
// Remove the script
fs.unlinkSync(path.join(__filename))
// Check for Mac's DS_store file, and if it's the only one left remove it
const remainingFiles = fs.readdirSync(path.join(__dirname))
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') {
fs.unlinkSync(path.join(__dirname, '.DS_store'))
}
// Check if the scripts folder is empty
if (fs.readdirSync(path.join(__dirname)).length === 0) {
// Remove the scripts folder
fs.rmdirSync(path.join(__dirname))
}
}
// Adds the extension recommendation
fs.mkdirSync(path.join(projectRoot, ".vscode"), { recursive: true })
fs.writeFileSync(path.join(projectRoot, ".vscode", "extensions.json"), `{
"recommendations": ["svelte.svelte-vscode"]
}
`)
console.log("Converted to TypeScript.")
if (fs.existsSync(path.join(projectRoot, "node_modules"))) {
console.log("\nYou will need to re-run your dependency manager to get started.")
}
tsconfigやrollup.configを作成してくれる
起動
src/App.svelte
を下記のように書き換える
<script lang="ts">
export let name: string;
let countStore: number = 0;
function count() {
return ++countStore;
}
</script>
<main>
<h1>Hello {name}!</h1>
<p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
<button on:click="{count}">{ countStore }</button>
</main>
<style>
main {
text-align: center;
padding: 1em;
max-width: 240px;
margin: 0 auto;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 4em;
font-weight: 100;
}
@media (min-width: 640px) {
main {
max-width: none;
}
}
</style>
yarn check
をターミナルで打つと書き方が正しいかみてくれるので実行します。
yarn check
問題なさそう...実行!
hintsがでてめんどくさい時は、一旦消したい時にはpackage.json
内のコマンドyarn check
に--threshold warning
を追加します
warningだけ出るので、warningを修正したら戻しておくと良いです 新しくコマンドを追加してもOKです
チェックを飛ばしたいファイルがあれば--ignore ファイル名
で飛ばせます
yarn dev
vueで最初に出てくるcounterみたいなのができた
SCSSを使う
typescriptでrollup.config.jsを書き換えてあるのでインストールするだけでOK
yarn add -D sass
src/App.svelte
を編集する
<script lang="ts">
export let name: string;
let countStore: number = 0;
function count() {
return ++countStore;
}
</script>
<main>
<h1>Hello {name}!</h1>
<p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
<button on:click="{count}">{ countStore }</button>
</main>
<style lang="scss">
main {
text-align: center;
padding: 1em;
max-width: 240px;
margin: 0 auto;
@media (min-width: 640px) {
max-width: none;
}
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 4em;
font-weight: 100;
}
</style>
styleの部分にlang="scss"
を追加して、
mainの中に@mediaを入れた
実行するとちゃんとレスポンシブになっているので反映されてるよう
Vite + Svelte
svelte + rollupとは別の話
viteで立ち上げたら設定何もいらないのでおまけで書いておきます
yarn create @vitejs/app vite-svelte
vite-svelte
のところはアプリの名前を入れる
選択項目でsvelteを選んでsvelte-tsを選ぶ
yarn add -D sass
yarn
src/App.svelte
をscssに書き換えて
<script lang="ts">
import logo from './assets/svelte.png'
import Counter from './lib/Counter.svelte'
</script>
<main>
<img src={logo} alt="Svelte Logo" />
<h1>Hello Typescript!</h1>
<Counter />
<p>
Visit <a href="https://svelte.dev">svelte.dev</a> to learn how to build Svelte
apps.
</p>
<p>
Check out <a href="https://github.com/sveltejs/kit#readme">SvelteKit</a> for
the officially supported framework, also powered by Vite!
</p>
</main>
<style lang="scss">
:root {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
main {
text-align: center;
padding: 1em;
margin: 0 auto;
}
img {
height: 16rem;
width: 16rem;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 4rem;
font-weight: 100;
line-height: 1.1;
margin: 2rem auto;
max-width: 14rem;
@media (min-width: 480px) {
max-width: none;
}
}
p {
max-width: 14rem;
margin: 1rem auto;
line-height: 1.35;
@media (min-width: 480px) {
max-width: none;
}
}
</style>
<style lang="scss">
と@mediaの位置を書き換えてる
yarn dev
何一つエラーなくHello Worldできると好印象
~sveltekitに切り替えられるとあるけどまだベータ版だし見送り~ 今このサイトSveltekitを使って作ってます!