昨年はサービスのフロントをVueで作ったり、Vue.js+Nuxt.js+Vuetifyを3系にバージョンアップしたり、JestをVitestに切り替えたりと、個人開発のみならず仕事でもフロントはVueをかなり使いました。バックエンドはRailsで開発、7系にバージョンアップもしました。
今年はReactに挑戦して、サービスをリリースしたいと考えています。
(Vueを使った方が早いけどあえて)

フレームワーク選定

React自体はライブラリなので、ルーティング等をしてくれるフレームワークがあると便利。
CSR(Client Side Rendering)かSSR(Server Side Rendering)かで、本番環境で静的ファイルが返せれば良いのか、Nodeサーバーが必要なのかが変わってきます。
また、SEOに力を入れる必要があるならSSR、ログイン前提ならCSRの方がサーバー管理から解放されるので良いです。

本番環境対応の React フレームワーク -> React プロジェクトを始める – React
Next.js, Gatsby and Remix. Which is right for project?• Flexmonster

Next.js: SSR, SSG(Static Site Generation), CSR
Remix: SSR
Gatsby: SSG

Nuxt.js(Vue)では、nuxt.config.ts「ssr: false」で、CSRのみに設定できましたが、
Next.js(React)のCSRは存在しないと書いている人もいるように、SSR+CSRで使うもののようです。
Gatsbyは、SSGなので、動的サイトには向いていない。
という事で、CSRのみは諦め、シェアの高いNext.jsを使う事にしました。

UIコンポーネントライブラリ選定

NextUI

Next使うならこれかなと思いきや、
NextUI – Beautiful, fast and modern React UI Library

Grid(Vuetifyだとv-row/v-col)がv2に存在しない。v1には存在する。
v2 -> Introduction | NextUI – Beautiful, fast and modern React UI Library
v1 -> Grid | NextUI – Beautiful, fast and modern React UI Library

あと、layout.tsxで呼び出すNextUIProviderに’use client’を付けなきゃいけないのが気になりました。(まだ、ちゃんと理解できていないだけなのか?)
Setup Provider -> Next.js | NextUI – Beautiful, fast and modern React UI Library

Material UI(MUI)

Material Designを使いたいので、こちらを使う事にしました。
Material UI: React components that implement Material Design

当然かもですが、Gridも存在する。
React Grid component – Material UI

Next.jsとMaterial UIインストール

Getting Started: Installation | Next.js
Installation – Material UI
Next.js integration – Material UI

% npx create-next-app@latest next-app-origin
✔ Would you like to use TypeScript? … No / [Yes]
✔ Would you like to use ESLint? … No / [Yes]
✔ Would you like to use Tailwind CSS? … [No] / Yes		← Material UI使うので不要
✔ Would you like to use `src/` directory? … No / [Yes]		← app使うかsrc/app使うか?好みで
✔ Would you like to use App Router? (recommended) … No / [Yes]	← App Routerが新しい。従来のPages Routerも使える
✔ Would you like to customize the default import alias (@/*)? … No / [Yes]
✔ What import alias would you like configured? … @/*

% cd next-app-origin
% npm install @mui/material @emotion/react @emotion/styled
% npm install @mui/material-nextjs @emotion/cache

src/app/layout.tsx

import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
- import './globals.css'
+ import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter'
+ import { ThemeProvider } from '@mui/material/styles'
+ import { theme } from '@/theme'
+ import CssBaseline from '@mui/material/CssBaseline'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
-    <html lang="en">
+    <html>
-      <body className={inter.className}>{children}</body>
+      <body className={inter.className}>
+        <AppRouterCacheProvider>
+          <ThemeProvider theme={theme}>
+            <CssBaseline />
+            <main>{children}</main>
+          </ThemeProvider>
+        </AppRouterCacheProvider>
+      </body>
    </html>
  )
}

src/app/globals.css

% rm -f src/app/globals.css

src/theme.ts

'use client'
import { createTheme } from '@mui/material/styles'

const theme = createTheme({
  palette: {
    mode: 'dark'
  }
})

export {
  theme
}

トップページ実装

src/app/page.tsx

import NextLink from 'next/link'
import { Grid, Card, CardActionArea, CardContent, Typography, Link, Box } from "@mui/material"
import SignUp from './components/SignUp'
import Infomations from './components/Infomations'

export default function Page() {
  return (
    <>
      <Grid container spacing={2}>
        <Grid item xs={12} md={12}>
          <Card>
            <CardActionArea>
              <CardContent>
                <Typography gutterBottom variant="h6" component="div">
                  Next.js(React/Material UI)のベースアプリケーションです。(サービス概要に差し替え)
                </Typography>
                <Typography variant="body2" color="text.secondary">
                  サービスを迅速に立ち上げられるように、よく使う機能を予め開発しています。(サービス説明に差し替え)<br />
                  リポジトリ: <Link href="https://dev.azure.com/nightonly/_git/next-app-origin" target="_blank" rel="noopener noreferrer">https://dev.azure.com/nightonly/_git/next-app-origin</Link>
                </Typography>
              </CardContent>
            </CardActionArea>
          </Card>
        </Grid>
        {true
          ? <Grid item xs={12} md={6}>
              <SignUp />
            </Grid>
          : ''
        }
        <Grid item xs={12} md={6}>
          <Infomations />
        </Grid>
      </Grid>
      {process.env.NODE_ENV !== 'production'
        ? <>
            <Box sx={{ m: 2 }} />
            <Grid container spacing={2}>
              <Grid item xs={12} md={6}>
                <Card>
                  <CardActionArea>
                    <CardContent>
                      <Typography gutterBottom variant="h6" component="div">
                        development
                      </Typography>
                      <Typography variant="body2">
                        <Link component={NextLink} href="/development/color">テーマカラー確認</Link>
                      </Typography>
                    </CardContent>
                  </CardActionArea>
                </Card>
              </Grid>
            </Grid>
          </>
        : ''
      }
    </>
  )
}

src/app/page.module.css

% rm -f src/app/page.module.css

src/app/components/SignUp.tsx

'use client'
import NextLink from 'next/link'
import { Card, CardActionArea, CardContent, CardActions, Typography, Divider, Button, Link } from "@mui/material"
import PersonAddIcon from '@mui/icons-material/PersonAdd'

export default function App() {
  return (
    <Card>
      <CardActionArea>
        <CardContent>
          <Typography gutterBottom variant="h6" component="div">
            アカウント登録
          </Typography>
          <Typography variant="body2" color="text.secondary">
            <Button variant="contained" startIcon={<PersonAddIcon />} href="/users/sign_up">無料で始める</Button>
          </Typography>
        </CardContent>
        <Divider />
        <CardActions>
          <Typography variant="body2" m={1}>
            <Link component={NextLink} href="/users/sign_in">ログイン</Link>
          </Typography>
        </CardActions>
      </CardActionArea>
    </Card>
  )
}

src/app/components/Infomations.tsx

'use client'
import { Card, CardActionArea, CardContent, Typography, Link } from "@mui/material"

export default function App() {
  return (
    <Card>
      <CardActionArea>
        <CardContent>
          <Typography gutterBottom variant="h6" component="div">
            大切なお知らせ
          </Typography>
          <Typography variant="body2">
            TODO
          </Typography>
        </CardContent>
      </CardActionArea>
    </Card>
  )
}

ポート変更

デフォルトの3000だとRailsとかと被るので変えておきます。
個人的にNuxt.js(Vue.js)を5000にしているので、7000に変更。

package.json

  "scripts": {
-    "dev": "next dev",
+    "dev": "next dev -p 7000",

動作確認

% npm run dev
% open http://localhost:7000

今回のコミット内容

Initial commit from Create Next App
Material UIインストール、トップページ実装

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です