【2021年6月版】Windows10でSvelteKit+TypeScript+Electronの開発環境をサクッと構築

# Windows10にてTypeScript版のSvelteKit+Electronの環境をサクッと構築してみよう。

Electronについて今更ご紹介することはないと思いますので、以下をご覧ください。

https://www.electronjs.org/

SvelteKitはまだ絶賛開発中ですが非常に開発が楽チンなので将来有望なプロジェクトであります。

https://kit.svelte.dev/

またSvelteについては以下が公式サイトとなります。

https://svelte.dev/

さて、SvelteKit+Electronのプロジェクトテンプレートはいくつか発見いたしました。

https://github.com/FractalHQ/sveltekit-electron

https://github.com/Dax89/electron-sveltekit

ただしこのプロジェクトテンプレートではJSを使っておりまして、せっかくSvelteKitですので`TypeScript`での開発環境を構築してみようと、さらにWindows10で構築してみよう、というアグレッシブな内容となっております。

今回、作業する環境のバージョンは以下となります。

- Windows 10 Pro
- node.js v14.16.1

ビルドの設定やエントリーポイントのcjs等はプロジェクトテンプレートを参考に調整していきます。

## 1. SvelteKitのプロジェクト開始

今回は先にGitなどでリポジトリを作成しておきます。

### 1-1. SvelteKitのプロジェクト生成

作成したフォルダに入り、`npm init svelte@next`でプロジェクトの初期化をします。

```bash
$ npm init svelte@next
...
√ Directory not empty. Continue? ... yes
√ Which Svelte app template? » SvelteKit demo app
√ Use TypeScript? ... No / Yes
√ Add ESLint for code linting? ... No / Yes
√ Add Prettier for code formatting? ... No / Yes
...
Next steps:
  1: npm install (or pnpm install, etc)
  2: git init && git add -A && git commit -m "Initial commit" (optional step)
  3: npm run dev -- --open

To close the dev server, hit Ctrl-C
...
```
というわけで今回は`SvelteKit demo app`を追加、`TypeScript`、`ESLint`と`Prettier`を追加します。

いったん、`npm i`しておきます。

```bash
$ npm i
...
```

### 1-2. static-adapterの使用とSSRの停止

Electronではサーバーサイドの処理は不要なので`SSR`の停止と、以下の`static-adapter`を使用します。

https://github.com/sveltejs/kit/tree/master/packages/adapter-static

こちらの手順に従ってセットアップを行います。

```
$ npm i -D @sveltejs/adapter-static@next
```

続いてアダプターの設定を変更します

```js:svelte.config.js
import adapter from '@sveltejs/adapter-static';

export default {
	kit: {
		adapter: adapter({}),
		target: '#svelte',
		ssr: false
	}
};
```

### 1-3. いったん動作確認

ここでいったん`npm run dev`してみましょう。

以下のようにHomeが表示できればOKです。
![SvelteKit_Home.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/ac18f4ec-e591-7c0f-a116-c692ed192b91.png)
Todoページもちゃんと動いています。
![SvelteKit_Todos.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/fe466cdd-3e28-f0c6-c13d-0d14d4bd7f91.png)

## 2. Electronの追加

いよいよ`Electron`の追加です。

### 2-1. パッケージの追加

以下のコマンドで`Electron`と開発用の追加パッケージを追加します。

```bash
$ npm i -D electron electron-builder electron-connect electron-packager electron-reloader electron-updater concurrently cross-env
...
$ npm i electron-context-menu electron-serve electron-window-state
```

### 2-2. `build.config.json`の作成

続いて `build.config.json`を作成します。

```json:build.config.json
{
	"appId": "com.example.app",
	"productName": "Svelte Electron",
	"directories": {
		"output": "dist"
	},
	"files": [
		"src/electron.cjs",
		{
			"from": "build",
			"to": ""
		}
	]
}
```

### 2-3. `package.json`の修正

以下のように`package.json`のビルドスクリプトを追加します。また、起点のスクリプトを`src/electron.js`にしておきます。

```json:package.json
{
...
  "main": "src/electron.cjs",
...
    "scripts": {
    "dev": "set NODE_ENV=dev && npm run dev:all",
    "dev:all": "concurrently -n=svelte,electron -c='#ff3e00',blue \"npm run dev:svelte\" \"npm run dev:electron\"",
    "dev:svelte": "svelte-kit dev",
    "dev:electron": "electron src/electron.cjs",
    "build": "cross-env NODE_ENV=production npm run build:svelte && npm run build:electron",
    "build:svelte": "svelte-kit build",
    "build:electron": "electron-builder -w --config build.config.json",
    "start": "svelte-kit start",
...
}
```

### 2-4. `electron.cjs`の追加

[`electron.cjs`はテンプレートのプロジェクト](https://github.com/FractalHQ/sveltekit-electron/blob/master/src/electron.cjs)を参考に、というかそのまま拝借いたします。

<details><summary>`electron.cjs`</summary><div>

```js:src/electron.cjs
const windowStateManager = require('electron-window-state');
const contextMenu = require('electron-context-menu');
const { app, BrowserWindow } = require('electron');
const serve = require('electron-serve');

try {
	require('electron-reloader')(module);
} catch (e) {
	console.error(e);
}

const serveURL = serve({ directory: "." });
const port = process.env.PORT || 3000;
const dev = !app.isPackaged;
let mainWindow;

function createWindow() {
	let windowState = windowStateManager({
		defaultWidth: 800,
		defaultHeight: 600,
	});
	
	const mainWindow = new BrowserWindow({
		backgroundColor: 'whitesmoke',
		titleBarStyle: 'hidden',
		autoHideMenuBar: true,
		trafficLightPosition: {
			x: 17,
			y: 32,
		},
		minHeight: 450,
		minWidth: 500,
		webPreferences: {
			enableRemoteModule: true,
			contextIsolation: true,
			nodeIntegration: true,
			spellcheck: false,
			devTools: dev,
		},
		x: windowState.x,
		y: windowState.y,
		width: windowState.width,
		height: windowState.height,
	});

	windowState.manage(mainWindow);

	mainWindow.once('ready-to-show', () => {
		mainWindow.show();
		mainWindow.focus();
	});

	mainWindow.on('close', () => {
		windowState.saveState(mainWindow);
	});

	return mainWindow;
}

contextMenu({
	showLookUpSelection: false,
	showSearchWithGoogle: false,
	showCopyImage: false,
	prepend: (defaultActions, params, browserWindow) => [
		{
			label: 'Make App 💻',
		},
	],
});

function loadVite(port) {
	mainWindow.loadURL(`http://localhost:${port}`).catch((e) => {
		console.log('Error loading URL, retrying', e);
		setTimeout(() => {
			loadVite(port);
		}, 200);
	});
}

function createMainWindow() {
	mainWindow = createWindow();
	mainWindow.once('close', () => { mainWindow = null });

	if (dev) loadVite(port);
	else serveURL(mainWindow);
}

app.once('ready', createMainWindow);
app.on('activate', () => {
	if (!mainWindow) {
		createMainWindow();
	}
});
app.on('window-all-closed', () => {
	if (process.platform !== 'darwin') app.quit();
});
```

</div></details>

## 3. Electronの動作確認

では `Electron` の動作確認をしてみましょう。

```bash
$ npm run dev
...
```

以下のようなウィンドウが上がったらＯＫです。
![Electron_Home.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/7de42132-19ac-9c1f-41c2-f944500e4f3a.png)
Todoウィンドウも動いてます。
![Electron_TODO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/f609c690-0f87-eb48-9cab-a7099ccbd56a.png)
ToDoの追加や操作などもちゃんと行えます。しっかり、動いてますね。

はい、無事に動きました！

Svelte+TypeScriptでサクサクと画面が作成できるので、ちょっとしたクライアントツールなどこれで簡単に作成できそうですね。
今回はWindows上での開発環境でしたが、他のOSに持っていけばそのまま別環境でのアプリとしてビルド可能です。

さらにSVGの生成やd3.jsなども使えばいろいろダッシュボードもめっちゃ簡単に作成出来そう。。。

ただしWindowsネイティブの処理は`electron.cjs`に詰め込まれていますのでここもTypeScriptにするにはもう一工夫必要そうです。

ここまでのアウトプットは以下のリポジトリに上げておきました。

https://github.com/Yoshinori-Koide-PRO/sveltekit-ts-electron-sample

ご参考までに。

本日はここまでといたします。