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

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

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

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

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


### 追加パッケージ
```bash:console
yarn add -D svelte-preprocess typescript rollup-plugin-typescript2 rollup-plugin-postcss
```

### package.jsonの修正

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

```json: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に変更

```typescript:main.ts
import App from './App.svelte';

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



### svelte.d.tsの追加
これがないと、`main.ts`が`App.svelte`を読み込まない

```typescript: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の追加

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

#### inputの修正
`main.js`を`main.ts`に変更

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

#### svelte()の修正
`svelte`内に以下の3行を追加

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

追加後の`svelte`

```javascript: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`を追加


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

#### 最終的なrollup.config.js

```javascript: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`にすることをこだわらなければ更に楽に書けると思います。