投稿日:2021年3月6日
CreateReactAppのコンパイラの内部ではESLintが動いています。しかし、gRPCの自動生成コードはなんとESLintに通すとエラーになってしまうのです。gRPCを使うときには必要に応じてESLintの除外設定をしましょう。
この記事のコードは以下の環境で確認されました。
自分は現在、CreateReactApp + TypeScript + gRPCで開発しているのですが、gRPCの生成コードを使ったコードを書いて、いざ実行!という段階で謎のエラーが発生してしまいました。
発生したエラーは以下のようなもの。
Failed to compile.
src/proto/notematon_pb.js
Line 34:1: 'proto' is not defined no-undef
Line 37:15: 'proto' is not defined no-undef
Line 38:20: 'COMPILED' is not defined no-undef
Line 39:3: 'proto' is not defined no-undef
Line 54:1: 'proto' is not defined no-undef
Line 55:10: 'proto' is not defined no-undef
Line 68:1: 'proto' is not defined no-undef
Line 87:1: 'proto' is not defined no-undef
[...]
内容を見るとprotoという変数がどこにも定義されていないのに使用しているためコンパイルは中止したぞというエラーのようです。このsrc/proto/notematon_pb.jsというはprotocコマンドを利用して.protoファイルから自動生成したコードなのですが…。
自動生成したコードでなぜこんなエラーが…?
実際にコードを確認してみましょう。
var jspb = require('google-protobuf');
var goog = jspb;
var global = Function('return this')();
var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/timestamp_pb.js');
goog.exportSymbol('proto.CreatePieceRequest', null, global);
goog.exportSymbol('proto.CreatePieceResponse', null, global);
goog.exportSymbol('proto.GeoPoint', null, global);
goog.exportSymbol('proto.ListPiecesRequest', null, global);
goog.exportSymbol('proto.ListPiecesResponse', null, global);
goog.exportSymbol('proto.Piece', null, global);
goog.exportSymbol('proto.PieceNew', null, global);
goog.exportSymbol('proto.User', null, global);
[...]
proto.GeoPoint = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
なるほど、原因がわかりました。
このコードの中ではexportSymbol()という関数を使ってprotoの定義をグローバルでしているのですが、コンパイラは言語の文法にしたがった変数定義がされていないため不正なコードであると勘違いしてエラーになったようです。
自動生成されたコードに問題が無いようでとりあえず一安心。
解決策はいくつか考えられるのですが、今回はCreateReactAppのコンパイラのチェック対象から問題が発生しているファイルを除外するのが良いでしょう。
CreateReactAppのコンパイルはESLintで文法のチェックをしているのでESLintの除外設定をすれば良いのですが、デフォルトのままではこの設定をすることができません。ESLintの設定をするには、環境変数でEXTEND_ESLINTをtrueに設定する必要があります。環境変数の設定方法はいくつかありますが、今回は.envファイルを使って設定してみます。
プロジェクトのルートに以下の様に.envファイルを作成します。
EXTEND_ESLINT=true
これでESLintの設定のカスタマイズができる様になりました。
早速設定ファイルを作成しましょう。
ESLintのファイル・ディレクトリの除外は.eslintignoreというファイルを利用します。
今回の僕の環境の場合、.protoファイルから自動で生成されるコードの出力先は常にsrc/protoというディレクトリで固定なので、このディレクトリのjsファイルを除外する設定にします。
プロジェクトのルートに以下の.eslintignoreファイルを作成しました。
src/proto/*.js
無事コンパイルできました!
gRPCの導入はまだまだ難しい…。