簡単にコンポーネントなどをシェアしたい
create-react-appの環境下でコンポーネントを複数プロジェクトで共有などで調べると、Lerna
を使用してmonorepoにしたり、create-react-appをejectしたりなど、あまり気軽には行えない印象でした。
そこまでアプリも大きくないので、ユーザータイプ毎に条件分岐して出し分ければいいかな...と考えていたのですが、バンドルサイズがその内デカくなってしまうのも問題です。
しばらく調べていると、下記の記事で手軽に出来る方法がわかりました。
参考: Multiple entry points in create-react-app without ejecting
ダイナミックインポートで対応する
今回実施したかったのは、ユーザータイプ毎にサイトを切り分けることです。(public, adminなど)
それを行うために、単純にビルド時に環境変数を渡して、Appレベルのコンポーネントを条件分岐してダイナミックインポートするというものでした。
実装
まず、ビルド時にnpm scriptから環境変数を渡します。以下adminの例です。
※プロジェクトルートから実施しているため、appのprefixを入れています。
"build:admin": "REACT_APP_TARGET=admin npm run build --prefix app"
次に、ReactDOMでレンダーしているルートのファイルに、ダイナミックインポートを追加します。
条件分岐がスッキリ見えないですが無視してください。
function importBuildTarget() {
if (process.env.REACT_APP_TARGET === 'admin') {
return import('./components/AdminApp');
} else if (process.env.REACT_APP_TARGET === 'public') {
return import('./components/PublicApp');
} else {
return Promise.reject(
new Error('No such build target: ' + process.env.REACT_APP_TARGET)
);
}
}
importBuildTarget().then(({default: Target}) =>
ReactDOM.render(
<React.StrictMode>
<Target />
</React.StrictMode>,
document.getElementById('root')
)
);
これで基本的に完了です。あとはそれぞれのAppで好き放題書くだけになります。
その他
今回はfirebaseにホスティングしていたので、firebase.json
とビルドコマンドでそれぞれ切り分けました。
{
"target": "admin",
"public": "app/build",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
"hosting:admin": "npm run build:admin && firebase deploy --only hosting:admin"