React + Bootstrap から Preact + Tailwind CSS へ切り替えた
自社製品のブラウザ向け開発ツールを Preact + Tailwind CSS へ切り替えたので雑に書いて行きます。
2020 年の package.json
2017 年から自社製品の組み込みとして提供しており、OSS の開発ツールとして公開したのが 2020 年ということで、2020 年との比較にしてます。
"dependencies": {
"@reduxjs/toolkit": "^1.4.0",
"bootstrap": "^4.5.2",
"query-string": "^6.13.1",
"react": "^16.13.1",
"react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1",
"react-redux": "^7.2.1",
"redux-logger": "^3.0.6",
"sora-js-sdk": "^2020.2.0"
},
"devDependencies": {
"@types/node": "^14.10.0",
"@types/react": "^16.9.49",
"@types/react-redux": "^7.1.9",
"@types/redux-logger": "^3.0.8",
"@types/resize-observer-browser": "^0.1.3",
"@typescript-eslint/eslint-plugin": "^4.1.0",
"@typescript-eslint/parser": "^4.1.0",
"eslint": "^7.8.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-react-hooks": "^4.1.1",
"eslint-plugin-simple-import-sort": "^5.0.3",
"next": "^9.5.3",
"nextjs": "^0.0.3",
"prettier": "^2.1.1",
"typescript": "^4.0.2"
},
2026 年の package.json
"dependencies": {
"@shiguredo/mp4-media-stream": "2024.3.0",
"@shiguredo/noise-suppression": "2025.1.0",
"@shiguredo/virtual-background": "2023.2.0",
"@preact/signals": "2.5.1",
"preact": "10.28.1",
"sora-js-sdk": "2025.2.0"
},
"devDependencies": {
"@fast-check/vitest": "0.2.4",
"@playwright/test": "1.57.0",
"@preact/preset-vite": "2.10.2",
"@tailwindcss/vite": "4.1.18",
"@types/node": "25.0.3",
"dotenv": "17.2.3",
"fast-check": "4.5.3",
"jsdom": "27.4.0",
"oxfmt": "0.21.0",
"oxlint": "1.36.0",
"oxlint-tsgolint": "0.10.0",
"preact-render-to-string": "6.6.5",
"tailwindcss": "4.1.18",
"typescript": "5.9.3",
"vite": "7.3.0",
"vitest": "4.0.16"
},Preact 切り替え前までの振り返り
とにかく WebRTC のブラウザ向け開発ツールを SSG (Static Site Generation) を OSS として公開したい、という自分の要望で作られたのですが、開発当時は SSG をうまいことやってくれるフレームワークは Next.js くらいしかなかったような気がします。当時は Yarn を使ってた記憶があります。
その後は長い間 Next.js を使っていました。2023 頃に Vitest を導入して最低限のテストを追加しました。Prettier から Biome に切り替えたのもこの頃です。
そこから Next.js を外して React と Vite の組み合わせに切り替えたのが 2024 年です。この時点で SSG から SPA (Single Page Application) になりました。Playwright による E2E テストを導入したのもその頃でした。Next.js は 2 回目のチャレンジでやっと切り替えられた記憶があります。
2025 年に状態管理ライブラリを Redux から Zustand に切り替えました。Zustand 化はたしか 3 回目のチャレンジでの切り替えでした。
React から Preact へ
React や Redux が悪いとかは本当にないのですが、自社の利用方法からすると正直オーバーキルという感じが強く、ずっと Preact への移行を検討していました。
ただ、そのためには React Bootstrap から脱却する必要があり、さてどうしたものかと悩んでいたら、Preact はどうやら React 互換を実現する preact/compat というのがあることに気付きました。
また状態管理ライブラリとして Signals があるので、まずは React 互換モードを有効活用して Preact と Signals への移行をすることにしました。
React Bootstrap から Tailwind CSS へ
最初は UI コンポーネントも検討したのですが、難しい仕組みを使うこともないので、できるだけ Bootstrap に寄せたデザインを維持しながら、Tailwind CSS への切り替えを行いました。


Tailwind CSS 版はちょっとフッターをいじったたりしていますが、概ね似たようなデザインを実現できました。この後 preact/compat などを無事やめることができました。今は完全に Preact と Signals の構成に切り替わっています。
雑感
Preact + Tailwind CSS への移行で、コード行数は普通にふえました。ざっくり 2000 行くらい増えている気がします。とはいえ、無事 React と Bootstrap からの切り替えができてほっとしています。
ちなみに Biome から Oxc への切り替えも行いました。決め手は oxlint --type-aware です。

今後
DuckDB-Wasm と uPlot による可視化の仕組みを組み込んだりしていこうと思っています。また Playwright や Vitest を使って積極的にテストを組み込んでいければと思います。