Open11

ポートフォリオ作り: Pokemon app

mae616mae616

技術スタック

今回は

  • React, TypeScript, Vite
  • React Router
  • ゼロランタイムのCSS in JS(なんか熱いらしいので) Linaria
  • できれば Chart.js とか数値をグラフ化するのをしたい(好奇心)

追記、StyleLintの勉強会聞いて、面白そうだから規約バリバリにしてみる。(Storybookは今回はデザイン適当だから今度からにする)

  • Prettier
  • ESLint
  • StyleLint

CI / CD もやる

GitHub Actions

  • コードチェッカー
  • テスト
  • GitHub Pagesへデプロイ

お約束の

  • OGP設定
  • SEOは検索避ける(練習用のポートフォリオでGoogleのポリシーに違反するため)

使用API

PokeAPI v2
https://pokeapi.co/

作成ページ

  • ポケモン 一覧 ページネーション、検索(インクリメンタルサーチ)もつけたい(好奇心)
  • 1ポケモンの詳細画面

作成期間

予定: 2週間(4h * 4d = 16h)

mae616mae616

土台作り

プロジェクトの作成

参考: https://ja.vite.dev/guide/

$ npm create vite@latest pokemon-app -- --template react-ts
$ cd pokemon-app

React Routerのインストール

参考: https://reactrouter.com/en/main/start/tutorial

$ npm install react-router-dom

Linariaのインストール

参考: https://www.npmjs.com/package/linaria

$ npm i linaria

Chart.jsのインストール

参考: https://www.npmjs.com/package/chart.js?activeTab=readme

$ npm i chart.js
mae616mae616

Prettier + ESLint + StyleLint のインストールと設定

Prettierのインストール

https://prettier.io/docs/en/install
の通りにインストール

.prettierrc
{
  "trailingComma": "es5",
  "tabWidth": 4,
  "semi": false,
  "singleQuote": true
}

ESLintとの連携

ESLintはViteに初期から設定されている
https://github.com/prettier/eslint-config-prettier#installation
通りにインストールして、

eslint.config.js
// (importの最後)
+ import eslintConfigPrettier from "eslint-config-prettier";

export default tseslint.config(
    // (...略)
    {
        extends: [
          js.configs.recommended,
          ...tseslint.configs.recommended,
+           eslintConfigPrettier,
        ],
    // (...略)

を設定する。

StyleLintのインストールとPrettireとの連携

今回、ゼロランタイム CSS-in-JSの Linaria だから、
参考: https://stylelint.io/user-guide/get-started#linting-css-like-languages-and-css-within-containers, https://github.com/callstack/linaria/blob/master/docs/LINTING.md

npm install --save-dev stylelint @linaria/stylelint-config-standard-linaria stylelint-config-prettier
npm install --save-dev stylelint-processor-styled-components

touch .stylelintrc.json

でインストールして

.stylelintrc.json
{
  "extends": [
    "@linaria/stylelint-config-standard-linaria",
    "stylelint-config-prettier"
  ],
  "processors": ["stylelint-processor-styled-components"],
  "files": ["**/*.{js,jsx,ts,tsx}"]
}

で設定。

これやる(Editor Setup)
https://github.com/callstack/linaria/blob/master/docs/LINTING.md#editor-setup

scriptの設定

package.json
 // (...略)
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
+    "lint": "npm run eslint-check-fix && npm run stylelint-check",
    "preview": "vite preview",
+    "eslint-check-fix": "eslint . && prettier --write src/**/*.{ts,tsx}",
+    "stylelint-check": "stylelint-config-prettier-check '**/*.{js,jsx,ts,tsx}'"
  },
// (...略)

とりあえずこれで。ダメだったらまた後で考える。

参考

https://zenn.dev/kohski/articles/eslint-prettier-integration

脇道に逸れるけど知ったこと

VSCodeのNPMスクリプト ビュー


そんなことできたんだ...動画でやってて知った...
参考: https://www.youtube.com/watch?v=IrPz0kd2FTk

mae616mae616

Git hooks + デプロイ + CI / CD などGitHub Actionsの設定

Git hooks (lintをGitHubコミット時にも実行する)

https://prettier.io/docs/en/install#git-hooks
のインストールをして

package.json
    "scripts": {
        "dev": "vite",
        "build": "tsc -b && vite build",
        "lint": "npm run eslint-check-fix && npm run stylelint-check",
        "preview": "vite preview",
        "eslint-check-fix": "eslint . && prettier --write src/**/*.{ts,tsx}",
        "stylelint-check": "stylelint-config-prettier-check '**/*.{js,jsx,ts,tsx}'",
        "prepare": "husky"
    },
+    "lint-staged": {
+        "**/*": "npm run lint"
+    },

コミット時にlintが走ることを確認

GitHub Actionsを学ぶ

入会しているITコミュニティ(TechCommit)の
https://www.tech-commit.jp/main/event_archives/417
で学習。

メモ

https://docs.github.com/ja/actions

https://github.com/reviewdog/reviewdog

運用監視
https://sentry.io/welcome/

https://ja.mackerel.io/

mae616mae616

(続き)

一応これもみる
https://www.youtube.com/watch?v=15gn9FylOGw

GitHub Actionsの作成

とりあえず、サンプルから適当に作った

問題

review dogのエラー

ハマちゃった。レビュードッグのことをもっと知らないと無理そう。下記見る
https://youtu.be/v8cDXU60e54?si=1diAw21oZRTGQiev&t=1890

一応できたけど、時間がかかるのでまた考える。

Deploy失敗

Branch "main" is not allowed to deploy to github-pages due to environment protection rules.

これした。
https://github.com/orgs/community/discussions/39054#discussioncomment-6420042

デプロイはできたけど、真っ白のページ

何だっけ。前もあったな

これだったかな
https://stackoverflow.com/questions/74518887/blank-page-when-deploying-a-react-app-to-github-pages-and-vite

下記の修正

vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
+    base: './',
    plugins: [react()],
})

最終的なGitHub Actionsの内容

.github/workflows/reviewdog.yml
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: reviewdog

on:
  pull_request:
    branches: [ "dev" ]

jobs:
  reviewdog:

    runs-on: ubuntu-latest

    permissions:
      contents: read
      pull-requests: write
      
    strategy:
      matrix:
        node-version: [22.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - uses: actions/checkout@v4
    - name: misspell
      uses: reviewdog/action-misspell@v1
      with:
        github_token: ${{ secrets.github_token }}
        locale: "US"
    - uses: EPMatt/reviewdog-action-prettier@v1
      with:
        github_token: ${{ secrets.github_token }}
        # Change reviewdog reporter if you need
        # [github-pr-check,github-check,github-pr-review].
        # More about reviewdog reporters at
        # https://github.com/reviewdog/reviewdog#reporters
        reporter: github-pr-review
        # Change reporter level if you need
        # [info,warning,error].
        # More about reviewdog reporter level at
        # https://github.com/reviewdog/reviewdog#reporters
        level: warning
    - uses: reviewdog/action-eslint@v1
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        reporter: github-pr-review # Change reporter.
        eslint_flags: "src/"
    - name: stylelint
      uses: reviewdog/action-stylelint@v1
      with:
        reporter: github-pr-review # Change reporter.
        stylelint_input: '**/*.css'
    - uses: EPMatt/reviewdog-action-tsc@v1
      with:
        github_token: ${{ secrets.github_token }}
        # Change reviewdog reporter if you need
        # [github-pr-check,github-check,github-pr-review].
        # More about reviewdog reporters at
        # https://github.com/reviewdog/reviewdog#reporters
        reporter: github-pr-review
        # Change reporter level if you need
        # [info,warning,error].
        # More about reviewdog reporter level at
        # https://github.com/reviewdog/reviewdog#reporters
        level: warning
.github/workflows/test.yml
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Node.js CI Test

on:
  push:
    branches: [ "dev" ]
  pull_request:
    branches: [ "dev" ]

jobs:
  test:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [22.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - uses: actions/checkout@v4
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - run: npm ci
   # - run: npm test
.github/workflows/deploy-gh-pages.yml
# Simple workflow for deploying static content to GitHub Pages
name: Deploy react to GitHub Pages

on:
  # Runs on pushes targeting the default branch
  push:
    branches: ["main"]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
  contents: read
  pages: write
  id-token: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  # Single deploy job since we're just deploying
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Node
        uses: actions/setup-node@v4
        with:
          node-version: 22.6.0
          cache: "npm"
      - name: Install dependencies
        run: npm ci
      - name: Build
        run: npm run build      
      - name: Setup Pages
        uses: actions/configure-pages@v5
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          # Upload entire repository
          path: './dist'
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

デプロイページ

https://mae616.github.io/pokemon-app/

mae616mae616

各ライブラリの動作確認

あとでかく

Vite

$ npm run dev

http://localhost:5173/

OK

React Routerのコードの書き方確認

main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
+ import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import App from './App.tsx'
import './index.css'

+ const router = createBrowserRouter([
+     {
+         path: '/',
+         element: <App />,
+     },
+     {
+         path: 'poke',
+         element: <div>poke</div>,
+     },
+ ])

createRoot(document.getElementById('root')!).render(
    <StrictMode>
+        <RouterProvider router={router} />
-        <App />
    </StrictMode>
)

確認

Linariaのコードの書き方確認

あとで

Chart.jsのコードの書き方確認

あとで

mae616mae616

画面作成

ちょっと体調不良で時間が空いてしまったので、まずはリスケ
1週間遅れかな。

一覧画面 作成

なんかuseEffectを使わないfetchの仕方があるって最近見た気がする。これかな?

https://x.com/kazzyfrog/status/1847671184600814009

今インストールされてるバージョンは

npm list react-router-dom

すると6.27.0て出るから「React Router 6.4+」に該当するからそっちでできるっぽい。

参考: https://stackoverflow.com/questions/10972176/find-the-version-of-an-installed-npm-package参考: https://stackoverflow.com/questions/10972176/find-the-version-of-an-installed-npm-package

これかな?
https://reactrouter.com/en/main/route/loader

suspenseと組み合わせる、と。
https://ja.react.dev/reference/react/Suspense

UI コンポーネントのインストール

今回、デザインは適当だけど1から作るの面倒なのでChakra UIを使うことにする(ChatGPTに適当に出してもらって、有名どころから適当に決めた)

https://www.chakra-ui.com/docs/get-started/frameworks/vite

npm i @chakra-ui/react @emotion/react
npx @chakra-ui/cli snippet add
main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
+ import { Provider } from './components/ui/provider'
import App from './App.tsx'
import './index.css'

const router = createBrowserRouter([
    {
        path: '/',
        element: <App />,
    },
    {
        path: 'poke',
        element: <div>poke</div>,
    },
])

createRoot(document.getElementById('root')!).render(
    <StrictMode>
+        <Provider>
            <RouterProvider router={router} />
+        </Provider>
    </StrictMode>
)

一覧画面: とりあえず初期表示まで

utils.ts
async function fetchList() {
    return fetch('https://pokeapi.co/api/v2/pokemon')
}

export { fetchList }
main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { Provider } from './components/ui/provider'
import App from './App.tsx'
+ import { fetchList } from './utils'
import './index.css'

const router = createBrowserRouter([
    {
        path: '/',
+        loader: fetchList,
        element: <App />,
    },
    {
        path: 'poke',
        element: <div>poke</div>,
    },
])

createRoot(document.getElementById('root')!).render(
    <StrictMode>
        <Provider>
            <RouterProvider router={router} />
        </Provider>
    </StrictMode>
)
App.tsx
import { Suspense } from 'react'
import { useLoaderData } from 'react-router-dom'
import { Spinner, Flex, Card } from '@chakra-ui/react'
import './App.css'

function App() {
    const listData: any = useLoaderData()
    console.log(listData)

    return (
        <>
            <header>
                <h1>Pokemon app</h1>
            </header>
            <main>
                <Flex>
                    <Suspense fallback={<Spinner />}>
                        {listData.results.map((pokemon: any) => (
                            <Card.Root maxW="sm" overflow="hidden">
                                <Card.Body>
                                    <Card.Title>{pokemon.name}</Card.Title>
                                </Card.Body>
                            </Card.Root>
                        ))}
                    </Suspense>
                </Flex>
            </main>
        </>
    )
}

export default App


とりあえず今日はここまで٩( ᐛ )و

mae616mae616

2024/11/22 金 メモ

ちょっとLeetCodeで遊んでたら時間が空いた。

今日やること

ポートフォリオを作る数を減らすのでそれぞれの

  • なぜ作ったか、
  • どこまで作るのか
  • スケジュール

を考える

作るもの

  • Pokemon App
    • 基本のアプリでどこまで自分が作れるのかを表す
    • React 基礎のおさらい、React18のキャッチアップ
    • 品質として自分がどこまでを当たり前にできるのか(こだわっているのか)の探究
    • ゼロランタイム CSS in JS を使用してみる
    • グラフなど視覚的なインタラクティブアクションの勉強
    • 規約バリバリのライブラリを入れチーム開発を意識して、とりあえず体験してみる
    • GitHub Action CI/CDの体験、reviewDogの体験、dependBotの体験
    • なんちゃって1人スクラムの実施
    • 検索(インクリメンタルサーチ)を実装してみる体験

  • アンケートとアンケートの分析
    • 応募する事業に関係するポートフォリオ(自分はこの辺ができますってアピール)
    • Next.jsの基礎、Next.jsの最近のキャッチアップ
    • コンポーネント設計(自分の現状と課題を知るため)
    • 品質として自分がどこまでを当たり前にできるのか(こだわっているのか)の探究
    • TailWindCSS
    • AIなどでのアクションの勉強
    • 規約バリバリのライブラリを入れチーム開発を意識して、経験値を踏む
    • GitHub Action CI/CDの経験、reviewDogの経験
    • なんちゃって1人スクラムの実施
    • 認証、他認証
    • T3 Stack、postgres

参考: これみて面白そうだなと思ったので自分でも作ってみる、て動機
https://x.com/Selria1/status/1759612612567028034

  • LP
    • ペライチ
    • foriioのAPIを使う
    • あんまり拘らない

Udemyの下記の教材は全部やる(supabaseとかあるから)
https://www.udemy.com/course/react-product-development/

別途オンラインもくもく朝会でやってる、
https://www.udemy.com/course/the-complete-javascript-course/
とその次のReactのはオンラインもくもく朝会でそのままやって間に合う分だけポートフォリオに追加しておく

ポートフォリオはあまりみられないから丁寧に作って、自己分析や事業理解に力を入れる方針

mae616mae616

2024/12/02 月 一覧画面作り込み

メモ

  • Suspenseのchildren をasync のコンポーネントにできるってことだから、今回はreact-router-domのloaderでやるからSuspenseでなくてもいいのか?(もうちょっと作り込まないとよくわからないな)
    ↑ 勘違いっぽいasyncのコンポーネントできなかった

問題
fetch をローダでやると表示まで遅くて、Suspenseとfetchの組み合わせの仕方は自分は分かってない。明日、YouTubeとかみて勉強する