マナリンクのフロントエンド開発環境【基礎編/TypeScript,ESLint,Jest,Sentry】
CTOの名人です。
ちょっとした要望がありまして、弊社のフロントエンド開発環境についてざっくばらんにまとめてみようと思います!今回は基礎編と題しまして、フレームワークやライブラリについてまとめてみます。
フレームワーク
Nuxt.js
オンライン家庭教師マナリンクのフロントエンドをSSRで実装しています。
Next.js
マナリンクforTeachersという、先生向けのメディアサイトをISRにて実装しています。
ソースコード品質担保
ESLint
「このままのソースコードでも動くけど、(諸々の事情で)こう書いたほうがよりよいですよ」という注意をしてくれるライブラリです。
JavaScriptに限らず各言語に類似の目的を達成するライブラリはあり、一般に「Lintツール」「Linter」などと呼ばれます。
ESlintは、基本的にはnpm install -D eslintして、ルートディレクトリに.eslintrc.jsというファイルを置くだけで設定が完了します。.eslintrc.jsに自社の環境に合ったルールを色々と書いていくと、そのルールにそぐわないソースコードに対して注意してくれるようになる、という算段です。
主なセットアップ手順は以下のとおりです。
- npm install -D eslint
- .eslintrc.jsを作成
- 自社の環境に合ったルールを書き足していく
- 標準ではないルールは、追加でライブラリをインストールすることで利用できます
- コードを書くたびにeslintコマンドを実行したり、Gitへのコミットをフックにeslintコマンドを走らせるなどして、運用に組み込む(後述)
- VSCodeなどの使用しているエディタにESLint拡張機能を入れて、オプションを変更してfix on saveをONにする
詳しくは公式のドキュメントに説明を譲るとして、以下では弊社で使っているESlintルールの一例を示します。
vuejs-accessibility
vuejs-accessibilityはVue.jsで書いたHTMLのアクセシビリティをチェックしてくれるLintルールです。例えばimgタグにaltが設定されていないとエラーを出して怒ってくれます(
eslint-plugin-vuejs-accessibility)。
quotes: ['error', 'single']
文字列を基本的にシングルクォーテーションにするLintルールです。このルールは、eslintコマンドに--fixオプションを付けて実行すると勝手にコード中のダブルクオーテーションをシングルクォーテーションに修正してくれます。
vue/no-deprecated-XXXX
Vue2からVue3へのアップデートで非推奨になってしまったり廃止する機能を使っていると怒ってくれるLintルールです(eslint-plugin-vue)。現在Vue2を採用している方は脳死で入れておいてもいいかもしれません。
ESLintはエディタの拡張機能があり、VSCodeやPHPStormでは、ESLintの拡張機能を入れて、'fix on save'などというオプションをONにすることで、エディタでソースコードを書いて保存すると即座に整形が走ったり警告を赤線で教えてくれるので大変便利です。
初めてESLintを使う方は、create-nuxt-appとかcreate-next-appでデフォルトでそれっぽいeslintrcを作ってくれるので、それに従って関連するエディタやGit周りの設定を終わらせて、慣れてからルールのカスタマイズをするのがいいでしょう。
たまに、ESlintでエラーになっているとソースコードが動かないと勘違いする方がいるのですが、基本的にそんなことはないので注意してください。
Prettier
Prettierはコード整形ツールです。先のESLintにも、クォーテーションの自動修正を行うルールが有りましたが、PrettierとESLintは一部役割が被ることがあります。
適当な意見になってしまい申し訳ないのですが、ESLintだけで試し、機能不足を感じたらPrettierを足すくらいでいいのかなと思っています。
▼以下の記事を見ると、エディタのプラグイン(拡張機能)がPrettierを直接実行しているとのこと。
https://blog.ojisan.io/prettier-eslint-cli
以前は僕もPrettierを愛用していましたが、最近のプロジェクトではESLintだけで事足りることも多く、存在意義がよくわからなくなってきています。このへんは分かったら記事化します。
lint-staged, husky
Gitでコミットするタイミングで、指定したコマンドを動かしてくれるライブラリです。ESLint以外の場面でも使うでしょうが、僕は一般的にESLint実行のために使っています。
lint-stagedおよびhuskyの最新版をnpm install -Dして、以下のような設定をpackage.jsonに書き加えます。
"lint-staged": {
"*.{js,ts,tsx}": [
"eslint --fix",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
この状態で、ファイルをコミットすると、そのタイミングでESLintが動くことが確認できると思います。
TypeScript
Nuxt.jsでTypeScriptを使いたいときは、以下ページを参考に設定するといいです。
https://typescript.nuxtjs.org/
Next.jsでTypeScriptを使いたいときは、以下のテンプレートを使うのがおすすめです。
https://github.com/jpedroschmitz/typescript-nextjs-starter
2021年2月現在活発に更新されており、インストールするとTSX対応なども含め完了した状態でNext.jsの開発を始められます。
また、僕はいろいろなところで言っていますが、TypeScriptなフロントエンドから、REST APIを呼ぶときはaspidaというライブラリがおすすめです。
https://qiita.com/mejileben/items/11f206a51861bb404e1a
NuxtでのTipsの話で、TypeScriptではtsconfig.jsonという設定ファイルを使いますが、そこのtypes設定にライブラリ名を羅列することで、NuxtのappオブジェクトからライブラリによってInjectされたPluginを型安全に使うことが出来ます。
"types": [
"@types/node",
"@nuxtjs/axios",
"@nuxtjs/sentry",
"@nuxt/types",
"vuetify",
"nuxt-jsonld",
"@types/jest",
"@nuxtjs/device"
],
アプリケーション品質管理
jest
JavaScriptまたはTypeScriptでテストコードを書くためのライブラリです。若干セットアップに癖があるなどの理由から、人によってはmochaのほうが好きかもしれません。
jestのちょっと癖のあるところというのが、ts-jestとかvue-jestといった、複数種類のJestがあって、そこらへんの設定をしなければいけない点です。
jest.config.jsの一例
transform: {
'^.+\\.tsx?$': 'ts-jest',
'.*\\.(vue)$': 'vue-jest',
'^.+\\.js$': 'babel-jest',
'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
},
また、各Vueコンポーネントなどで、ファイルパスを`@/components/hogehoge...`のようにルートディレクトリの設定をしていたら、jestでも呼応させる必要があります。
@nuxtjs/composition-apiというNuxtでcomposition-apiを使えるライブラリについても、ここでマッピングを書く必要があります(Nuxt2.14系後半の場合)。
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/client/$1',
'^~/(.*)$': '<rootDir>/client/$1',
'@nuxtjs/composition-api': '@nuxtjs/composition-api/lib/entrypoint.js',
},
jestについては語り始めるとそれで単体の記事になりそうなのでこの辺にしておきます。フロントエンドのテストはそもそも難しくて、CSSやHTMLまで絡めてしまうと何かしらのレンダーを持ったテストツールを使わないといけないので、jestはVueやjsのレイヤーでのテストのみにとどめているわけですが、そうなるとテストして意味のあるコンポーネントは限られてくるんですよね。
かといってpuppeteerといったE2Eテストは、実際のDOMを見てテストコードを書くためか運用が大変という声をよく聞くので、なかなか悩ましいところです。僕は書いてません。割と真面目に、https://autify.com/ja のような自動化テストツールが世界を席巻すると思っているので、E2Eを内製するのに今からベットしなくてもいいかなという気持ちです。
ちょっと深入りした話をすると、Vueにおいては、composition-apiを使ってロジックを切り出して、単体でjestで完結するテストを書くのがいい感じの落とし所だと思っています。React Hooksについてもhttps://github.com/testing-library/react-hooks-testing-library というのがあるので、Hooks単位でロジックをまとめて、JSレイヤーでのテストを徹底して行うのがよさそうです。
Sentry
Sentryはアプリケーション監視のサービスで、SaaSとして提供されています。公式のSDKがあり、Sentry関連ライブラリをインストールして、APIキーをセットしておけば、フロントエンドの実環境で起こったエラーをSentryの管理画面上から見れるようにしてくれます。
要はユーザーのブラウザからクリックイベントとかConsole Errorを投げておいてくれるサービスで、Google Analyticsの強化版とも言えます。
エラーログだけでなく、First Contentful Paint等のパフォーマンスメトリクスも最近取ってくれるようになり、全能感があります。
以下はマナリンクのとある期間中のパフォーマンススコアです。Sentryで簡単な設定をするとコンソールから見れるようになります。こう見ると結構優秀な気はしますが黄色判定が多いので改善していきます。一緒にnuxt.config.jsの設定サンプルも貼っておくので参考にしてください。
sentry: {
dsn: 'XXX',
config: { environment: STAGE === 'production' ? 'production' : 'development' },
tracing: {
tracesSampleRate: STAGE === 'production' ? 0.1 : 1.0,
vueOptions: {
tracing: true,
tracingOptions: {
hooks: [ 'mount', 'update' ],
timeout: 2000,
trackComponents: true,
},
},
browserOptions: {},
},
},
フロントエンドでの利用が有名ですがバックエンドでも利用でき、好みに応じてフロントエンドもバックエンドも全部Sentry、というのができたりします。
NuxtでのSentryセットアップは割と簡単です。
実運用するアプリケーションであればとりあえず入れておくのがおすすめです。
以上です。
ざっくばらんに書きすぎて、誰向けの記事やねんみたいな内容になってしまいましたが、要望あればTwitterなりでご連絡ください笑
今回記事を書いていて、ESLint周りの動作原理に対する理解が意外となんとなくでやっているなと気が付きました。また、JestやTypeScriptの魅力、Sentryについては、別途語ってみたいなと思いました。