Nuxt3を使ったフロントエンド開発の品質管理のTipsをご紹介！

## はじめに
こんにちは！
株式会社Blankrで業務委託のフロントエンドエンジニアとして働いている谷澤と申します。

弊社では、『[ライドリ](https://rideo.jp)』というクリエイターの活動を支援するプラットフォームを運営しています。

私はこれまで複数の現場でフロントエンドの開発を行ってきましたが、その中でもライドリのフロントエンド開発はしやすく、フロントエンドコードの品質を担保するための様々な工夫がされています。

今回はその内容を紹介していきたいと思います！


## 目次
- [はじめに](#はじめに)
- [目次](#目次)
- [使っている技術](#使っている技術)
- [ライドリのフロントエンド品質管理のTips](#ライドリのフロントエンド品質管理のTips)
  - [コンポーネントの管理方法](#コンポーネントの管理方法)
  - [スタイルの変数管理](#スタイルの変数管理)
  - [pluginsの活用](#pluginsの活用)
  - [ロジック層の切り分け](#ロジック層の切り分け)
  - [共通機能のhooks化](#共通機能のhooks化)
- [終わりに](#終わりに)
- [エンジニア募集中！](#エンジニア募集中)


## 使っている技術
<!-- textlint-disable ja-no-mixed-period -->
開発言語：Typescript, Go (Rest / GraphQL)

フレームワーク： Nuxt.js

インフラ： GCP, Firebase, Docker, Cloudflare

アーキテクチャ：

 ・バックエンド：CleanArchitecture

 ・フロントエンド：

　 コンポーネント：AtomicDesign

　 スタイリング：BEM
<!-- textlint-enable ja-no-mixed-period -->


## ライドリのフロントエンド品質管理のTips
### コンポーネントの管理方法
#### 独自のAtomicDesign
ライドリではAtomicDesignをベースにした独自の方法でコンポーネントを管理しています。

これにより、コンポーネントの再利用性が高まり、保守性も向上しています。
<!-- textlint-disable ja-no-mixed-period -->
通常のAtomicDesignでは、

`atoms`,`molecules`,`organisms`,`templates`,`pages`

という5種類のディレクトリに分けて設計されると思いますが、

ライドリではcomponentsディレクトリの中で

`primitive（共通のコンポーネント）` と `domain（そのドメイン内で使われるコンポーネント）`

というディレクトリに分けて

それぞれの配下に
<!-- textlint-enable ja-no-mixed-period -->

`atoms`,`molecules`,`compounds`,`organisms`,`templates`

と5種類のディレクトリが存在しています。（Nuxtの設計の通り、`pages` はcomponentsと同列に位置してます）

通常のAtomicDesignとは違い `compounds` というディレクトリを追加しています。

#### compoundsとは
compoundsとorganismsが近い粒度のコンポーネントになりますが、その違いとしては外部依存を持つか、持たないかになります。

`compounds = "外部に依存することなく、単独で機能するUIコンポーネントのグループ"`

`organisms = "外部依存を持つことができる複雑なUIコンポーネントのグループ"`
<!-- textlint-disable ja-no-mixed-period -->
ですので、例えば、graphqlのmutationを使うポイント購入決済用のコンポーネントは `organisms` で作られており、
<!-- textlint-enable ja-no-mixed-period -->
ただ選択している購入予定のポイント内容を画面に表示するためのコンポーネントであれば、`compounds` で作られています。

AtomicDesignを採用するとどうしてもorganismsのコンポーネント数が多くなりすぎてしまう問題があると思います。

ライドリではそれが2つに適度の分けられていて、責務もわかりやすくなっています。

さらに、Lintの設定でAtomicDesignの規則に従って、`atoms` に `molecules` をimportしようとするとlintエラーが出るといったようにそれぞれの粒度でimportできるファイルを制限しています。

おかしな粒度でコンポーネントを作成してしまっていれば、importのlintエラーの時点でその間違いに気づけます。

また、`atoms`,`molecules` で作られたコンポーネントはFigmaと連携されています。

Figmaの中でコンポーネント名が表示されるので、参画して間もない方でもどのコンポーネントを使えばいいのかがひと目でわかります。

これによってデザインと実装の一貫性が保たれています。


### スタイルの変数管理
ライドリではCSSフレームワークを使っていないので、デザインに合わせて全てのスタイリングを行う必要があります。

スタイリングはSCSSのBEM記法で記述しており、その時に `variables.scss` ファイルで管理されている変数を使います。

この管理が徹底されているので、cssを書かないといけないといっても気持ちよくスムーズに書くことができます！

例えば、太文字タイトルの20pxの要素であれば、以下のように `variables.scss` ファイルで定義されています。
```
@mixin title20px {
  font-weight: 600;
  font-size: $font-size-20;
  line-height: $line-height-primary;
}
```

styleタグの中で以下のようにincludeして使うことができます。
```
@includes title20px
```

文字スタイルだけでなく、長文を省略するためのスタイル `omitText` など、複数箇所で使われるであろう共通スタイルは全て変数管理されています。
```
@mixin omitText($lineNumber) {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: $lineNumber;
  word-break: break-all;
}
```

また、これらの変数もFigmaと連携されているので、Figmaを見ればその箇所でどの変数を使えばいいかがわかります。

以上のようにそれぞれの開発者が無駄にスタイリングしなくて済むように工夫がされていてとても便利です。


### pluginsの活用
Nuxt.jsのプラグインは、アプリケーションの初期化時に特定のコードを実行するための仕組みです。

この機能を活用して、いくつかの共通処理（ナビゲーションやエラーハンドリングなど）がpluginsに一元管理されています。

これにより、コードの重複を避け、コードの可読性と保守性が高まっています。

例えば、ナビゲーションの処理は `plugins/01-navigator.ts` というファイルで管理されています。

vueファイル側でuseNuxtAppを使い、上記ファイルから呼び出した関数にroute名（nuxtのtypedRouterで型管理もされている）を渡すことで画面遷移できるようになっています。

useRouterを色々な箇所で呼びだすというようなことは行われていません。

また、ライドリではオンライン握手会といってファンと配信者がビデオ通話をできる機能があるのですが、そこで利用されるカメラデバイスのstate管理をpluginsに持たせる実装を最近行いました。

これによって、アプリとして保持しておきたい様々な箇所で使われるstateをpluginsの中に一元化することができました。

### ロジック層の切り分け
ライドリでは、ロジック層を明確に分離し、GraphQLとTypeScriptでしっかりと型付けされています。

これにより、コードの予測可能性と安全性が高まり、バグの発生を抑えることができます。

index.vueと同列にlogin.tsというファイルを切り出し、GraphQLで取得したデータを整形する際のロジックや、mutationを行う際のロジックをこのファイルで記述しています。

そして、vueファイルにそのデータを渡す際にはTypeScriptで型付けをしているため、修正を行った後に予期していないデータが残っていたり、取得できていないデータを使用してしまっていたりするバグが起こらないようになっています。

 ### 共通機能のhooks化
フロントエンド開発の中で必ず共通化して使われるモーダルやローディングといったいくつかのコンポーネントは `useModalDefiner`、`useLoadingDefiner` としてFunctionalComponentでhooks内で定義しています。

例えば、共通のモーダルのコンポーネントとして、ModalBaseというvueファイルを作り、モーダルを表示するときはpropsにモーダルを表示するかどうかのフラグを渡す。

ということを行ったりすると思いますが、複数のモーダルを1ファイル内で使いたい場合、複数のフラグ、またはフラグのidを変更して各モーダルの表示を切り替えたりすると思います。

ライドリで使っているuseModalDefinerであれば、useModalDefinerでAインスタンス、Bインスタンスとそれぞれインスタンスを作成して、モーダルを表示したいときには `Aインスタンス.openModal` といった形で関数を呼び出せば良いため、Propsとして渡すためのフラグを用意する必要がなく便利です。

こういった便利かつ共通化して皆が同じように使うことができる機能がライドリ内にはあります。

## 終わりに
以上、ライドリのフロントエンド開発のTipsを一部ご紹介いたしました。

ライドリのフロントエンド開発には効率的で高品質なコードを実現するための工夫がたくさん詰まっています。

自分自身ライドリで開発する中で勉強になることがたくさんありましたし、スキルアップできています。

しかし、まだまだやることできることはあります！

## エンジニア募集中！
株式会社Blankrでは、ライドリの開発に携わっていただけるエンジニアを募集しています！

Go言語、Nuxt 3、GraphQLなどの実務経験がある方大歓迎です。

下記に各種リンクを記載していますので、ぜひご覧ください！

### 求人

<!-- textlint-disable ja-no-mixed-period -->

正社員募集

https://offers.jp/jobs/33887

業務委託募集

https://offers.jp/jobs/33923

<!-- textlint-enable ja-no-mixed-period -->

### インタビュー記事

https://blankr.fun/news/aljzkHbB

https://blankr.fun/news/bfyaPR-X

https://blankr.fun/news/ri03YnL9

https://blankr.fun/news/cIRltJVG

https://blankr.fun/news/pCOJRM93

### サービス

https://rideo.jp