そもそもの前提問題としてReact-NativeではHMRを有効化してもStateless Functional Component(以下SFC)に対してhot module replacement(以下HMR)してくれない問題がある。
https://github.com/facebook/react-native/issues/10991
上記のissueに記載あるが babel-plugin-functional-hmr
を入れることでSFCに対してもHMRを有効化出来る。これで全て解決!と行けば良いのだが、、、
babel-plugin-functional-hmrを有効化した状態でjestのsnapshotテストをするとテストケースが失敗することがある
どういうケースで失敗するのか?
普段僕は業務でもプライベートでも styled-components を使用しています。
今回の場合、こういったエラーが発生しました。
locals[0] does not appear to be a `module` object with Hot Module replacement API enabled. You should disable react-transform-hmr in production by using `env` section in Babel configuration. See the example in README: https://github.com/gaearon/react-transform-hmr
2 |
3 | import React from 'react';
> 4 | import { Container, BadgeText } from './style';
これは react-transform-hmr が有効化されているので発生しているので、 babel-plugin-functional-hmr
を developmentだけで有効化すれば良いのがわかります。
しかし、 .babelrc
に記述するだけだと 例えば NODE_ENV=test jest
してもこのエラーを回避できませんでした。
解決方法
.babelrcではなく babel.config.jsにし、下記のように記述する
module.exports = api => {
const env = api.cache(() => process.env.NODE_ENV);
return {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./'],
alias: {
'@': './src'
}
}
]
],
env: {
development: {
plugins: env === 'test' ? [] : ['functional-hmr']
}
}
};
};
plugins
内は設定してなかったら特に何も記述しなくて良いと思います。
またこの書き方は自分の環境内で使っている形なので、 babel.config.js
はfunctionにする、引数.cache
を使う、 development以外では babel-plugin-functional-hmr
を有効化しない。
これらを守るとSFCにHMRを有効化させつつ、 babel-plugin-functional-hmr
によってjestでエラーが吐かなくなります。
汎用的なベストプラクティスがあれば編集リクエストください。
現場からは以上です。