個人的フロントエンド開発環境の締めくくり：2019年編

**この記事は勤労をしていない高校生が書いているということを念頭に置いて**参考にして下さい

この記事は 2019 年の個人的な締めくくりです、時間がないので何が何なのかという解説はしません、利用しているパッケージはできるだけ数を載せるのでハブ空港として利用して下さい

2020 年になっても更新はする

いまは*Nuxt.js* x *firebase*で日報アプリを作っていたり CLI ツールを作っていて、多分以下のリポジトリ内の内容が最新になっています

- [daze](https://github.com/SnO2WMaN/daze)（プライベートリポジトリなので見れなかったら諦めて下さい）
- [cz-gitmoji-cli](https://github.com/SnO2WMaN/customizable-gitmoji-cli)
- [cz-gitmoji-config-parser](https://github.com/SnO2WMaN/cz-gitmoji-config-parser)

# 開発環境

Windows で、VSCode から WSL の Ubuntu にリモート接続してやっている、zsh を使っています

[anyenv](https://github.com/anyenv/anyenv)で[nodenv](https://github.com/nodenv/nodenv)を管理して、Node.js のバージョン管理を nodenv でやっているので、ローカルに`.node-version`というファイルを作り（下記）、`nodenv local`と打つとそのバージョンが利用出来ます

```|.node-version
12.13.1
```

[nvm](https://github.com/nvm-sh/nvm)だと`.node-version`が`.nvmrc`という名前に置き換わるだけだと思う

[Yarn](https://yarnpkg.com/)を使っていますが正直好みだと思います（インストールのときに進捗バーが見れてうれしいです）

# フロントエンド：ツール

原則`@sno2wman/*`の形で共用ファイルとして配布する形をとっている

Github Actions で自動でテスト、場合によっては配布が行われるようにしている（後述）

## [ESLint](https://github.com/eslint/eslint)

> [@sno2wman/eslint-config](https://github.com/SnO2WMaN/eslint-config)

[eslint-config-airnbnb-base](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base)を継承した上で、以下のものが全載せされている

- [eslint-plugin-unicorn](https://github.com/xjamundx/eslint-plugin-promise)
- [eslint-plugin-promise](https://github.com/sindresorhus/eslint-plugin-unicorn)
- [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier)
- [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier)
- [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import)
- [eslint-plugin-eslint-comments](https://github.com/mysticatea/eslint-plugin-eslint-comments)

`@sno2wman/eslint-config/+ava`で[AVA](https://github.com/avajs/ava)の為の設定ファイルを追加できる

(この書き方は@teppeis 氏の[eslint-config-teppeis](https://github.com/teppeis/eslint-config-teppeis)を参考にしている)

### Typescript 連携

> [@sno2wman/eslint-config-typescript](https://github.com/SnO2WMaN/eslint-config-typescript)

[設定ファイル原本](https://github.com/SnO2WMaN/eslint-config-typescript/blob/master/index.js)

`@sno2wman/eslint-config`を継承している

`plugin:@typescript-eslint/recommended`以下公式推奨のやつは全部のルールをカバーしてないからほとんど色々自分で設定する必要がある

(大多数のコンフィグ部分を@akameco 氏の[eslint-config-precure/typescript](https://github.com/akameco/eslint-config-precure/blob/master/typescript.js)から引っ張ってきた覚えがある)

#### [eslint-import-resolver-typescript](https://github.com/alexgorbatchev/eslint-import-resolver-typescript)

`tsconfig.json`以下`compilerOptions.paths`で張ったエイリアスを解決する

[eslint-import-resolver-alias](https://github.com/johvin/eslint-import-resolver-alias)で`.eslintrc`に直接書くという手もある

### 配布時に行っているテスト

[eslint-find-rules](https://github.com/sarbbottam/eslint-find-rules)で未設定のルールがないかをチェックしている

参考：[akameco / eslint-find-rules を使い ESlint の全ての項目を設定する](https://qiita.com/akameco/items/87d8436c73514c39e69d)

## [Prettier](https://github.com/prettier/prettier)

> [@sno2wman/prettier-config](https://github.com/SnO2WMaN/prettier-config)

[v1.17 から共用ファイルが使えるようになっている](https://prettier.io/docs/en/configuration.html#sharing-configurations)ので、

`.prettierrc`にただ`"@sno2wman/prettier-config"`とだけ書けばそれで設定が終了する

## [Editorconfig](https://editorconfig.org/)

ファイルやエディター間でできるだけフォーマットを同じにしようというやつです

`.editorconfig`というファイルを作って、開発環境毎に随時書き換えたりはしますがおおよそこうです

```|.editorconfig
root = true

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

[*.yml]
indent_style = space

[.node-version]
insert_final_newline = false
```

Prettier の設定と矛盾しないように設定して下さい

YAML についてはあまり詳しくないですがタブを使うと壊れたのでこう設定しています

`.node-version`の部分は末尾に新しい空白行があると Netlify などで初期設定がうまく行かない現象があったのでこうしています

## [Stylelint](https://github.com/stylelint/stylelint)

> [@sno2wman/stylelint-config](https://github.com/SnO2WMaN/stylelint-config)

SASS/SCSS を使うのでこうなっている、`no-descending-specificity`はズボラなので切っています

```javascript
module.exports = {
  plugins: ['stylelint-scss'],
  extends: [
    'stylelint-config-standard',
    'stylelint-config-recommended-scss',
    'stylelint-config-prettier'
  ],
  rules: {
    'no-descending-specificity': null
  }
}
```

- [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard)
- [stylelint-scss](https://github.com/kristerkari/stylelint-scss)
- [stylelint-config-recommended-scss](https://github.com/kristerkari/stylelint-config-recommended-scss)
- [stylelint-config-prettier](https://github.com/prettier/stylelint-config-prettier)

## [lint-staged](https://github.com/okonet/lint-staged) / [husky](https://github.com/typicode/husky)

`.lintstagedrc`、`.huskyrc`でそれぞれ設定ファイルを作ることが出来る

`.huskyrc`は余程なければ以下の内容でいいんじゃないでしょうか

```json
{
  "hooks": {
    "pre-commit": "lint-staged"
  }
}
```

`.lintstagedrc`は[このあたり](https://github.com/okonet/lint-staged#configuration)を見て下さい

## [gitmoji](https://github.com/carloscuesta/gitmoji)

Conventional Commit でコミットメッセージを書いていたんですが CLI で色々やろうとするとメチャクチャ複雑になった覚えがあったので、[gitmoji](https://gitmoji.carloscuesta.me/) を採用しています、

本家の [gitmoji-cli](https://github.com/carloscuesta/gitmoji-cli) を使わずに拙作の[cz-gitmoji-cli](https://github.com/SnO2WMaN/customizable-gitmoji-cli)を利用しています([この記事](https://qiita.com/SnO2WMaN/items/45a68905e6768f5d7c39)からちょっと書き直して設定ファイル別物になったので参考にしないで下さい)

# Vue.js w/ Nuxt.js

**この辺は後で別の記事でまた書いておきたい**

## Typescript 周り

[ここを参考にしてください](https://typescript.nuxtjs.org/ja/)

自分は Typescript と相性が良いような気がするので[@vue/composition-api](https://github.com/vuejs/composition-api)を採用しています

`setup`メソッドの第 2 引数で Nuxt 関連のコンテキストに触れたりするのはかなり便利です

### 参考

- [Vue Composition API](https://vue-composition-api-rfc.netlify.com/)
- [@ryo2132 / 先取り Vue 3.x !! Composition API を試してみる](https://qiita.com/ryo2132/items/f055679e9974dbc3f977)

## Vuex

[nuxt-typed-vuex](https://nuxt-typed-vuex.roe.dev/)がかなりいいんじゃないかと思っています

Composition API と相性が多分よく、先程の`setup`メソッドで、第 2 引数(`context`としましょう)、`context.root.$accessor`で楽に Vuex ストアを参照できるのが本当に嬉しい

あと型推測を特に設定無しでやってくれるので書き心地がよいです

## i18n

`<template/>`内に日本語を持ち込みたくなかった

```
yarn add yaml-loader nuxt-i18n @kazupon/vue-i18n-loader
```

`nuxt.config.ts`

```typescript
{
  modules: [
    [
      'nuxt-i18n',
      {
        locales: [{ code: 'ja', iso: 'ja-JP' }],
        defaultLocale: 'ja',
        vueI18n: {fallbackLocale: 'ja'},
        vueI18nLoader: true
      }
    ]
  ],
  build: {
    transpile: [/nuxt-typed-vuex/],
    extend(config) {
      config.module!.rules.push({
        resourceQuery: /blockType=i18n/,
        type: 'javascript/auto',
        loader: ['@kazupon/vue-i18n-loader', 'yaml-loader']
      })
    }
  }
}
```

の用に設定すると

```vue
<i18n locale="ja" lang="yml">
submit: "投稿する"
</i18n>

<template>
  <div>
    <p>{{ $t('submit') }}</p>
  </div>
</template>
```

のようにできます

# インフラテクチャー

## Github Actions

個人プロジェクトとかで Travis CI、Circle CI 以外の選択肢が出来たのは本当に嬉しい

設定ファイルをテストする方法は現状ないと思うので、プライベートリポジトリなどを作ってコミット駆動開発をすると良いと思います

参考

- [abetomo / GitHub Actions: tag で filter](https://qiita.com/abetomo/items/531d925fbbe917963f0d)
- [actions/cache](https://github.com/actions/cache)
- [Github Actions - 依存関係をキャッシュしてワークフローのスピードを上げる](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/caching-dependencies-to-speed-up-workflows)

今使っているものを全文載せる

```yaml
name: Node CI

on: [push]

jobs:
  default:
    runs-on: ubuntu-latest
    env:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
    steps:
      - uses: actions/checkout@v1
      - name: Get Node.js version
        id: node-version
        run: echo "::set-output name=version::$(cat .node-version)"
      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: ${{ steps.node-version.version }}
      - name: Setup yarn
        run: |
          curl -o- -L https://yarnpkg.com/install.sh | bash
          export PATH="$HOME/.yarn/bin:$PATH"
      - name: Get yarn cache dir
        id: yarn-cache
        run: echo "::set-output name=dir::$(yarn cache dir)"
      - name: Cache
        uses: actions/cache@v1
        with:
          path: ${{ steps.yarn-cache.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-
      - name: Install dependencies
        run: yarn --frozen-lockfile
      - name: Lint
        run: npm run lint
        env:
          CI: true
      - name: Test
        run: npm run test
        env:
          CI: true
      - name: Build
        run: npm run build
        env:
          CI: true
      - name: Codecov
        run: npx codecov
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
      - name: Publish
        run: npm publish
        if: contains(github.ref, 'tags/v')
```

`jobs.steps.[name].env`で`CI: true`を設定するとどこでコケたのか分かりやすくなるので適当につけてください

### `Get Node.js version`, `Setup Node.js`

Node.js のバージョンはできるだけ一箇所に纏めておきたかったので、`.node-version`ファイルからバージョンを取得して、それを使用するようにしています

（CLI ツールのようないろんな環境で使われる場合は matrix などで色々指定すると良いと思います）

### `Setup yarn`, `Get yarn cache dir`, `Cache`, `Install dependencies`

yarn をインストールして、キャッシュをあれしておきます、キャッシュ関連は[公式で配布](https://github.com/actions/cache)されているのでここを見るといいでしょう

yarn を使ってない場合は`yarn --frozen-lockfile`の部分は`npm ci`になったりすると思います

参考：

- [akameco / CI 上の yarn の設定](https://qiita.com/akameco/items/8945e434da315a0fbe44)
- [mstssk / npm ci を使おう あるいはより速く](https://qiita.com/mstssk/items/8759c71f328cab802670)

### `Codecov`

~~気休めで~~[Codecov](https://codecov.io/)でカバレッジを測ったりしている、Github App として Codecov を設定しても競合して崩壊するということはなかったです

### `Publish`

`v1.2.3`みたいなタグがついたコミットが行われるときにこの job が実行され、自動で publish が行われるようになります

参考：[@KamataRyo / Travis CI を使って npm を継続的に公開・メンテナンスするよ](https://qiita.com/KamataRyo/items/6e795c6734f9a775f5a6)

## Renovate

[Renovate Bot](https://github.com/renovatebot/renovate)、依存関係のバージョンを自動で更新をやってくれます

参考

- [Teppei Sato - Automated Dependency Updates with Renovate](https://www.slideshare.net/teppeis/automated-dependency-updates-with-renovate-102769685)
- [teppeis/renovate-config](https://github.com/teppeis/renovate-config)

> [SnO2WMaN/renovate-config](https://github.com/SnO2WMaN/renovate-config)

`renovate.json`

```json
{
  "extends": [
    "github>sno2wman/renovate-config",
    ":timezone(Asia/Tokyo)",
    "schedule:daily"
  ]
}
```

# その他

## fossa

アプリ / サービス配布のときにライセンス周りで怒られが発生しないように[fossa](https://fossa.com/)というサービスで解析するようにはしてありますが、詳しいことはよく分かっていません

## FontAwesome 5

アイコン周りは全部[FontAwesome 5](https://fontawesome.com/)及び、[vue-fontawesome](https://github.com/FortAwesome/vue-fontawesome)を使用しています

利用するときには、以下の用に書くと Tree Shaking が働いて出力ファイルのサイズが減るはずです

```typescript
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { faPenNib, faCircleNotch } from '@fortawesome/pro-solid-svg-icons'
```

### Pro ライセンスについて

トークンが手に入るはずなので、`NPM_FONTAWESOME_TOKEN`という名前で各々サービスや`.env`で設定しておくとして、

以下の内容の`.npmrc`を作成する

```
@fortawesome:registry=https://npm.fontawesome.com/
//npm.fontawesome.com/:_authToken=${NPM_FONTAWESOME_TOKEN}
```

`renovate.json`は、トークンを[ここ](https://renovatebot.com/encrypt.html)で暗号化したうえで、`encrypted.npmToken`に入れると上手くいく

```json
{
  "encrypted": {
    "npmToken": "<ENCRYPTED>"
  },
  "npmrc": "@fortawesome:registry=https://npm.fontawesome.com/\n//npm.fontawesome.com/:_authToken=${NPM_TOKEN}",
  "npm": {
    "packageRules": [
      {
        "groupName": "FontAwesome Icons Pack",
        "packagePatterns": ["^@fortawesome/pro-", "^@fortawesome/free-"],
        "automerge": true,
        "updateTypes": ["minor"]
      }
    ]
  }
}
```

参考：[Renovate Docs - Private npm module support](https://docs.renovatebot.com/private-modules/)

# あとがき

クリスマスの深夜に書くものではない、2019 年 12 月 31 日 にはもっとまともな感じの記事になっていると思います

共用ファイルとして色々配布するのは色々楽しいです、皆さんもやってみてはどうでしょうか