3 min read

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 への切り替えを行いました。

Bootstrap
Tailwind CSS

Tailwind CSS 版はちょっとフッターをいじったたりしていますが、概ね似たようなデザインを実現できました。この後 preact/compat などを無事やめることができました。今は完全に Preact と Signals の構成に切り替わっています。

雑感

Preact + Tailwind CSS への移行で、コード行数は普通にふえました。ざっくり 2000 行くらい増えている気がします。とはいえ、無事 React と Bootstrap からの切り替えができてほっとしています。

ちなみに Biome から Oxc への切り替えも行いました。決め手は oxlint --type-aware です。

Type-Aware Linting Alpha
A collection of high-performance JavaScript tools written in Rust

今後

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