[W.I.P.] 【実況】Vue の 50 倍の速度が出るらしい「Svelte」のライブラリ「Sapper」を使って人生初のポートフォリオを作ってみる

前提として，
1. GitHub にリポジトリを作っただけの段階で記事を書き始めています。
2. Svelte を触ったことは一度もありません。ドキュメントも今から読みます。
3. ~~２日以内を目標に~~ GitHub Pages に公開するまで随時更新します。
4. (2020/02/01) 2日以内とはなんだったのか状態ですが，前述の通り公開までは随時更新します :bow:

## 目次
[0. はじめに - Svelte って何](#0-はじめに---svelte-って何)
[1. 動機](#1-動機)
[2. 実装](#2-実装)

## 0. はじめに - Svelte って何？
あなたは Svelte をご存知ですか？　私は２日前にはじめて知りました :neutral_face:

[公式サイト](https://svelte.dev/)には次のように説明があります。

> Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app.

> Instead of using techniques like virtual DOM diffing, Svelte writes code that surgically updates the DOM when the state of your app changes.

> *"Svelte・Cybernetically enhanced web apps" from https://svelte.dev*

:rolling_eyes:「ほーん（Google 翻訳つかお）」

グーグル先生「Svelte は、ユーザーインターフェイスを構築するための根本的な新しいアプローチです。 React や Vue のような従来のフレームワークはブラウザーで大部分の作業を行いますが、Svelte はその作業をアプリのビルド時に発生するコンパイルステップに移行します。 仮想 DOM 差分のような手法を使用する代わりに、Svelte はアプリの状態が変化したときに外科的に DOM を更新するコードを記述します。」

:yum:「よくわからんけど
　『React や Vue は仮想 DOM 越しに JavaScript を動かすからブラウザに負荷がかかって重い』
　『仮想 DOM は遅いから使わないようにしたぜ』
　『ついでにコンパイルのときに最適化もかけてやるぜ』
　みたいな話かな（ふんいきでものを言っています）」

## 1. 動機

2日前に Qiita でこういった記事を見かけまして，Vue 好きの私[^footnote]としては「Vue の 50 倍!?」「構文は Vue ライク!?」「これは試さなければ!!!」という感じで Svelte 使って何か作ることにしました

[^footnote]: nuxt-create-app の TypeScript 対応が待ちきれなかったので [Nuxt+TypeScript のテンプレート](https://qiita.com/u-sho/items/7fc33381e154510a8a84) を作ったりしています

> 
[ReactとVueを改善したSvelteというライブラリーについて](https://qiita.com/so99ynoodles/items/a8144ced1a21467c6300)
ベンチマークでReactの35倍、Vueの50倍速いです。
![image](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F375274%2F2a2ccb0b-a3fc-8e9f-2675-43f9c5c06982.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=10f097d0f1e14416fcbd1b2ad33e927f)

~~ToDo アプリみたいな完成しても使わないものは作ってる途中で飽きちゃうので，~~ ちょうどポートフォリオサイトを何で作るか悩んでいたので，自分のポートフォリオサイトを作ることにしました :laughing:

## 2. 実装
前述のとおりこれからやって行きます(ここまで：2020/01/26 04:37:42)

### 2.1 Svelte インストール
とりあえず公式ドキュメントの[ここ](https://svelte.dev/blog/the-easiest-way-to-get-started#2_Use_degit)を参考に， [GitHub で作ったリポジトリ](https://github.com/u-sho/portfolio)を clone して，
degit コマンドを使ってテンプレを作りました。

<details><summary> $ npx degit sveltejs/template svelte-app </summary><div>

```bash
u-sho@~/github/u-sho/svelte-app (master=)$ npx degit sveltejs/template app
npx: 32個のパッケージを3.88秒でインストールしました。
> cloned sveltejs/template#master to app

u-sho@~/github/u-sho/svelte-app (master %=)$ mv app/* ./

u-sho@~/github/u-sho/svelte-app (master *%=)$ mv app/.
./          ../         .gitignore  

u-sho@~/github/u-sho/svelte-app (master *%=)$ mv app/.gitignore ./

u-sho@~/github/u-sho/svelte-app (master *%=)$ git add .

u-sho@~/github/u-sho/svelte-app (master +=)$ git commit -m ":tada: initial commit"
```

</div></details>

公式は npm を推してくるけど私は yarn 派です

```bash
u-sho@~/github/u-sho/svelte-app (master >)$ yarn

u-sho@~/github/u-sho/svelte-app (master *>)$ yarn dev
```

dev モードの初期画面です。port が 5000 なのが配慮してる感じが出てて嬉しい

![スクリーンショット 2020-01-26 5.06.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/04559c07-bec3-29e8-b778-8786bf6b92e1.png)

これもコミット&プッシュしたところでリポジトリ名を `svelte-app` から `portfolio` に変えました(ここまで：2020/01/26 05:50:39)
該当コミット時のリポジトリツリーは[こちら](https://github.com/u-sho/portfolio/tree/6f23c4716725637eccf4e929a16f18dcfb3713fb) (追加：2020/01/28 05:22:22)

:thinking: Qiita 書くのに時間かかりすぎてるなあ

### 2.2 方針転換

React に対する Next のように，Svelte には [Sapper](https://sapper.svelte.dev/) というライブラリがあるそうです。
とにかく速く実装を終えたいので，今回はこれを使うことにしました :muscle_tone4: 

もう夜も終わりそうなので，一旦寝て，夜から再会したいと思います(ここまで：2020/01/26 06:13:35)

### 2.3 Sapper インストール

[公式ドキュメント](https://sapper.svelte.dev/docs#Getting_started)にしたがってインストールしていきます。

webpack しか使ったことがないですが，公式が rollup を推してくるので rollup でやってみます :yum: 

<details><summary> $ npx degit "sveltejs/sapper-template#rollup" sapper-app </summary><div>

```bash
u-sho@~/github/u-sho/portfolio (master=)$ rm -r ./*

u-sho@~/github/u-sho/portfolio (master *=)$ npx degit "sveltejs/sapper-template#rollup" sapper-app
npx: 32個のパッケージを5.789秒でインストールしました。
> cloned sveltejs/sapper-template#rollup to sapper-app

u-sho@~/github/u-sho/portfolio (master %=)$ rm -r node_modules/

# 以前のプロジェクト(2.1で入れたやつ)の dotfiles を消して sapper-app/* のファイルを親 (portfolio/*) に移動
```

</div></details>

公式は [npm](https://www.npmjs.com/get-npm) 推しっぽいですが，~~package-lock.json が読めないので~~ [yarn](https://classic.yarnpkg.com/ja/docs/install#mac-stable) を使います。

local serve するついでに `package.json` の `name` と `description` も適当に書き換えました。

```bash
u-sho@~/github/u-sho/portfolio (master *%=)$ yarn

u-sho@~/github/u-sho/portfolio (master *%=)$ yarn dev
```

初期画面です。見知らぬおじさんが両手でサムズアップです。人間味がありますね(?)
port が 3000 番なのは Next.js を意識しているのでしょうか(?)

![画面収録-2020-01-28-5.31.24.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/987df64c-22e5-c468-0320-760ee2dbcf12.gif)

ここで[コミット](https://github.com/u-sho/portfolio/tree/5ae920f38df8d7d93ed36bfd739fa66f9a510474)したら GitHub から security alert が飛んできました。

![スクリーンショット 2020-01-28 6.16.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/f2c40c25-a621-f25c-6fde-93ad97586b74.png)

どうも [serialize-javascript](https://www.npmjs.com/package/serialize-javascript) というパッケージのバージョンが古くて，XSS の危険性があるらしいです
直さねば・・・(ここまで：2020/01/28 06:23:39)

#### 2.3.1 security alert の解消

GitHub によると serialize-javascript を ^2.1.1 にバージョンアップする必要があるようです
`package.json` で直接インストール(依存)しているパッケージの中にはなかったので `yarn.lock` を漁ります 

```:yarn.lock
 rollup-plugin-terser@^4.0.4:
   version "4.0.4"
   resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-4.0.4.tgz#6f661ef284fa7c27963d242601691dc3d23f994e"
   integrity sha512-wPANT5XKVJJ8RDUN0+wIr7UPd0lIXBo4UdJ59VmlPCtlFsE20AM+14pe+tk7YunCsWEiuzkDBY3QIkSCjtrPXg==
   dependencies:
     "@babel/code-frame" "^7.0.0"
     jest-worker "^24.0.0"
     serialize-javascript "^1.6.1"
     terser "^3.14.1" 
```

serialize-javascript は **^**1.6.1 で指定されているので，メジャーバージョンを上げなければなりません。

serialize-javascript のみアップデートすると， [rollup-plugin-terser](https://www.npmjs.com/package/rollup-plugin-terser) が serialize-javascript v2 で廃止された機能を使っている場合を考えないといけません。これは確認がとてもめんどくさいので，[rollup-plugin-terser のリリース一覧](https://github.com/TrySound/rollup-plugin-terser/releases)でヤバイ変更がなさそうなことを確認して，rollup-plugin-terser のバージョンを上げました(ここまで：2020/01/28 07:26:21)

[該当コミット](https://github.com/u-sho/portfolio/commit/a3d50ee0df4310725408709c2c7ef71b1c28fc25)

```bash
$ yarn add --dev rollup-plugin-terser
```

### 2.4 エディタの設定 [editorconfig](https://editorconfig.org/)

普段インデントにはスペースを使っているのですが，Sapper のテンプレはタブ文字を使っていたので，これに合わせて `.editorconfig` を書きます[^tabVSspaces]

[^tabVSspaces]: `s/\t/\s\s/g` 全部スペースに置換してもいいんですが，テンプレがタブ文字ということは，Sapper Community では「タブ派」がマジョリティなのかなと思い揃えることにしました。

```config:.editorconfig
# editorconfig.org
root = true

[*]
indent_style = tab
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = false

[*.md]
trim_trailing_whitespace = false
```

該当コミットは[こちら](https://github.com/u-sho/portfolio/commit/0ab03e665215b069661a5ed70942605e4ed2d556)

これでタブとスペースが入り混じった悲しいイン(シ)デントになることは避けられました :clap:

### 2.5 Sass の導入

[この記事](https://medium.com/@sean_27490/svelte-sapper-with-sass-271fff662da9) を参考にして SCSS で書けるようにしました。

「SCSS ってなんぞ？」という方は [こちらの記事](https://qiita.com/m0nch1/items/b01c966dd2273e3f6abe) をどうぞ

また，ここから実際にコードをいじっていくので develop ブランチとして切り分けました :tada:

#### 2.5.1 Sass (SCSS) の設定

- [autoprefixer](https://www.npmjs.com/package/autoprefixer), [node-sass](https://www.npmjs.com/package/node-sass), [svelte-preprocess](https://www.npmjs.com/package/svelte-preprocess) をインストール
- `rollup.config.js` に `preprocess` を追加
- `svelte.config.js` を作成

```bash
u-sho@~/github/u-sho/portfolio (master=)$ git switch -c develop

u-sho@~/github/u-sho/portfolio (develop)$ yarn add --dev autoprefixer node-sass svelte-preprocess
```

該当コミットは[こちら](https://github.com/u-sho/portfolio/commit/5590d3391e84e8c4a1978f0ca772dc5fd213dcca)です

(追記：2020/02/05 17:45:14)
[svelte-preprocess-sass](https://www.npmjs.com/package/svelte-preprocess-sass) を使ったり，やり方は色々あるようです

#### 2.5.2 テンプレートの style を CSS から SCSS に変更

次のような変更を加えて，書き方を SCSS チックにしました。

```diff:*.svelte
-<style>
+<style lang="scss">
```

また，`src/styles/global.scss` をつくり，`_layout.svelte` でそれを `@import` させています。

![スクリーンショット 2020-02-01 19.00.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/54df63a6-48ba-a74a-0ba1-c7a0d1c65550.png)

`yarn dev` で，ちゃんとスタイルがあたっていることを確認して [コミット](https://github.com/u-sho/portfolio/commit/14edb39cd153416464e644d96c3053edafd803ac) ！

### 2.6 VS Code の設定

私はフロントのコードを書くときは VS Code を使うことにしているので，その設定をしていきます。

#### 2.6.1 拡張機能の設定

前項の Sass 導入にあたって，syntax hilight がきれいに当たらなかったので，先に挙げた記事
にしたがって [SCSS Style Tag](https://marketplace.visualstudio.com/items?itemName=sissel.scss-style-tag) という拡張機能を入れました。

ここで，普段 Svelte.js を書かない私は，このリポジトリでしか使っていない拡張機能が増えてきたことに気付きました。

**手作業で管理するのはめんどくさい** ので，`.vscode/extensions.json` に最低限必要そうな拡張機能をメモすることにしました。

<details><summary> `.vscode/extensitons.json` </summary><div>

```json-doc:extensions.json
{
	"recommendations": [
		// coding style
		"DavidAnson.vscode-markdownlint",
		"EditorConfig.EditorConfig",
		// commit message
		"benjaminadk.emojis4git",
		// svelte
		"JamesBirtles.svelte-vscode",
		"fivethree.vscode-svelte-snippets",
		// scss
		"sissel.scss-style-tag",
	]
}
```

</div></details>

該当コミットは[こちら](https://github.com/u-sho/portfolio/commit/4fb211dc551a77b8989296747717876c1a0a61da) (ここまで:2020/02/01 21:06:23)

#### 2.6.2 その他の設定

(以下 2020/02/05 18:19:55 追加分)

`.vscode/settings.json` も書いていきます

<details><summary> `.vscode/settings.json` </summary><div>

```json-doc:settings.json
{
  /* Validation */
  "css.validate": false,
  "scss.validate": true,
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "html"
  ],
  /* others */
  "files.associations": {
    "*.svelte": "html",
  },
  /* Markdown */
  "markdownlint.config": {
    "no-trailing-spaces": true,   // MD009 default
    "no-multiple-blanks": {       // MD012
      "maximum": 2
    },
    "line-length": false,         // MD013
    "commands-show-output": true, // MD014 default
    "blanks-around-headers": {    // MD022
      "lines_above": 2,
      "lines_below": 1
    },
    "single-h1": true,            // MD025 default
    "fenced-code-language": true, // MD040 default
    "first-header-h1": true,      // MD041 default
  },
}
```

</div></details>

Markdown の lint を拡張機能で実現しています
CSS の代わりに SCSS を使うので，そのように設定しています

(以上 2020/02/05 18:19:55 追加分)

### 2.7 CI の構築 (GitHub Actions)

[GitHub Actions](https://help.github.com/ja/actions) を使って CI / CD 環境を構築していきます
やっと日本語でドキュメントが読める :joy: 

#### 2.7.1 テストの導入

Sapper テンプレートに入っていたテストライブラリ [Cypress](https://www.cypress.io/) を使ってみます

テンプレには，UI テストがちょっとだけ書いてあるので，それを動かしてみます

```bash
$ yarn add --dev cypress
$ yarn test
```

<details><summary>テスト結果</summary><div>

![yarn run-p --race dev cy:run の実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/10ad8d39-416f-b186-4f47-6c837a6ad7f0.png)

上の画像は，`yarn test` (`yarn run-p --race dev cypress run`) の実行結果です

</div></details>

テスト項目の「has the correct \<h1\>」，「navigates to /about」，「navigates to /blog」をクリアしていることがわかります

![yarn run-p --race dev cy:open の実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/9a0775ca-9ea3-7181-edbd-f5b7036027ca.gif)

上の動画は，`yarn run-p --race dev cypress open` の実行結果です(ファイルサイズ削減のため2.5倍速にしています)

GUI が立ち上がってわかりやすくテストの実行やその結果の閲覧ができます


いい感じ！！

#### 2.7.2 テストの自動化

GitHub Actions を使って，テストを自動化していきます

まずは `.github` フォルダを作るところからです[^touch-is-not]

[^touch-is-not]: 「`touch` コマンドはファイル作成コマンドじゃないぞ」というのは全くもってその通りです。ファイルの最終更新日時を変更するコマンドの用途外使用です(これでおk)

```bash
$ mkdir .github
$ mkdir .github/workflows
$ touch .github/workflows/test-and-build.yml
```

~~pull_request~~ push (一人なので PR を出す必要性がなかった) したタイミングでテストとビルドが走るようにします

CI 環境は以下です

| 機能 | バージョン | 理由 |
|:---:|:---:|:--- |
| OS | ubuntu-latest | 手元の mac で動くことは確認できるため，あとで他の PC から編集できるように(本当は CentOS が嬉しいけどセルフホストするサーバーがない) |
| node.js | 12.x | LTS のうち最新のもの |

<details><summary>コードはこんな感じ</summary><div>

```yml:test-and-build.yml
name: Test and Build

on: push

jobs:
  test-build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-node@v1
        with:
          node-version: '12.x'
      - name: install dependencies
        run: yarn --frozen-lockfile
      - name: test
        run: yarn test
      - name: sapper export static files
        run: yarn export
```

依存関係をインストールするときに，ローカルのものと異なると困るので，`--frozen-lockfile` で `yarn.lock` に書かれたバージョンを使うようにしてます

あと次いでにビルドが通るかどうかも一応チェックしてます

</div></details>

これを push します

<img width="751" alt="スクリーンショット 2020-02-05 12.50.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/6abbf2c7-949f-0c5e-9aef-8637d5001537.png">

![スクリーンショット 2020-02-05 12.51.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/b9b1942d-d11f-c4a0-9b5f-93c4fe27bb4f.png)

CI がちゃんと動くと嬉しい :laughing:

自分で GitHub Actions の設定をするのがはじめてだったので (CI 構築自体２回目)，手戻りが多く発生してしまい，該当コミットと言えるものはないです :bow_tone1: 
記事には載せているので，上の折り畳みを開いて確認してください(ここまで:2020/02/05 13:08:01)

#### 2.7.3 cache を利用する

時間がかかる依存関係のインストールを cache を使って高速化します(正直する必要があるほど遅くないですが，GitHub さんのサーバーの負担を気持ち分減らすためです)

[yarn での cache 利用のサンプル - GitHub](https://github.com/actions/cache/blob/master/examples.md#node---yarn)

公式にやり方が紹介されていたので，これをそのまま使いました

![スクリーンショット 2020-02-05 14.07.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/235dd873-ff5e-6894-cd2f-9f3ecc5e4798.png)

cache を使う前は install dependencies ステップにかかる時間は25-27秒でした :cry: 

![スクリーンショット 2020-02-05 14.22.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316196/f72b9119-fa06-0bf1-8749-bfd81ad71ad3.png)

cache 利用直後は18秒に改善しました :clap: 

該当コミットは[こちら](https://github.com/u-sho/portfolio/pull/8/commits/7544b9ea6e4cbe7f4fc2c670b8890a1b7312c143) (ここまで:2020/02/05 14:33:15)

## 参考

**英語サイト**

- [EditorConfig 公式ドキュメント](https://editorconfig.org/)
- [How to deploy Sapper PWA on GitHub Pages - Dev Community](https://dev.to/pixeline/how-to-deploy-a-sapper-pwa-on-github-pages-47lc)
- [Integrating with Linters - Prettier 公式ドキュメント](https://prettier.io/docs/en/integrating-with-linters.html#eslint)
- [Sapper 公式ドキュメント](https://sapper.svelte.dev)
- [Svelte 公式ドキュメント](https://svelte.dev)
- [Svelte / Sapper with Sass! - Medium](https://medium.com/@sean_27490/svelte-sapper-with-sass-271fff662da9)

**日本語サイト**

- [【初心者向け】Sassをいい感じに活用する - Qiita](https://qiita.com/cotolier_risa/items/33ca1dcd700927dd7ba0)
- [GitHub アクションでワークフローを自動化する - GitHub ヘルプ](https://help.github.com/ja/actions)
- [ReactとVueを改善したSvelteというライブラリーについて - Qiita](https://qiita.com/so99ynoodles/items/a8144ced1a21467c6300)
- [UNIXタイムスタンプ変換ツール by SELTAEB](https://url-c.com/tc/) (記事中のタイムスタンプ用)

## 主な変更履歴
- 2020/01/26 05:50:39 インストールまで
- 2020/01/26 05:53:55 sirv-cli の使いどころが思ったよりなかったのでタイトルを編集しました
- 2020/01/26 06:13:35 Sapper がいいらしいので Sapper を使うことにしました
- 2020/01/28 06:23:39 Sapper のインストール
- 2020/01/28 07:26:21 security alert の解消
- 2020/02/01 21:06:23 Sass の導入と VS Code の拡張機能の管理
- 2020/02/05 13:08:01 Cypress + GitHub Actions で CI の構築
- 2020/02/05 14:33:15 CI での依存関係のインストールに cache を利用する
- 2020/02/05 18:19:55 VS Code の設定ファイル