- Laravelのセットアップ
- CoreUI管理画面テンプレートのデータをダウンロードしてZIPを展開
- 必要なライブラリをインストール
- Laravel側のファイルの書き換え
- SCSSのコンパイルでWarningが出まくるよ問題
- ルーティングの問題
- Reactのページコンポーネントが表示されるまでの道のり(ここまでのまとめ)
- で、色々とやったのをここに
前の記事の続き。ただし、「CoreUIのCSSを読み込む 」のところは後述するように変更している。
CoreUIでLaravelの管理画面作るのにテンプレートが必要で、それはnpmで一発インストールできるわけじゃないんですね。見本にあるのをちゃちゃっと行けると思ったんだけど、そんな甘くなかった。
CoreUIはパーツで管理画面はコンポーネント?みたいな。どっちかというとレイアウトか。
CoreUI謹製のLaravelテンプレートもあったんだけど、もう丸っと4年更新が止まっててLaravel7に対応したよってのが最後らしいので自力でガンバるか。 github.com
この記事が「あ、できるんだな」って気持ちにさせてくれるレベルで参考になりました。 techshack-creatives.medium.com
Laravelのセットアップ
前の記事の通り。Breezeを入れて、coreuiをnpmでインストールする。
CoreUI管理画面テンプレートのデータをダウンロードしてZIPを展開
ということでここからデータをダウンロードする。メールを登録するとそこにダウンロードURLが送られてくる。ありがとうございます。
選んだのは、Reactの管理画面テンプレート。 coreui.io
手に入れたZIPファイル( coreui-free-react-admin-template-main.zip)を展開するとこんな感じ。
$ tree . . ├── LICENSE ├── README.md ├── index.html ├── package.json ├── public │ ├── favicon.ico │ └── manifest.json ├── src │ ├── App.js │ ├── _nav.js │ ├── assets │ │ ├── brand │ │ │ ├── logo.js │ │ │ └── sygnet.js │ │ └── images │ │ ├── angular.jpg │ │ ├── avatars │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.jpg │ │ │ ├── 7.jpg │ │ │ ├── 8.jpg │ │ │ └── 9.jpg │ │ ├── react.jpg │ │ └── vue.jpg │ ├── components │ │ ├── AppBreadcrumb.js │ │ ├── AppContent.js │ │ ├── AppFooter.js │ │ ├── AppHeader.js │ │ ├── AppSidebar.js │ │ ├── AppSidebarNav.js │ │ ├── DocsCallout.js │ │ ├── DocsExample.js │ │ ├── DocsLink.js │ │ ├── header │ │ │ ├── AppHeaderDropdown.js │ │ │ └── index.js │ │ └── index.js │ ├── index.js │ ├── layout │ │ └── DefaultLayout.js │ ├── routes.js │ ├── scss │ │ ├── _custom.scss │ │ ├── _theme.scss │ │ ├── _variables.scss │ │ ├── examples.scss │ │ ├── style.scss │ │ └── vendors │ │ └── simplebar.scss │ ├── store.js │ └── views │ ├── base │ │ ├── accordion │ │ │ └── Accordion.js │ │ ├── breadcrumbs │ │ │ └── Breadcrumbs.js │ │ ├── cards │ │ │ └── Cards.js │ │ ├── carousels │ │ │ └── Carousels.js │ │ ├── collapses │ │ │ └── Collapses.js │ │ ├── index.js │ │ ├── jumbotrons │ │ │ └── Jumbotrons.js │ │ ├── list-groups │ │ │ └── ListGroups.js │ │ ├── navbars │ │ │ └── Navbars.js │ │ ├── navs │ │ │ └── Navs.js │ │ ├── paginations │ │ │ └── Paginations.js │ │ ├── placeholders │ │ │ └── Placeholders.js │ │ ├── popovers │ │ │ └── Popovers.js │ │ ├── progress │ │ │ └── Progress.js │ │ ├── spinners │ │ │ └── Spinners.js │ │ ├── tables │ │ │ └── Tables.js │ │ ├── tabs │ │ │ └── Tabs.js │ │ └── tooltips │ │ └── Tooltips.js │ ├── buttons │ │ ├── button-groups │ │ │ └── ButtonGroups.js │ │ ├── buttons │ │ │ └── Buttons.js │ │ ├── dropdowns │ │ │ └── Dropdowns.js │ │ └── index.js │ ├── charts │ │ └── Charts.js │ ├── dashboard │ │ ├── Dashboard.js │ │ └── MainChart.js │ ├── forms │ │ ├── checks-radios │ │ │ └── ChecksRadios.js │ │ ├── floating-labels │ │ │ └── FloatingLabels.js │ │ ├── form-control │ │ │ └── FormControl.js │ │ ├── input-group │ │ │ └── InputGroup.js │ │ ├── layout │ │ │ └── Layout.js │ │ ├── range │ │ │ └── Range.js │ │ ├── select │ │ │ └── Select.js │ │ └── validation │ │ └── Validation.js │ ├── icons │ │ ├── brands │ │ │ └── Brands.js │ │ ├── coreui-icons │ │ │ └── CoreUIIcons.js │ │ ├── flags │ │ │ └── Flags.js │ │ └── index.js │ ├── notifications │ │ ├── alerts │ │ │ └── Alerts.js │ │ ├── badges │ │ │ └── Badges.js │ │ ├── index.js │ │ ├── modals │ │ │ └── Modals.js │ │ └── toasts │ │ └── Toasts.js │ ├── pages │ │ ├── login │ │ │ └── Login.js │ │ ├── page404 │ │ │ └── Page404.js │ │ ├── page500 │ │ │ └── Page500.js │ │ └── register │ │ └── Register.js │ ├── theme │ │ ├── colors │ │ │ └── Colors.js │ │ └── typography │ │ └── Typography.js │ └── widgets │ ├── Widgets.js │ ├── WidgetsBrand.js │ └── WidgetsDropdown.js └── vite.config.mjs
とりあえず、この中の src
ディレクトリを resources/js/coreui
としてコピーする。resources/js/coreui/App.js
とかができることになる。
必要なライブラリをインストール
laravelのpackage.jsonとcoreui-templateのpackage.jsonを比較してcoreui-templateで必要なライブラリをインストールする。自分の場合
npm i @coreui/chartjs @coreui/icons @coreui/icons-react @coreui/react-chartjs @coreui/utils chart.js classnames core-js prop-types react-redux react-router-dom redux simplebar-react npm i -D @vitejs/plugin-react
だった。
Laravel側のファイルの書き換え
resources/js/coreui のコンポーネントファイルを.tsx拡張子にする
TypeScriptで書いているので、.jsなのを.tsxにする。ただし、まとめて読み込んでいるindex.jsやAssetなどは変えない。
- coreui/components
- coreui/layout
- coreui/views
の中にある大文字から始まるファイルがJSXコンポーネントを含んでいるものなので、拡張子を.jsから.tsxに変更。renameコマンド使うならこんな感じ。
find src/resources/js/coreui -type f -name "*.js" ! -name "index.js"|xargs -I{} rename "s/.js/.tsx/;" {}
レイアウトの resources/js/Layouts/AuthenticatedLayout.tsx (管理画面なので)
resources/js/coreui/App.js
を参考にしてreturnを以下の通りにする。
import { Link, usePage } from '@inertiajs/react'; import React, { PropsWithChildren, ReactNode, Suspense, useState } from 'react'; import { CSpinner } from '@coreui/react'; import DefaultLayout from '@/coreui/layout/DefaultLayout'; import { Provider } from 'react-redux' import { BrowserRouter, Route, Routes } from 'react-router-dom' import store from '../coreui/store' export default function Authenticated({ header, children, }: PropsWithChildren<{ header?: ReactNode }>) { const user = usePage().props.auth.user; const [showingNavigationDropdown, setShowingNavigationDropdown] = useState(false); return ( <BrowserRouter> <Provider store={store}> <Suspense fallback={ <div className="pt-3 text-center"> <CSpinner color="primary" variant="grow" /> </div> } > <Routes> <Route path="*" element={<DefaultLayout> {header && ( <header className="bg-white shadow"> <div className="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8"> {header} </div> </header> )} {children} </DefaultLayout>} /> </Routes> </Suspense> </Provider> </BrowserRouter> ) }
CSSの読み込み
resources/css/app.scss
に以下の行を追加。
@import "@coreui/coreui/scss/coreui"; @import "../js/coreui/scss/theme";
chartjs使いたかったら、@import "@coreui/chartjs/scss/coreui-chartjs";
も追加。
DefaultLayout コンポーネントでchildrenを出す。
これをやらないと、Dashboard.tsxで表示させたいコンテンツが表示されない。
import React, { ReactNode } from 'react' import { AppContent, AppSidebar, AppFooter, AppHeader } from '../components/index' const DefaultLayout = (props: {children: ReactNode}) => { const {children} = props; return ( <div> <AppSidebar /> <div className="wrapper d-flex flex-column min-vh-100"> <AppHeader /> <div className="body flex-grow-1"> <AppContent /> {children} </div> <AppFooter /> </div> </div> ) } export default DefaultLayout
SCSSのコンパイルでWarningが出まくるよ問題
CoreUIがSASSでDeprecatedなグローバル変数や@import、mixinを使いまくっているのでWarningが出まくってデバッグしづらい。
そもそも、コンパイルする時間が長い…
ってことで、もう最初からコンパイルしたものを@importだけでいいんじゃないかな?って思った。
管理画面テンプレートをbuildする。
全然別のディレクトリに coreui-free-react-admin-template-main.zip を持ってきて以下の作業をする。
unzip coreui-free-react-admin-template-main.zip cd coreui-free-react-admin-template-main npm i npm run build
で、 build/assets/index-wUvqVzu6.css
みたいなファイルができるのでこれをLaravelの resources/css/coreui-template.css
とでもコピーして resources/css/app.scss
で@importする。
@tailwind base; @tailwind components; @tailwind utilities; /* coreuiコンポーネント */ @import './coreui-template.css';
ルーティングの問題
3つ考えなければならない。
- Laravel側のルーティング
- ReactのRoute登録
- 管理メニューの変更
後者2つのCoreUIのテンプレートの2つは関連しているのかと思いきや、全然そうでもなかった。ReactのRouteの登録は、resources/js/coreui/routes.js
で、左側管理メニューは resources/js/coreui/_nav.tsx
で行っている。両方のPathを合わせてやるとDashboard.tsxからリンクを踏んだ時にページが表示される。まぁ、なかなか一発でimportされんくてlazyloadとかを直接importにしたり、ちょいちょいと変更しなければならないけど。
ただ、このReactのルーティングを行っても http://localhost:8000/admin/buttons/dropdowns に 直接アクセス すると404エラーになってしまう。Laravel側のルーティングが無いからね。
とういことで、LaravelのRoutingを少し変更。
<?php Route::middleware(['auth', 'verified'])->name('admin')->any('/admin/{operation}/{target?}', function(){ return Inertia::render('Dashboard', []); });
どうせGETしか来ないから、->anyじゃなくて->getでもいいかも。
Reactのページコンポーネントが表示されるまでの道のり(ここまでのまとめ)
- routes/web.phpで任意のルーティングにはReactを起動させるようにする。
Inertia::render('Dashboard', []);
をreturnさせると、Dashboardコンポーネントをブラウザのファーストアクセス時に起動する。ただし、このDashboardコンポーネントのパスは後で決められる。 app/Http/Middleware/HandleInertiaRequests.php
で、HandleInertiaRequests::rootView()の返すbladeテンプレートを決める。返り値がadmin
だと、resources/views/admin.blade.php
がそれになる。- そのbladeテンプレートで使える変数、
$page['component']
が先ほどのInertia::render()の第一引数でReactのページコンポーネントである。render()の第二引数はそのコンポーネントのpropsに渡す値。 - bladeテンプレートでは、以下の3行でReactを呼び出す。
@viteReactRefresh
@vite(['resources/js/admin.tsx', "resources/js/Pages/Admin/{$page['component']}.tsx"])
@inertiaHead
2行目の配列は、1つ目がメインのInertia.jsを記述する。上記の場合は、resources/js/admin.tsx
となる。これはBreezeをインストールされる時に自動生成されるのでコピーさせて増やせる。resolvePageComponent()で対象にするページコンポーネントのファイルを指定する。2つ目に最初のReactページコンポーネントを指定する。この場合、$page['component']はDashboardになる。ので、resources/js/Pages/Admin/Dashboard.tsx
が該当のページコンポーネントである。 - このDashboardコンポーネントなどのReactコンポーネントでは、HandleInertiaRequests::share()で返す値を
usePage().props
として取り出せる。
で、ここまで作って、管理者画面のDashboardコンポーネントはただの入り口ではなくすべてを受けるデフォルトページなんだと気づいた。ReactのRouteでいうところのresources/js/Pages/Admin/Dashboard.tsx
を resources/js/Pages/Admin/Default.tsx
と変更する。
で、色々とやったのをここに
置いておく。