はじめに
みなさまはrelay-compilerを使っていて以下のようなエラーに遭遇したことはありませんか。私は3000回ぐらいあります。
ERROR: Parse error: Error: RelayFindGraphQLTags: Operation names in graphql tags must be prefixed with the module name and end in "Mutation", "Query", or "Subscription". Got `BarQuery` in module `Foo`. in "components/Foo.tsx"
relay-compilerは graphql
タグ内に記述したQuery, Mutation, Fragmentの名前に「モジュール名から始まる」「Fragment以外は種類 (Query, Mutation) で終わる」という規則を要求し、従っていない場合はコンパイルを失敗させます。例えば components/Foo.tsx
なら FooQuery
FooMutation
Foo_user
のように、モジュール名 Foo
から始めないといけません。
一方で components/Bar/index.tsx
のようなパスの場合は Bar
がモジュール名になります。今のチームではReactコンポーネントのファイルパスは基本的にPascalCaseにして実装していますが、camelCase*1やsnake_caseやkebab-caseを使う場合も考えられるでしょう。
relay-compilerが要求するモジュール名がどのように判定されているのか、気になりませんか?
Relay 12の実装を見る
ということでrelay-compilerの実装を見ましょう。v12.0.0
タグにcheckoutして探してみます。
エラーメッセージをもとに探してみます。RelayFindGraphQLTags:
でgrepするといくつか出てきます。今回該当するのは以下の行ですね。
validateTemplate
関数の呼び出し元は、同じファイルの find
関数のみなので、この引数が moduleName
でモジュール名だと分かります。ということで getModuleName
関数の実装を見ればよさそうです。
getModuleName
関数の実装は以下です。コメントと合わせて読むと分かりやすいですね。kebab-caseはうまくcamelCaseに変換してくれるようです。snake_caseは回避したほうがよさそうなことも分かります。.ios.js
や .android.js
のようなファイル名のときに特別対応が行われているのは知りませんでした。
getModuleName
関数のテストを見たほうが早いかもしれませんね。
Relay 13
ところで今日、Relay 13がリリースされていました。1行目にさらっと書いてありますが、relay-compilerは完全にRustで書き直されたようです。手元にrelayのリポジトリをcloneしていたのですが、久しぶりにpullしたらめちゃくちゃ時間がかかってびっくりしました。
気を取り直して勘でRustを読んでいきます。module name
でgrepしたら以下の行が見つかりました。ここで module_name
というフィールドに渡している値を特定できればよさそうに見えますね。
すぐ上を見ると extract_module_name
という関数がありそうですね。この関数の定義は以下です。正規表現が使われていないのですが、おそらくここで互換性を壊すようなことはないだろうと想像します。
テストも見てみました。一見するとRelay 12までと挙動は変わっていなさそう?
おわりに
relay-compilerが要求する命名規則が分かりました。そろそろRustを難なく読み書きできるようになったほうがよいのかもしれません。
*1:先頭が小文字。Reactコンポーネントだとあまりない?