◆ index.html へ自由にデータを埋め込みできない
◆ index.js からインポートするモジュール内で最初に作る
◆ サーバから取得して埋め込みもできるが非同期処理になる
   ◆ 埋め込み前提のモジュールでエラーになる場合があるので工夫が必要
   ◆ React アプリの初期化を準備できてからになるよう遅延させる
   ◆ プロダクションビルドでも 1 ファイル余分にリクエストが増える

以前書いたこれの続きです
build する分には困らなかったのですが 実際になにか作るとなるとファイルの変更を監視して自動で更新してくれる開発サーバを使います
開発サーバでは index.html が使われて データの埋め込みはありません
プロダクションビルドでは HTML に埋め込まれてるはずのデータがないとなると色々不便です

ドキュメントを見ても index.html を動的にはできなさそうだったので JavaScript 側で対処します

静的に

単純な方法は index.js でダミーデータスクリプトを最初に import します

index.js
import "./dummy.js"

// 以降にその他モジュールの import

一番最初に実行される処理になるので この dummy.js でダミーデータを作れば実質 HTML に埋め込まれていたのと変わりません

dummy.js
if (process.env.NODE_ENV !== 'production') {
window.INIT_DATA = {
foo: "bar",
}
}

ダミーデータがプロダクションビルドに入るのは気持ち悪い部分ですが NODE_ENV の if を入れておくと確実に false になることで minify で消えるらしいです

画面表示のためのデータを最初に取得せず HTML に埋め込まれたデータに全部入ってる作りにするなら ページごとのダミーデータを URL で分岐して用意する必要があります
SSG のビルド時みたいに全ページのデータをサーバから取得してしまえばいいですが それをやるのは面倒ですし サーバ側で変えたときに追従できないのが不便です

動的に

API で毎回取得するように 初期データも動的にします

dummy.js
export default async () => {
const url = new URL(location)
const backend_url = url.href.replace(url.origin, "http://localhost:8000")
const html = await fetch(backend_url).then(x => x.text())
const doc = new DOMParser().parseFromString(html, "text/html")
window.INIT_DATA = JSON.parse(doc.querySelector("#data").innerHTML)
}

API があればそれをつかえばいいのですが SPA にしなくて HTML 埋め込み予定だと API がないこともあります
開発サーバの都合だけで API 用意も大変なので HTML から埋め込まれた JSON データを取り出してます

index.js
import setDummy from "./dummy.js"

const run = async () => {
const { default: App } = await import("./App.js")

ReactDOM.render(
<App/>,
document.getElementById("root")
)
}

if (process.env.NODE_ENV !== 'production') {
setDummy().then(run)
} else {
run()
}

ダミーデータの取得が非同期になると HTML に埋め込まれてる前提のモジュールが動かなくなるので ダミーデータの設置が完了してから App モジュールのロードを行います
ここが動的になるので プロダクションビルドでもファイルが分かれて App.js を動的にロードすることになります
せっかく webpack してるのに開発サーバの都合でプロダクションビルドに無駄な 1 リクエストを増やしたくないという場合は build 時に index.js を差し替えてから react-scripts の build を行うようにすれば回避はできます