今Reactで新規PJを作るなら 2022
 mrskiro
mrskiroバンドラー:Vite
理由:速いは正義 全ての効率を向上させてくれる
 mrskiro
mrskiroTypeScriptは大前提
 mrskiro
mrskiroスタイリング候補
- styled-component
- linaria
- emotion
 mrskiro
mrskiro一旦linariaで試す
時間があったらCSS in JSは一通り試したい
そしてStyledXに期待
 mrskiro
mrskirotree -I "node_modules|dist"
.
├── index.html
├── package.json
├── public
│   └── favicon.svg
├── src
│   ├── App.tsx
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── yarn.lock
2 directories, 10 files
 mrskiro
mrskiroとりあえずlint
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier",
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: "latest",
    sourceType: "module",
  },
  plugins: ["react", "@typescript-eslint"],
  rules: {},
  settings: {
    react: {
      version: "detect",
    },
  },
}
 mrskiro
mrskiroReact18でこれを指定しないとwarningがでた
Warning: React version not specified in eslint-plugin-react settings. See https://github.com/yannickcr/eslint-plugin-react#configuration .
settings: {
    react: {
      version: "detect",
    },
  },
 mrskiro
mrskiro現時点のpackage.json
{
  "name": "react-template",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "format": "prettier --write ./src/**/*.{ts,tsx}",
    "lint": "eslint --ext ts,tsx .",
    "lint:fix": "yarn lint --fix"
  },
  "dependencies": {
    "react": "18.0.0",
    "react-dom": "18.0.0"
  },
  "devDependencies": {
    "@types/react": "18.0.0",
    "@types/react-dom": "18.0.0",
    "@typescript-eslint/eslint-plugin": "5.20.0",
    "@typescript-eslint/parser": "5.20.0",
    "@vitejs/plugin-react": "1.3.0",
    "eslint": "8.14.0",
    "eslint-config-prettier": "8.5.0",
    "eslint-plugin-react": "7.29.4",
    "eslint-plugin-react-hooks": "4.4.0",
    "prettier": "2.6.2",
    "typescript": "4.6.3",
    "vite": "2.9.5"
  }
}
 mrskiro
mrskiroルーティング: react-router-dom@v6
理由:デファクトスタンダードのため(破壊的変更を繰り返してるのが心配だけど...)
 mrskiro
mrskirotsconfigのpathを自動でマッピングしてくれるプラグイン
依存増やしたくないマンなのでとりあえず使わないけどPJが大きくなってaliasも複数貼るなら便利そう
 mrskiro
mrskiroこのレポジトリに随時pushしている
 mrskiro
mrskiro現時点のdir
.
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── index.html
├── package.json
├── public
│   └── favicon.svg
├── src
│   ├── App.tsx
│   ├── assets
│   │   └── .gitkeep
│   ├── components
│   │   └── Button
│   │       └── .gitkeep
│   ├── context
│   │   └── .gitkeep
│   ├── features
│   │   ├── objective
│   │   │   └── .gitkeep
│   │   └── user
│   │       └── .gitkeep
│   ├── hooks
│   │   └── .gitkeep
│   ├── lib
│   │   └── .gitkeep
│   ├── main.tsx
│   ├── pages
│   │   └── .gitkeep
│   ├── routes
│   │   ├── index.ts
│   │   └── routes.tsx
│   ├── utils
│   │   └── .gitkeep
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── yarn.lock
14 directories, 25 files
 mrskiro
mrskirolinaria、ドキュメントこれだけなのか...
(全部githubに飛ばされる)
 mrskiro
mrskirostylingはstyled-componentsを採用する
理由
- 候補だったlinariaはviteの正式サポートがなく不安が残る
- パフォーマンスは困ったときに対応したらいい
- styled-componentsはなんだかんだデファクトでありメンタルモデルが働く
 mrskiro
mrskiroセバスチャンさんがzero runtimeのCSSライブラリを推奨してる...
はやくStyledXを公開してくれ
 mrskiro
mrskirostylingはやっぱりvanilla-extractを採用する
.css.tsというファイルを強制してくるのがうーんだけど慣れるかもしれないという期待をしている
あとviteをサポートしているのが強い
参考にさせていただいた
 mrskiro
mrskiroReactは当然18
 mrskiro
mrskiroVitestを触ってみる
特に問題なければ採用するかも
 mrskiro
mrskirovanilla-extractと相性が悪い
rollupのプラグイン使ってbabelのプラグイン噛ませてもダメ
 FAIL  src/components/Spinner/spinner.test.tsx [ src/components/Spinner/spinner.test.tsx ]
Error: Styles were unable to be assigned to a file. This is generally caused by one of the following:
- You may have created styles outside of a '.css.ts' context
- You may have incorrect configuration. See https://vanilla-extract.style/documentation/setup
 mrskiro
mrskiroissueもいくつかあがってる
一旦vitestは様子見することにする
 mrskiro
mrskirobabel書いてやっとテストできるようになった
ここまできたらvanilla-extractやめてもいい気持ちになってきた
 mrskiro
mrskiroせっかくだしvitestを使いたい気持ちが拭えない
styled-componentならいけるのか試すことにする
 mrskiro
mrskirovanilaの供養
import { keyframes } from "@vanilla-extract/css"
import * as V from "@vanilla-extract/recipes"
const rotate = keyframes({
  "0%": { transform: "rotate(0deg)" },
  "100%": { transform: "rotate(360deg)" },
})
export const recipe = V.recipe({
  base: {
    borderStyle: "solid",
    borderRadius: "99999px",
    borderWidth: "2px",
    borderBottomColor: "transparent",
    borderLeftColor: "transparent",
    animation: `${rotate} 0.45s linear infinite`,
  },
  variants: {
    size: {
      sm: {
        width: "16px",
        height: "16px",
      },
      md: {
        width: "24px",
        height: "24px",
      },
    },
  },
  defaultVariants: {
    size: "md",
  },
})
export type Variants = V.RecipeVariants<typeof recipe>
 mrskiro
mrskiroふとRomeの存在を思い出した
 mrskiro
mrskirostyled-componentsのv6を試しに入れてみたらbuildできず
v5にする
✘ [ERROR] No matching export in "node_modules/tslib/tslib.es6.js" for import "__spreadArray"
    node_modules/styled-components/dist/styled-components.browser.esm.js:1:7:
      1 │ import{__spreadArray as e,__read as t,__values as n,__assign as o,__rest as r}from"tslib";import i ...
        ╵        ~~~~~~~~~~~~~
23:27:50 [vite] error while updating dependencies:
Error: Build failed with 1 error:
node_modules/styled-components/dist/styled-components.browser.esm.js:1:7: ERROR: No matching export in "node_modules/tslib/tslib.es6.js" for import "__spreadArray"
 mrskiro
mrskiroこれはstyled-componentsが依存してるtslibのバージョンが低いことが原因
 mrskiro
mrskirotesting系は以下を採用
- vitest
- testing-library
 mrskiro
mrskirostylingは結局styled-components
 mrskiro
mrskiro今日はここまで
残り
- api client
- storybook
- アプリケーション実装
 mrskiro
mrskiroいまからやる
Storybookの導入から
 mrskiro
mrskiroerrorboudaryつくる
 mrskiro
mrskiro18でも特に変わったことなし
ただsuspenseをたくさん活用したいので、ErrorBoundaryも複数箇所で使えるようにかいた
import * as React from "react"
type Props = {
  onError?: (err: unknown) => void
  fallback: (err: unknown) => React.ReactNode
  children: React.ReactNode
}
type State = {
  cause: unknown | null
}
export class ErrorBoundary extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props)
    this.state = {
      cause: null,
    }
  }
  static getDerivedStateFromError(cause: unknown) {
    return { cause }
  }
  componentDidCatch(error: unknown, _info: React.ErrorInfo) {
    if (!this.props.onError) return
    this.props.onError(error)
  }
  render() {
    const { cause } = this.state
    if (cause) {
      return this.props.fallback(cause)
    }
    return this.props.children
  }
}