症状
react-native start
でサーバを立ち上げると, node_modules
配下に含まれているライブラリが依存しているBabelのプリセットが反応して
TransformError Couldn't find preset "es2015"
TransformError Couldn't find preset "airbnb"
などとエラーになってしまう問題。
(備考) .babelrc
の動作
親ディレクトリの `.babelrc` の設定を子の `.babelrc` で上書きし,最終的に生成された設定で子ディレクトリ内のトランスパイルを行う。
原因
npm と, React Native の方針の違いに起因する。
npm の方針
ホスティングされるパッケージはすべて CommonJS と ES5 までの実装で動作するようにトランスパイル済みであることを想定している。つまり,そもそも
「node_modules
以下はトランスパイル対象にならない」
ということを前提としている。ゆえに,公開されるパッケージが .babelrc
を含んでいても,普通のプロジェクトではそのディレクトリがトランスパイル対象から除外されるため,トランスパイラに影響を及ぼすことは無い。
React Native の方針
通常の JavaScript コードをネイティブコードに変換する必要があるため, babel-preset-react-native
を用いて
「node_modules
以下もトランスパイル対象にする」
という方針を採る。そのため, 依存パッケージがもし .babelrc
を含んでいる場合,それに使用されているプリセットをすべて必要としてしまう。
対処法
パッケージインストール後に node_modules
下の .babelrc
をすべて削除する
現状これが最善の解決策。npm scripts に以下の設定を追記。
{
"scripts": {
"clean-underlying-babelrc": "(find node_modules -type f -name .babelrc | grep -v /react-native/ | xargs rm) || true",
"post-install": "npm run clean-underlying-babelrc",
}
}
ライブラリ作者に .babelrc
を .npmignore
の設定で除外するように求める
この対応をライブラリ作者全員がとってくれれば最善ではあるが,React Native 固有の事情であるため,拒否される場合もあるだろう。
/.*
/*
!/src/
!/es/
!/lib/
必要ないプリセットもすべてプロジェクトの .babelrc
で記述する
一応動作はするが,新しく追加するパッケージがあるたびに,新しいプリセットに依存していないかどうかを確認する必要があるため,安定した解決策とは言えない。それに,なんとなく負けた気分…
{
"preset": ["react-native", "es2015", "stage-0", "stage-1", "stage-2", "stage-3", "stage-4", "env", "airbnb"]
}
その他
React Native プロジェクトはデフォルトで babel-preset-react-native
を使用するため,自分で .babelrc
を置かなくてもトランスパイル可能であるが,ホームディレクトリに .babelrc
がある場合はそれを読んでしまうため,結局置いておくほうが無難。上に述べた対策を実施しつつ,
{
"preset": ["react-native"]
}
を書いておく。実際 ES.Next の使用をふんだんに使おうとすると
{
"preset": ["react-native", "env"]
}
というように, babel-preset-env
などを追加せざるを得ない。