-
Notifications
You must be signed in to change notification settings - Fork 0
DNET_ReactFirstStep2
- 戻る(React -> Redux)
- ...Reactの5thステップ
- Reactのファースト・ステップ2
- Reactのセカンド・ステップ2
- Reactのサード・ステップ2
2026年、リブート(Vite + React + TypeScript + Tailwind)。
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev
※ 生成AIのサポートを受けつつ実施
※ TypeScript については JavaScript の「AltJS」の該当節を参照。
- 最初の一行だけで実行まで行ける。
- 「press h + enter to show help」も実行
PS > npm create vite@latest my-app -- --template react-ts
Need to install the following packages:
create-vite@9.0.3
Ok to proceed? (y) y
> npx
> create-vite my-app --template react-ts
│
◇ Install with npm and start now?
│ Yes
│
◇ Scaffolding project in D:\temp\my-app...
│
◇ Installing dependencies with npm...
added 172 packages, and audited 173 packages in 25s
49 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
│
◇ Starting dev server...
> my-app@0.0.0 dev
> vite
VITE v8.0.2 ready in 940 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
h
Shortcuts
press r + enter to restart the server
press u + enter to show server url
press o + enter to open in browser
press c + enter to clear console
press q + enter to quit
-
コマンドで
cd my-app -
VSCで
my-appフォルダを開き編集できる
-
新規のインストール
npm install xxxx -
package.jsonから。
npm install
npm run dev
外部からのアクセスを可能にする。
npm run dev -- --host
VSCでデバッグ設定を行ってRuntimeに接続する。
-
VSCodeで「デバッグと実行」(Ctrl+Shift+D / Cmd+Shift+D) を開く
-
上部のドロップダウンで Debug Vite App (Chrome) を選択
-
.vscode/launch.json が生成されるので、URL(ポート番号)を修正する。
{ // IntelliSense を使用して利用可能な属性を学べます。 // 既存の属性の説明をホバーして表示します。 // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "chrome", "request": "launch", "name": "localhost に対して Chrome を起動する", "url": "http://localhost:5173/", "webRoot": "${workspaceFolder}" } ] } -
VSCode上の .tsx / .ts ファイルにブレークポイントを設定
-
再度「デバッグと実行」の「▶」再生ボタン または F5 でChromeを起動し、デバッグ接続
-
ビルド
npm run build -
デプロイ
xcopy /E /Y "dist" "配置先"
フロントエンドの開発を面倒な設定なしで TypeScript、JSX、CSS などをすぐに使い始められるツール
(TypeScript / JSX については JavaScript の「AltJS」の該当節を参照)
ほとんどの追加機能(フレームワーク対応、カスタム変換、開発サーバーの拡張など)をプラグインで実現
- webpack時代に比べてプラグインの作成・共有が簡単で、開発者体験(DX)が非常に良い。
- フレームワーク(Vue、React、Svelte、Solidなど)もViteプラグインとして統合される。
- プロジェクト作成時にスキャフォールディングで vite.config.js が生成・編集される。
- 以降は、ほとんどの場合、自分で vite.config.js を直接編集する。
-
esbuildを活用した高速トランスパイルで起動が速い
-
本番ビルドはRollup(現在はRolldownに移行傾向)で最適化
- Rollup:2015年頃にリリースされたバンドラ
- Rolldown:Rust製の次世代バンドラ
-
「開発は速く、本番も高品質」というバランスが取れる。
- HMR (Hot Module Replacement)
- ファイルを編集した時に効率よくブラウザに反映
Rollup/Rolldownに、バンドル、コード分割、minifyなどが同梱される(一部プラグイン)。
- モダンなWeb開発で非常に人気のある Utility-First なCSSフレームワーク
- あらかじめ用意された小さなUtility-Classを組み合わせてデザインを作る。
- Utility-First:CSSにおいて小さな Utility-Class をあらかじめ大量に定義し、それらを組み合わせることでデザインを構築する設計手法。
npm install tailwindcss
npm install @tailwindcss/forms
index.css や globals.css などに追記
@import "tailwindcss";
@plugin "@tailwindcss/forms";AI活用(https://claude.ai/chat )で、殆どWebを参照せず、作業を進めることが出来た(Sonnet4.6)。
ココまでの導入手順もAIに生成させている。
以下はプロンプト
以下で生成したコードを修正して3分割のヘッダ、左メニュー、メインエリアの画面を作成したい。
なお、左メニューのリンクを押下するとメインエリアが画面遷移するものとする。
npm create vite@latest my-app -- --template react-ts
修正内容を教えてください。
以下は、出力から修正ポイントを抜粋したもの。
npm install react-router-dom
src/App.tsx、App.css
-
App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom' import Header from './components/Header' import Sidebar from './components/Sidebar' import Home from './pages/Home' import About from './pages/About' import Settings from './pages/Settings' import './App.css' function App() { return ( <BrowserRouter> <div className="app-container"> <Header /> <div className="body-container"> <Sidebar /> <main className="main-area"> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/settings" element={<Settings />} /> </Routes> </main> </div> </div> </BrowserRouter> ) } export default App
-
App.css
/* src/App.css */ * { margin: 0; padding: 0; box-sizing: border-box; } .app-container { display: flex; flex-direction: column; height: 100vh; } /* ヘッダー */ header { height: 60px; background-color: #1e293b; color: white; display: flex; align-items: center; padding: 0 24px; font-size: 1.2rem; font-weight: bold; flex-shrink: 0; } /* ヘッダー下の横並びエリア */ .body-container { display: flex; flex: 1; overflow: hidden; } /* 左メニュー */ nav.sidebar { width: 220px; background-color: #f1f5f9; border-right: 1px solid #e2e8f0; padding: 16px 0; flex-shrink: 0; overflow-y: auto; } nav.sidebar a { display: block; padding: 12px 24px; text-decoration: none; color: #334155; font-size: 0.95rem; transition: background 0.2s; } nav.sidebar a:hover, nav.sidebar a.active { background-color: #e0e7ef; color: #1e40af; font-weight: 600; } /* メインエリア */ .main-area { flex: 1; padding: 32px; overflow-y: auto; background-color: #ffffff; }
src/components/Header、Sidebar.tsx
-
Header.tsx
export default function Header() { return <header>My App</header> }
-
Sidebar.tsx
import { NavLink } from 'react-router-dom' export default function Sidebar() { return ( <nav className="sidebar"> <NavLink to="/" end className={({ isActive }) => isActive ? 'active' : ''}> Home </NavLink> <NavLink to="/about" className={({ isActive }) => isActive ? 'active' : ''}> About </NavLink> <NavLink to="/settings" className={({ isActive }) => isActive ? 'active' : ''}> Settings </NavLink> </nav> ) }
src/pages/Home、About、Settings.tsx
-
Home.tsx
export default function Home() { return <div><h1>ホーム</h1><p>ホームページです。</p></div> }
-
About.tsx
export default function About() { return <div><h1>アバウト</h1><p>アバウトページです。</p></div> }
-
Settings.tsx
export default function Settings() { return <div><h1>設定</h1><p>設定ページです。</p></div> }
-
移行元(react_template)
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/old/react_template/src/common.js
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/old/react_template/src/const.js
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/old/react_template/src/touryo/common.js
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/old/react_template/src/touryo/oauth_oidc.js
-
移行先(vite-react-ts)
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/vite-react-ts/src/common.ts
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/vite-react-ts/src/const.ts
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/vite-react-ts/src/touryo/common.ts
- https://github.com/OpenTouryoProject/FrontendTemplates/blob/develop/UI/SPA/React/vite-react-ts/src/touryo/oauth_oidc.ts
- Counter.jsコンポーネントをTSXに変換
- App.tsx、Sidebar.tsxに組み込む。
-
FetchData.jsコンポーネントをTSXに変換
-
App.tsx、Sidebar.tsxに組み込む。
-
WebAPI呼び出しを行って実行をテスト。
-
修正
- WebAPI(SampleDataController.cs)をRST上に復元
- FetchDataの処理をページング対応させた。
- CrudSample.jsコンポーネントをTSXに変換
- App.tsx、Sidebar.tsxに組み込む。
- WebAPI呼び出しを行って実行をテスト。
- SignIn、RedirectOfAuth.jsコンポーネントをTSXに変換
- Header.tsxにSignInを組み込む。
- App.tsxにRedirectOfAuthを組み込む。
- 認証テストを実行し、デバッガでデバッグ、修正して完了。
- CrudSample画面をコンポーネント分割した版。
- Input、DDL、Button、Output.tsxをコンポーネント化
fetchとはWebAPI呼び出し処理のこと。
-
プロンプト
AIに共通関数を提案させ、 以下の2つの関数から共通部を切り出せますか? 切り出した関数は、ライブラリ化して2つの関数内から呼び出します。 selectAll_DT() { this.setState({ message: '' }); const method = 'POST'; const headers = oauth_oidc.createHttpRequestHeader(false); const body = 'ddlDap=' + this.state.ddl.ddlDap + '&ddlMode1=' + this.state.ddl.ddlMode1 + '&ddlMode2=' + this.state.ddl.ddlMode2 + '&ddlExRollback=' + this.state.ddl.ddlExRollback; fetch(constants.CrudSampleRootUrl + 'SelectAll_DT', { method, headers, body }) .then(oauth_oidc.fetchStatusHandler) .then(response => response.json()) .then(data => { if (data.result) { this.setState({ message: '', shippers: data.result, loading: false }); } else if (data.errorMSG) { this.setState({ message: JSON.stringify(data.errorMSG) }); } else if (data.exceptionMSG) { this.setState({ message: JSON.stringify(data.exceptionMSG) }); } }) .catch((error: Error) => { this.setState({ message: JSON.stringify(error.stack) }); }); } delete() { this.setState({ message: '' }); const method = 'POST'; const headers = oauth_oidc.createHttpRequestHeader(true); const body = JSON.stringify({ ddlDap: this.state.ddl.ddlDap, ddlMode1: this.state.ddl.ddlMode1, ddlMode2: this.state.ddl.ddlMode2, ddlExRollback: this.state.ddl.ddlExRollback, shipper: { shipperID: this.state.shipper.shipperID, companyName: '', phone: '', }, }); fetch(constants.CrudSampleRootUrl + 'Delete', { method, headers, body }) .then(oauth_oidc.fetchStatusHandler) .then(response => response.json()) .then(data => { if (data.message) { this.setState({ message: data.message }); } else if (data.errorMSG) { this.setState({ message: JSON.stringify(data.errorMSG) }); } else if (data.exceptionMSG) { this.setState({ message: JSON.stringify(data.exceptionMSG) }); } }) .catch((error: Error) => { this.setState({ message: JSON.stringify(error.stack) }); }); } -
出力
ちなみに getFetch も準備した。type SuccessHandler = (data: Record<string, unknown>) => void; /** * 共通のfetchラッパー * @param url リクエスト先URL * @param headers HTTPヘッダー * @param body リクエストボディ * @param onSuccess 成功時のハンドラ(data.errorMSG / data.exceptionMSG 以外の処理) * @param setMessage メッセージをセットする関数 */ export function postFetch( url: string, headers: HeadersInit, body: BodyInit, onSuccess: SuccessHandler, setMessage: (msg: string) => void, ): void { setMessage(''); fetch(url, { method: 'POST', headers, body }) .then(oauth_oidc.fetchStatusHandler) .then(response => response.json()) .then((data: Record<string, unknown>) => { if (data.errorMSG) { setMessage(JSON.stringify(data.errorMSG)); } else if (data.exceptionMSG) { setMessage(JSON.stringify(data.exceptionMSG)); } else { onSuccess(data); } }) .catch((error: Error) => { setMessage(JSON.stringify(error.stack)); }); }
-
ソレを使用するように書き直した。
- 拡張はコールバックにて行う。
- 幾つかの問題は生成AIで修正
// 元のクラス内 selectAll_DT() { const headers = oauth_oidc.createHttpRequestHeader(false); const body = 'ddlDap=' + this.state.ddl.ddlDap + '&ddlMode1=' + this.state.ddl.ddlMode1 + '&ddlMode2=' + this.state.ddl.ddlMode2 + '&ddlExRollback=' + this.state.ddl.ddlExRollback; postFetch( constants.CrudSampleRootUrl + 'SelectAll_DT', headers, body, (data) => { if (data.result) { this.setState({ message: '', shippers: data.result, loading: false }); } }, (msg) => this.setState({ message: msg }), ); } delete() { const headers = oauth_oidc.createHttpRequestHeader(true); const body = JSON.stringify({ ddlDap: this.state.ddl.ddlDap, ddlMode1: this.state.ddl.ddlMode1, ddlMode2: this.state.ddl.ddlMode2, ddlExRollback: this.state.ddl.ddlExRollback, shipper: { shipperID: this.state.shipper.shipperID, companyName: '', phone: '', }, }); postFetch( constants.CrudSampleRootUrl + 'Delete', headers, body, (data) => { if (data.message) { this.setState({ message: data.message }); } }, (msg) => this.setState({ message: msg }), ); }
デザインをTailwind 拡張にするように修正。
- 全体的に編集中のコードの提示では上手く行かないことが多かった。
- ChromeのF12(DevTools)で「Elements」パネルや
*.cssの情報をプロンプトに入れると良い。
-
Vite ってよく聞くけど何なんですか? あれは
https://zenn.dev/comm_vue_nuxt/articles/what-is-vite -
FrontendTemplates/UI/SPA/React at develop · OpenTouryoProject/FrontendTemplates
https://github.com/OpenTouryoProject/FrontendTemplates/tree/develop/UI/SPA/React
移行メモ
- 「全体的に編集中のコードの提示では上手く行かなことが多かった。」→ 「上手く行かないことが多かった。」に修正した。
- 「ChromeのF12で「Application」の「Element」」は、Chrome DevTools では 「Elements」が「Application」の下ではなく独立したパネルであるため、 「ChromeのF12(DevTools)で「Elements」パネル」に修正した。
- 生成AIの出力をそのまま貼り付けたことによりコードの先頭に コード・ブロックの言語名が混入していた箇所(
css@import "tailwindcss";)は、 言語名を除去してコード・フェンスの言語指定に移した。- 元 Wiki の
[[Webpack]](先頭大文字)は元 Wiki 側にページが存在しない リンク切れだったため、実在する webpack へのリンクとした。- 同名の見出し(「インストール」「設定」)が複数あり GitHub Wiki でアンカが衝突するため、括弧で文脈を補って一意にした。
- PukiWiki のページ内アンカ(
#xxxxxxxx)は GitHub Wiki では再現できないため、 同一ページ内のアンカは見出しから生成されるアンカに張り替え、 他ページのアンカを指すリンクは「〜(ページ名の該当節を参照)」の形に置き換えた。
Tags: 移行, React, Vite, TypeScript, Tailwind, react-router-dom, 生成AI, リブート
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。