Help us understand the problem. What is going on with this article?

【Svelte】最低限の修正でTypeScript対応してみました【初期設定】

概要

Svelteでcomponentを書く時に、中身をJSからTypescriptでかけるようにしました。
今回はデフォルトでできるプロジェクトに対して、最低限何があればTypescriptにできるかを重視してます。

なお、デフォルトに乗っ取りrollupを使用するのでwebpackとかでのやり方は対象外です。

手順

tsconfig.json追加

TypescriptのConfigファイルです。
こちらは手動での追加になります。

tsconfig.json
{
    "compilerOptions": {
      "target": "es6",
      "baseUrl": "./"
    },
    "include": [
      "./src"
    ]
  }

追加パッケージ

console
yarn add -D svelte-preprocess typescript rollup-plugin-typescript2 rollup-plugin-postcss

package.jsonの修正

"main": "src/index.ts",を追加

package.json
  "name": "svelte-app",
  "version": "1.0.0",
  "main": "src/index.ts",
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "start": "sirv public"
  },

main.jsをmain.tsに変更

main.ts
import App from './App.svelte';

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

svelte.d.tsの追加

これがないと、main.tsApp.svelteを読み込まない

svelte.d.ts
declare module "*.svelte" {
    interface ComponentOptions<Props> {
      target: HTMLElement;
      anchor?: HTMLElement;
      props?: Props;
      hydrate?: boolean;
      intro?: boolean;
    }

    interface Component<Props> {
      new (options: ComponentOptions<Props>): any;
      $set: (props: {}) => any;
      $on: (event: string, callback: (event: CustomEvent) => any) => any;
      $destroy: () => any;
      render: (props?: {}) => {
        html: string;
        css: { code: string; map?: string };
        head?: string;
      };
    }

    const component: Component<{}>;

    export default component;
}

rollup.config.jsの修正

importの追加

3種類のImportの追加

rollup.config.js
import typescript from "rollup-plugin-typescript2"
import typescriptCompiler from "typescript"
import sveltePreprocessor from "svelte-preprocess"

inputの修正

main.jsmain.tsに変更

rollup.config.js
input: 'src/main.ts',

svelte()の修正

svelte内に以下の3行を追加

rollup.config.js
extensions: [".svelte"]
preprocess: sveltePreprocessor()
emitCss: true

追加後のsvelte

rollup.config.js
        svelte({
            dev: !production,
            css: css => {
                css.write('public/build/bundle.css');
            },
            extensions: [".svelte"],
            preprocess: sveltePreprocessor(),
            emitCss: true,
        }),

postcss()とtypescript()の追加

Typescriptのトランスパイラと、Typescriptで書いた.svelteにCSSを適用させるpostcssを追加

rollup.config.js
        postcss({
            extract: true
        }),
        typescript({ typescript: typescriptCompiler }),

最終的なrollup.config.js

rollup.config.js
import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import postcss from "rollup-plugin-postcss"
import typescript from "rollup-plugin-typescript2"
import typescriptCompiler from "typescript"
import sveltePreprocessor from "svelte-preprocess"

const production = !process.env.ROLLUP_WATCH;

export default {
    input: 'src/main.ts',
    output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'public/build/bundle.js'
    },
    plugins: [
        svelte({
            dev: !production,
            css: css => {
                css.write('public/build/bundle.css');
            },
            extensions: [".svelte"],
            preprocess: sveltePreprocessor(),
            emitCss: true,
        }),
        resolve({
            browser: true,
            dedupe: ['svelte']
        }),
        postcss({
            extract: true
        }),
        typescript({ typescript: typescriptCompiler }),
        commonjs(),
        !production && serve(),
        !production && livereload('public'),
        production && terser()
    ],
    watch: {
        clearScreen: false
    }
};

function serve() {
    let started = false;

    return {
        writeBundle() {
            if (!started) {
                started = true;

                require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
                    stdio: ['ignore', 'inherit', 'inherit'],
                    shell: true
                });
            }
        }
    };
}

まとめ

冒頭にあったとおり最低限の修正なので、使いやすさを考えたらrollupをもう少しplugin追加したほうがよいです。
main.jsのTypescript化で詰まったり、CSS読み込みで詰まったりとありましたが
とりあえずそのあたりもクリアしてTypeScriptでSvelteが書けるようになりました。

追加 2020/03/09

恐らく、main.tsではなくmain.jsのままであれば、追加パッケージのtypescriptがいらないです。
rollupのtypescript({ typescript: typescriptCompiler }),この行もいらなくなります。

理由としては、. svelteファイルののts部分についてはsvelte-preprocessがトランスパイルしちゃうので使わないですね。
なのでmain.jsを極力コード量減らして、.tsにすることをこだわらなければ更に楽に書けると思います。

hisayuki
IT系ノマドワーカーです。主にWeb系だけどRuby未経験、PHPはあんま好きじゃない。メインはJVM言語、そろそろ他のやりたいなって思えてきてる。 最近使ってる: aws/terraform/spring/kotlin/Angular/Typescript/DDD/github/CICD 興味ある: serverless/自動化/gcp
https://hisa-tech.site
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした