Open37

Vite + React(ts) + Eslint(standard) + Prettier + Stylelint + Emotion + Storybook + jest の開発環境構築

warugakiwarugaki

GOAL

  • 過去に作成した環境が古くなったのでアップデートをかねて構築しなおす
  • node v18 ではstorybook(vite)が起動できなくなったので、起動できるようにする

過去:Vite +TypeScript + React + Eslint(airbnb) + Prettier + Stylelint + Emotion + Storybook の開発環境構築

warugakiwarugaki

構築環境

  • MacBook Pro M1
  • Node18.12.0(fnm)
  • Vscode

※構築後はwindowsでも動作確認する

機能

  • Vite
  • typescript
  • Eslint
    • airbnb
  • Prettiter
  • Stylelint
  • storybook
  • vitest
warugakiwarugaki

.gitignoreを更新

vscode設定ファイルはgit 管理する

.gitignore 下記を削除

.vscode/*
!.vscode/extensions.json
warugakiwarugaki

Nodeのバージョン固定と自動切り替え

package.jsonに追加

"engines": {
  "node": "18.12.0",
  "npm": "8.19.2"
}

.npmrcをルートに追加

engine-strict=true

nodeのバージョンが違う場合は、警告がでるようになる

.node-version.nvmrc をルートに追加

node -v > .node-version
node -v > .nvmrc

package-lock.json(engines) 更新

npm i
warugakiwarugaki

Eslintを導入

インストール

npm i -D eslint
npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser, node
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · standard
✔ What format do you want your config file to be in? · JavaScript

warugakiwarugaki

airbnbの設定内容

コンソール上で選択

✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser, node
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · airbnb
✔ What format do you want your config file to be in? · JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
Local ESLint installation not found.
The config that you've selected requires the following dependencies:

eslint-plugin-react@^7.28.0 @typescript-eslint/eslint-plugin@latest eslint-config-airbnb@latest eslint@^7.32.0 || ^8.2.0 eslint-plugin-import@^2.25.3 eslint-plugin-jsx-a11y@^6.5.1 eslint-plugin-react-hooks@^4.3.0 @typescript-eslint/parser@latest
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm

Eslint の拡張

  • AirbnbのESLintコンフィグをTypeScriptに対応させて強化する

https://github.com/iamturns/eslint-config-airbnb-typescript

  • eslintrc.cjs の更新(ルールの拡張)
    • React17からJSXを使う際にReactをインポート不要になったため無効化(rulesに追加)

      'react/react-in-jsx-scope': 'off',
      
    • devDependenciesのimportを許可(rulesに追加)

      'import/no-extraneous-dependencies': 'off',
      
    • コンポーネントはアロー関数で統一(rulesに追加)

      'react/function-component-definition': [
        'error',
        {
          namedComponents: 'arrow-function', // 'function-declaration' | 'function-expression' | 'arrow-function'
          unnamedComponents: 'arrow-function' // 'function-declaration' | 'function-expression' | 'arrow-function'
        }
      ],
      
  • eslintrc.cjs の更新(parserOptions の project に 「./tsconfig.json」を指定)
"include": ["src",".eslintrc.cjs","vite.config.ts"],
  • tsconfig.jsonの更新(Parsing error: "parserOptions.project")エラー解消のため
"include": ["src",".eslintrc.cjs","vite.config.ts"],

Eslintの見直しをして最終の設定ファイルをはっておく

{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "extends": [
    "airbnb",
    "airbnb/hooks",
    "airbnb-typescript",
    "plugin:react/recommended",
    "plugin:storybook/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "prettier"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json",
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": ["react", "react-hooks", "@typescript-eslint", "testing-library", "jest-dom"],
  "settings": {
    "import/extensions": [".js", ".jsx", ".ts", ".tsx"],
    "import/resolver": {
      "typescript": {
        "directory": "./tsconfig.json"
      },
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    }
  },
  "rules": {
    //関数や変数が定義される前に使われているとエラーになるデフォルトの機能をoff
    "no-use-before-define": "off",
    // 一貫した型定義
    "@typescript-eslint/consistent-type-definitions": ["error", "interface"], // or type
    // 一貫した型のインポート
    "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }],
    // 明示的な関数の戻り値の型
    "@typescript-eslint/explicit-function-return-type": "error",
    //typescript側のno-use-before-defineを使うようにする
    "@typescript-eslint/no-use-before-define": ["error"],
    //TypeScriptでチェックしているから不要
    "react/prop-types": "off",
    "react/require-default-props": "off",
    "react/no-unknown-property": ["error", { "ignore": ["css"] }],
    "react/react-in-jsx-scope": "off",
    "react/function-component-definition": [
      "error",
      {
        "namedComponents": "arrow-function",
        "unnamedComponents": "arrow-function"
      }
    ],
    //jsx形式のファイル拡張子をjsxもしくはtsxに限定
    "react/jsx-filename-extension": [
      "error",
      {
        "extensions": [".jsx", ".tsx"]
      }
    ],
    //named exportがエラーになるので使えるようにoff
    "import/prefer-default-export": "off",
    "import/no-extraneous-dependencies": [
      "error",
      {
        "devDependencies": [
          "vite.config.ts",
          ".storybook/**/*.{cjs,jsx,tsx}",
          "src/setupTest.ts",
          "src/stories/**/*.stories.{ts,tsx}",
          "src/**/*.test.{ts,tsx}"
        ]
      }
    ],
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "js": "never",
        "jsx": "never",
        "ts": "never",
        "tsx": "never"
      }
    ],
    // importの自動整列
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "parent", "sibling", "index", "object", "type"],
        "pathGroups": [
          {
            "pattern": "{react,react-dom/**,react-router-dom}",
            "group": "builtin",
            "position": "before"
          },
          {
            "pattern": "@src/**",
            "group": "parent",
            "position": "before"
          }
        ],
        "pathGroupsExcludedImportTypes": ["builtin"],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ]
  },
  "overrides": [
    {
      "files": ["**/tests/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"],
      "extends": ["plugin:jest-dom/recommended", "plugin:testing-library/react"]
    }
  ]
}

warugakiwarugaki

eslintrc.cjsの中身

追記:eslintの見直しをした

eslintrc.cjs
module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'plugin:react/recommended',
    'plugin:jsx-a11y/strict',
    'plugin:react-hooks/recommended',
    'plugin:storybook/recommended',
    'standard-with-typescript',
    'prettier',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: './tsconfig.json',
  },
  plugins: ['react', 'react-hooks', '@typescript-eslint', 'testing-library', 'jest-dom', 'import'],
  rules: {
    '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
    'react/require-default-props': 'off',
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'warn',
    'react/no-unknown-property': [
      'error',
      {
        ignore: ['css'],
      },
    ],
    'react/react-in-jsx-scope': 'off',
    'react/function-component-definition': [
      'error',
      {
        namedComponents: 'arrow-function',
        // 'function-declaration' | 'function-expression' | 'arrow-function'
        unnamedComponents: 'arrow-function', // 'function-declaration' | 'function-expression' | 'arrow-function'
      },
    ],
    'import/no-extraneous-dependencies': 'off',
    // importの自動整列
    'import/order': [
      'error',
      {
        groups: ['builtin', 'external', 'parent', 'sibling', 'index', 'object', 'type'],
        pathGroups: [
          {
            pattern: '{react,react-dom/**,react-router-dom}',
            group: 'builtin',
            position: 'before',
          },
          {
            pattern: '@src/**',
            group: 'parent',
            position: 'before',
          },
        ],
        pathGroupsExcludedImportTypes: ['builtin'],
        alphabetize: {
          order: 'asc',
        },
        'newlines-between': 'always',
      },
    ],
  },
  overrides: [
    {
      files: ['**/tests/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
      extends: ['plugin:jest-dom/recommended', 'plugin:testing-library/react'],
    },
  ],
  settings: {
    react: {
      version: 'detect',
    },
  },
}


warugakiwarugaki

tsconfig.jsonの中身

{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src",".eslintrc.cjs","vite.config.ts"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

warugakiwarugaki

npm scriptsの追加

eslint 構文チェックと自動修正ができるように

{
 "scripts": {
・・・中略・・・
   "lint:eslint": "eslint --ignore-path .gitignore .  --ext .js,.jsx,.ts,.tsx,cjs",
   "lintfix:eslint": "npm run lint:eslint -- --fix",
 },
}
warugakiwarugaki

Eslintのlintエラー修正

自動修正

npm run lintfix:eslint

手動修正

warugakiwarugaki

Prettierの導入

1. インストール

npm i -D prettier eslint-config-prettier

2. Prettierの設定ファイルを作成

プロジェクトのルートに.prettierrc を作成

{
  "printWidth": 120,
  "singleQuote": true,
  "trailingComma": "all"
}

semi や カンマを無効にしたい場合の設定

{
  "printWidth": 120,
  "semi": false,
  "singleQuote": true,
  "trailingComma": "none"
}

3.eslintとprettierの競合ルールをoffに

.eslintrc.cjs に追加(prettierは必ず最後に追加する)

extends: [
・・・中略・・・
  "prettier"
],

4. npm scriptsの追加

"format:check": "prettier --check --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,cjs,json,css}'",
"format:fix": "prettier --write --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,cjs,json,css}'"
warugakiwarugaki

emotionの導入

1.インストール

npm i @emotion/react

2.Emotionの自動インポート(JSXプラズマを自動挿入)

tsconfig.json の compilerOptionsに追加

"compilerOptions": {
    ・・・中略・・・
    "jsxImportSource": "@emotion/react",

vite.config.tsが、tsconfig.json の jsxImportSource を参照できるように

plugins: [
  react({
    jsxImportSource: '@emotion/react',
  }),
]

3. eslintのルール追加|css props は許容する

https://emotion.sh/docs/eslint-plugin-react

'react/no-unknown-property': ['error', { ignore: ['css'] }]

4.vscodeの推奨拡張機能を追加

vscode-styled-components - Visual Studio Marketplace

5. 既存スタイルをemotion使ってcss-in-js仕様にする

グローバルスタイルの実装

Global Styles

1.src/styles/globalStyle.tsxファイルを作成してindex.cssを移植

import { css } from '@emotion/react'

const globalStyle = css`
  :root {
    font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
    font-size: 16px;
    line-height: 24px;
    font-weight: 400;

    color-scheme: light dark;
    color: rgba(255, 255, 255, 0.87);
    background-color: #242424;

    font-synthesis: none;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-text-size-adjust: 100%;
  }

  a {
    font-weight: 500;
    color: #646cff;
    text-decoration: inherit;
  }
  a:hover {
    color: #535bf2;
  }

  body {
    margin: 0;
    display: flex;
    place-items: center;
    min-width: 320px;
    min-height: 100vh;
  }

  h1 {
    font-size: 3.2em;
    line-height: 1.1;
  }

  button {
    border-radius: 8px;
    border: 1px solid transparent;
    padding: 0.6em 1.2em;
    font-size: 1em;
    font-weight: 500;
    font-family: inherit;
    background-color: #1a1a1a;
    cursor: pointer;
    transition: border-color 0.25s;
  }
  button:hover {
    border-color: #646cff;
  }
  button:focus,
  button:focus-visible {
    outline: 4px auto -webkit-focus-ring-color;
  }

  @media (prefers-color-scheme: light) {
    :root {
      color: #213547;
      background-color: #ffffff;
    }
    a:hover {
      color: #747bff;
    }
    button {
      background-color: #f9f9f9;
    }
  }
`

export default globalStyle

2.main.tsxにglobalスタイルをインポート

import React from 'react'
import { Global } from '@emotion/react'
import ReactDOM from 'react-dom/client'
import App from './App'

import globalStyle from './styles/globalStyle'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <Global styles={globalStyle} />
    <App />
  </React.StrictMode>
)

src/App.css はコンポートスタイルに

  1. import { css } from '@emotion/react'

  2. const styleApp = css`` にまるっとコピー(#rootは&に書き換え)

  3. styleApp をcssprops でスタイルを定義

    <div className="App" css={styleApp}>
    

完成

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import { css } from '@emotion/react'

const styleApp = css`
  & {
    max-width: 1280px;
    margin: 0 auto;
    padding: 2rem;
    text-align: center;
  }

  .logo {
    height: 6em;
    padding: 1.5em;
    will-change: filter;
  }
  .logo:hover {
    filter: drop-shadow(0 0 2em #646cffaa);
  }
  .logo.react:hover {
    filter: drop-shadow(0 0 2em #61dafbaa);
  }

  @keyframes logo-spin {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    a:nth-of-type(2) .logo {
      animation: logo-spin infinite 20s linear;
    }
  }

  .card {
    padding: 2em;
  }
  .read-the-docs {
    color: #888;
  }
`

const App = (): JSX.Element => {
  const [count, setCount] = useState(0)

  return (
    <div className="App" css={styleApp}>
      <div>
        <a href="https://vitejs.dev" target="_blank" rel="noreferrer">
          <img src="/vite.svg" className="logo" alt="Vite logo" />
        </a>
        <a href="https://reactjs.org" target="_blank" rel="noreferrer">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>count is {count}</button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">Click on the Vite and React logos to learn more</p>
    </div>
  )
}

export default App

ユニークなクラス名が付与され、コンポート別にスタイルを閉じ込めることができる

6. 不要になったcssファイルを削除しておく

warugakiwarugaki

Stylelintの導入

インストール

npm i -D stylelint stylelint-config-recess-order stylelint-config-standard postcss-syntax @stylelint/postcss-css-in-js stylelint-config-prettier

設定ファイルの作成とルールを拡張

プロジェクトルートに.stylelintrcを作成して以下を追加

{
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-recess-order",
    "stylelint-config-prettier"
  ],
  "rules": {},
  "overrides": [
    {
      "files": [
        "**/*.jsx",
        "**/*.tsx"
      ],
      "rules": {
      },
      "customSyntax": "@stylelint/postcss-css-in-js"
    }
  ]
}

npm scriptsを追加

"lint:stylelint": "stylelint ./src/**/*.{css,jsx,tsx}",
"lintfix:stylelint": "stylelint --fix ./src/**/*.{css,jsx,tsx}",
warugakiwarugaki

storybook(for vite)の導入

npx sb@next init --builder=vite

✔ Do you want to run the 'eslintPlugin' migration on your project? … yes
✔ Do you want to run the 'npm7' migration on your project? … no
✔ Do you want to run the 'mdx1to2' migration on your project? … yes

起動!! docsが別タブではなくなっている・・・w

導入したeslintのルール順を変更

prettierより前にしておく

.eslintrc.cjs

js
extends: [
・・・中略
+  'plugin:storybook/recommended',
  'prettier'
],
Hidden comment
Hidden comment
warugakiwarugaki

動作確認のため src/stories/App.stories.tsx を作成する

コード

import type { Meta, StoryObj } from '@storybook/react'

import App from '../App'

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
const meta: Meta<typeof App> = {
  title: 'App',
  component: App,
  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/react/writing-docs/docs-page
  tags: ['docsPage'],
  // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
  argTypes: {}
}

export default meta
type Story = StoryObj<typeof App>

// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
export const Default: Story = {
  // More on args: https://storybook.js.org/docs/react/writing-stories/args
  args: {}
}

動いた!storybookv7はいろいろ書き方変わっている?

http://localhost:6006/?path=/docs/app--docs

warugakiwarugaki

stylelintのルール拡張

no-empty-first-line lintエラー解消のため
ルールoffでもよかったがprettierの競合ルール無効化でいいかとおもったので・・この設定にした

npm i -D stylelint-config-prettier
.stylelintrc
{
  "extends": [
    // other configs ...
    "stylelint-config-prettier"
  ]
}

https://github.com/prettier/stylelint-config-prettier

warugakiwarugaki

Vitestの導入

https://vitest.dev/

guideを参考に設定する
https://vitest.dev/guide/

Vitest 例
https://vitest.dev/guide/#examples

インストール

npm install -D vitest

npm scriptsにtestコマンドを追加

{
  "scripts": {
    "test": "vitest",
    "coverage": "vitest run --coverage"
  }
}

vscodeの拡張機能も入れておく
https://marketplace.visualstudio.com/items?itemName=ZixuanChen.vitest-explorer

testing-library をインストールする

npm install --D @testing-library/react jsdom @testing-library/user-event @testing-library/jest-dom 

テストファイルのimportの省略できるように

https://markus.oberlehner.net/blog/using-testing-library-jest-dom-with-vitest/

上記を参考にsrc/setupTest.ts」を作成する

import matchers from '@testing-library/jest-dom/matchers';
import { expect } from 'vitest';

expect.extend(matchers);

vite.config.tsも更新

/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference types="vitest" />
/// <reference types="vite/client" />

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react({
      jsxImportSource: '@emotion/react'
    })
  ],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/setupTest.ts']
  }
})
warugakiwarugaki

App.test.tsx の作成

src/tests/App.test.tsx を作成

import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../App'

test('should first', async () => {
  // 描画
  render(<App />)

  let button = screen.getByRole('button', { name: /count is/i }) 
  expect(button).toHaveTextContent('count is 0') 

  const user = userEvent.setup()
  await user.click(button)
  button = await screen.findByRole('button', { name: /count is \d/ })
  expect(button).toHaveTextContent('count is 1')
})

warugakiwarugaki

test実行

npm run test

✓ src/tests/App.test.tsx (1)

Test Files 1 passed (1)
Tests 1 passed (1)
Start at 19:18:44
Duration 849ms (transform 276ms, setup 50ms, collect 208ms, tests 65ms)

warugakiwarugaki

coverageの実行

npm run coverage

starter-vite-react-ts@0.0.0 coverage
vitest run --coverage

✓ src/tests/App.test.tsx (1)

Test Files 1 passed (1)
Tests 1 passed (1)
Start at 18:48:07
Duration 1.68s (transform 358ms, setup 153ms, collect 273ms, tests 100ms)

% Coverage report from c8
--------------|---------|----------|---------|---------|-------------------

File % Stmts % Branch % Funcs % Lines Uncovered Line #s
All files 100 100 100 100
App.tsx 100 100 100 100
setupTest.ts 100 100 100 100
-------------- --------- ---------- --------- --------- -------------------
warugakiwarugaki

eslintの設定追加

npm i -D eslint-plugin-testing-library eslint-plugin-jest-dom

eslint の設定ファイルを更新

追加

plugins: ['react', 'react-hooks', '@typescript-eslint', 'testing-library', 'jest-dom'],

上書き

testファイルのみ

  overrides: [
    {
      files: ['**/tests/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
      extends: ['plugin:jest-dom/recommended', 'plugin:testing-library/react']
    }
  ],
warugakiwarugaki

path エイリアスの設定

npm i -D vite-tsconfig-paths

vite.config.ts

export default defineConfig({
  plugins: [
    react({
      jsxImportSource: '@emotion/react'
    }),
+    tsconfigPaths()
  ],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/setupTest.ts']
  }
})

tsconfig.json にパスエイリアスの設定を追加

    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }

vscodeでもパス補完できるように

拡張機能のインストール
https://marketplace.visualstudio.com/items?itemName=ionutvmi.path-autocomplete

  "path-autocomplete.pathMappings": {
    "@": "${folder}/src"
  },
  "path-autocomplete.extensionOnImport": true

「extensionOnImport」は拡張子を入力するのがめんどくさい方向けw
なくてもいい

warugakiwarugaki

検証ビルド|storybook

npm run build-storybook

結果

エラ〜なし

プレビュー

エラ〜なし

npx http-server ./storybook-static
warugakiwarugaki

nodeのデフォルトモジュールで型の補完がきくようにする

やること

npm i -D  @types/node
warugakiwarugaki

Vite v4 がリリースされたのアップデートする

やること

  • そのほか、パッケージも併せてやっておく
  • ビルドを高速できるようにvite pluginを変更する
    • 「@vitejs/plugin-react」 →「@vitejs/plugin-react-swc」
  • 使用されていないパッケージの整理

参考記事

https://qiita.com/sugurutakahashi12345/items/df736ddaf65c244e1b4f

npm outdated
https://docs.npmjs.com/cli/outdated

npm-check-updates
https://github.com/tjunnone/npm-check-updates
オプション一覧:https://github.com/tjunnone/npm-check-updates#options

やったこと

更新するパッケージの確認

npx npm-check-updates

アップデート

npx npm-check-updates -u

以下を削除して、再インストール

  • node_modules
  • package-lock.json
npm i

storybookv7 もベータ版になっていたので手動アップデート

起動確認

OK!

storybook

OK!

vite-plugin-react-swcの設定

Vercel社が作っている。Babelの代替えとなるコンパイラーだそうですw

SWC is 20x faster than Babel on a single thread and 70x faster on four cores.

公式を参考に設定する
https://github.com/vitejs/vite-plugin-react-swc

起動も早くなったw

前より、半分の時間になった・・・
VITE v4.0.1 ready in 122 ms

warugakiwarugaki

GlobalStyle にリセットcssを追加する

src/styles/GlobalStyle.tsx
import { css } from '@emotion/react';
+ // https://github.com/csstools/sanitize.css#install
+ import 'sanitize.css';
+ import 'sanitize.css/forms.css';

const GlobalStyle = css`
///省略
`;
export default GlobalStyle;
warugakiwarugaki

GlobalStyle のベーススタイルを定義しなおす

以下のようにした

import { css } from '@emotion/react';

// reset css
// https://github.com/csstools/sanitize.css#install
import 'sanitize.css';
import 'sanitize.css/forms.css';

const globalStyle = css`
  @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@300;400;500;700;900&family=Roboto:wght@400;700&display=swap');

  :root {
    --font-color-base: #090a0a;
    --font-family-base: Inter, Avenir, 'Helvetica Neue', Helvetica, Arial, sans-serif;
    --font-size-base: 16px;
    --font-weight-base: 400;
    --line-height-base: 1.5;
    --bg-color-base: #fcfcfc;
  }

  [lang='ja'] {
    --font-family-base: 'Roboto', 'Noto Sans JP', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  }

  body {
    font-family: var(--font-family-base);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-base);
    line-height: var(--line-height-base);
    color: var(--font-color-base);
    background-color: var(--bg-color-base);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
`;

export default globalStyle;