自分は React で開発する際 default export を推奨するよ、という話

2020-10-21

Qiita 開発チームが React の開発で default export を使わなくなった理由

この記事を読んでみての感想です。


よく default export を使うべきだの named export を使うべきだの議論を目にしますが。

自分としてはぶっちゃけどっちでも良いです、どーでも良いです、興味がないです。

ただ、チームとして開発する場合 export に関するルールはしっかり決めておくべきだよなーとは思います。

なので、Qiita の開発チームが named export に寄せたルールのもと開発を行っていくというのは良いことなんじゃないかなーと思います。


named export を使用するルールを敷いたことについては良いことだと思いますが、一方で以下の 2 点については少し気になりました。

  1. Qiita 開発チームが default export を使わなくなった理由は、default export だと import する側で自由に名前を決められてしまうためです。
  2. Atomic Design では、部品ごとにパーツを作り、さらに組み立てたコンポーネントをつくっていくため、どうしてもコンポーネントの数が多くなってしまいます。そこで default export を使うと、コードを書く人によってコンポーネント名が変わる可能性があり、コンポーネントの管理が難しくなるといった問題が考えられます。

default export は import する側で自由に名前を決められてしまう件

あくまで自分の開発手法における考え方ですが。

自身がテックリードを務める現場の場合、1 ファイル 1 コンポーネントというルールを敷いて開発を行うことがほとんどです。

つまり、コンポーネントを扱うファイル内では 1 コンポーネントしか扱うことを許容せず、そのコンポーネントは必ず default export することを強制します。

import React, { FC } from "react"; export type HogeProps = { hoge: string; }; const Hoge: FC<HogeProps> = ({ hoge }) => <div>{hoge}</div>; export default Hoge;

で、もう少し言うと、コンポーネント以外のファイルも可能な限り 1 ファイル 1 default export で統一するようにしています。

特に custom hooks や Redux 周りについては 1 ファイル 1 default export を強制するようにしています。

なぜこのようなルールを敷くかというと、1 ファイル内に複数のコンポーネントや複数のモジュールを切ってほしくないからです。

1 ファイル 1 default export のルールで開発を行うと、必然的に 1 ファイル内の記述量が減り、ファイルごとの見通しが良くなります。

もちろんその分ファイル数は増えるのですが、個人的にはファイルごとの目的を明確にしたいため、ファイル数が増えることは問題だと思っていません。

それよりは、保守的な観点から見たときに、ファイルごとの目的が薄まることのほうが危ないかなーと思っています。

例えば Hoge というコンポーネントファイルを作成した際、そのファイル内に Fuga というコンポーネントが作成されていると『ん?』と思うんですよね。

import React, { FC } from "react"; // ん?と思う const Fuga: FC = () => <div>fuga</div>; export type HogeProps = { hoge: string; }; export const Hoge: FC<HogeProps> = ({ hoge }) => ( <div> <Fuga /> <div>{hoge}</div> </div> );

100 歩譲ってその Fuganamed export されていなければ、Hoge のみで使用されるコンポーネントなのかなーと推察されますが。(自身がテックリードの場合は許容しませんが)

Fuganamed export されている場合、『なんで Hoge コンポーネントファイル内で Fuga コンポーネントが export 可能な状態なの…?』と感じてしまいます。

import React, { FC } from "react"; // このファイル名が Hoga.tsx の場合すごく気持ち悪い export const Fuga: FC = () => <div>fuga</div>; export type HogeProps = { hoge: string; }; export const Hoge: FC<HogeProps> = ({ hoge }) => ( <div> <Fuga /> <div>{hoge}</div> </div> );

で、これって保守観点からすると、保守性の低い状態だよなーと強く感じます。

また、HogeFuga が並列なレベルに存在するのも気持ち悪いですし、そもそも HogeHogeProps が並列なのも気持ち悪いです、あくまで個人的にですが。

なのでコンポーネントファイルにおいては、そのファイル名と同一のコンポーネントを default export させる、というルールを採用するようにしています。

で、ようやくここから本題なのですが、default export を使用した場合、import する側で自由に名前を変えれてしまう、という件ですが。

まぁ、イヤっちゃイヤですよね、勝手に名前変えられるのって。

自分がテックリードを務める現場でも、import してきたコンポーネントの名前がファイル名とズレている場合指摘します。

でもこれってあくまで import する側の言い分であって、default export するか named export するかは import される側の問題なのではないかなーと、あくまで個人的にですが。

ちなみに、MDN には以下のように書かれています。

Named exports are useful to export several values. During the import, it is mandatory to use the same name of the corresponding object.

名前付きエクスポートは、いくつかの値をエクスポートするのに役立ちます。 インポート中は、対応するオブジェクトと同じ名前を使用する必要があります。

なので、import する際に名前が変えられるから named export を使用するというのは、そもそもの目的からはちょっと外れているんじゃないかな?と感じました。

コンポーネントの数が多くなり、コンポーネントの管理が難しくなった

これも気持ちはよーくわかります。

いくら Atomic Design を導入したとしても、いくら Storybook を導入したとしても、コンポーネントの数が増えれば管理するのが厳しくなってきます。

が、そもそも論ではあるのですが、コンポーネントの管理を行うのってフロントエンドエンジニアではなく UI / UX デザイナーの仕事だと個人的には思っています。

UI / UX デザイナーがきちんとコンポーネントの管理・整理を行い、コンポーネントごとに的確な名前を定め、Atomic Design のもとしっかりとしたプロトタイピングを行えば、そもそもフロントエンドエンジニアはコンポーネントの管理で困ることはありませんし、ファイル名云々の問題もそこまで発生しません。

記事中では以下のように書かれていますが。(抽象化ってなんだ…?)

SubmitButton を抽象化し、Button にした場合

この文面だけ見ると、Qiita の開発チームではフロントエンドエンジニアが全てのコンポーネントの管理を行い、フロントエンドエンジニアが Atomic Design を導入し、フロントエンドエンジニアがファイル名を定めているように見受けられました、あくまで予想ですが。

で、Qiita くらいの規模であれば、フロントエンドエンジニアがコンポーネントの管理を行うのって、厳しそうだよなーと思います。

なので、余計なお世話であることは承知の上で、もし UI / UX デザイナーがコンポーネントの管理を行っていないのであれば、早急に補強を行ったほうが良いのでは?と、勝手に思いました。


JavaScript における export 周りについては様々な書き方ができるため、逆に難易度が上がっているよなーと感じます。

まぁ JavaScript 自体がそういう言語なのでしょーがないとは思うのですが。

なので、フロントエンドエンジニアは開発を行う際、JavaScript の自由度の高さに甘えるのではなく自らルールを定めて縛る必要が出てきます。

そういった意味で Qiita の開発チームが named export で統一している、というのは本当に立派なことだなーと思います。

一方、自分がテックリードを務める場合は default export を強制したり、1 ファイル 1 コンポーネントを強制します、基本的に例外は認めません。

過去の経験上、UI / UX デザイナーとフロントエンドエンジニアがしっかりと連携しているプロジェクトなんて日本にはほぼ存在しませんし、そうなると必然的にフロントエンドエンジニアがコンポーネントを管理するしかありません。

eslint にも import/no-default-exportimport/prefer-default-exportのようなルールも存在しますので、しっかりと縛ってやることが保守性の向上に繋がるのかなーと。

© 2018 kk-web