Closed35

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

warugakiwarugaki

.editorconfigを追加

editorconfig
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
warugakiwarugaki

Eslintの導入|パッケージのインストール

npm i -D eslint
npx eslint --init

対話式で選択

npx eslint --init
✔ 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
The config that you've selected requires the following dependencies:

eslint-plugin-react@^7.27.1 @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 with npm? · No / Yes
Installing eslint-plugin-react@^7.27.1, @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

AirbnbのESLintコンフィグをTypeScriptに対応させて強化する
https://github.com/iamturns/eslint-config-airbnb-typescript

npm i -D eslint-config-airbnb-typescript
warugakiwarugaki

Eslintの導入|設定

自動生成された .eslintrc.jsに以下を追加

.eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'airbnb',
+   'airbnb-typescript',
+   'airbnb/hooks',
+   'plugin:@typescript-eslint/recommended',
+   'plugin:@typescript-eslint/recommended-requiring-type-checking',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 13,
    sourceType: 'module',
    project: './tsconfig.json'
  },
  plugins: [
    'react',
    '@typescript-eslint',
  ],
  rules: {
  },
};
warugakiwarugaki

Eslintの導入|動作検証

npx eslint . --ext .js,.jsx,.ts,.tsx
  0:0  error  Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: .eslintrc.js.
The file must be included in at least one of the projects provided
 0:0  error  Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: vite.config.ts.
The file must be included in at least one of the projects provided
warugakiwarugaki

Eslintの導入|設定

Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser. の解消

tsconfig.json に 以下を追加

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

Eslintの導入|動作検証

npx eslint . --ext .js,.jsx,.ts,.tsx

以下のeslint errorがでるようになる

.eslintrc.js
21:31  error  Missing trailing comma  @typescript-eslint/comma-dangle
vite.config.ts
  1:1   error  'vite' should be listed in the project's dependencies, not devDependencies                  import/no-extraneous-dependencies
  1:36  error  Missing semicolon                                                                           @typescript-eslint/semi
  2:1   error  '@vitejs/plugin-react' should be listed in the project's dependencies, not devDependencies  import/no-extraneous-dependencies
  2:41  error  Missing semicolon                                                                           @typescript-eslint/semi
  6:21  error  Missing trailing comma                                                                      @typescript-eslint/comma-dangle
  7:3   error  Missing semicolon                                                                           @typescript-eslint/semi
warugakiwarugaki

Eslintの導入|npm scriptsの追加

package.json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "serve": "vite preview",
+   "lint:eslint": "eslint --ignore-path .gitignore .  --ext .js,.jsx,.ts,.tsx",
+   "fix:eslint": "eslint --fix --ignore-path .gitignore . --ext .js,.jsx,.ts,.tsx"
  },
}
warugakiwarugaki

Eslintの導入|ルールのカスタマイズ

react/react-in-jsx-scopeをoffにする 
React v17からは以下のインポートが不要になったため

import React from "react";

ルールの追加

./.eslinttrc.js
  rules: {
    'react/react-in-jsx-scope': 'off',
  },

コンポーネントはアロー関数で書く様に、ルールの追加

./.eslinttrc.js
  rules: {
    'react/function-component-definition': [
      'error',
      {
        namedComponents: 'arrow-function', // 'function-declaration' | 'function-expression' | 'arrow-function'
      },
    ],
  },

vite.config.tsの以下のエラーをoffにする

1:1   error  'vite' should be listed in the project's dependencies, not devDependencies                  import/no-extraneous-dependencies

2:1   error  '@vitejs/plugin-react' should be listed in the project's dependencies, not devDependencies  import/no-extraneous-dependencies

ルールの追加

./.eslinttrc.js
+ overrides: [
+   {
+     files: ['**/vite.config.ts'],
+     rules: {
+       'import/no-extraneous-dependencies': 'off',
・・・省略
+     },
+   },
+ ],
warugakiwarugaki

Eslintの導入|Eslintのerror修正

自動修正

npm run fix:eslint

手動修正

エラー内容

14:58  error  'count' is already declared in the upper scope  @typescript-eslint/no-shadow
App.tsx
-<button type="button" onClick={() => setCount((count) => count + 1)}>
+<button type="button" onClick={() => setCount(count + 1)}>
warugakiwarugaki

Eslintの導入|import/order rules setting

importの順番ルールを追加

公式を参考に独自ルールを追加
https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md

./.eslintrc.js
  plugins: [
    'react',
    '@typescript-eslint',
+   'import',
  ],
./.eslintrc.js
  overrides: [
    {
      files: ['**/vite.config.js'],
      rules: {
        'import/no-extraneous-dependencies': 'off',
      },
    },
+   {
+     // import/order rules setting
+     files: ['src/**/*.{js,jsx,ts,tsx}'],
+     rules: {
+       'import/order': [
+         'error',
+         {
+           groups: [
+             'builtin',
+             'external',
+             'parent',
+             'sibling',
+             'index',
+             'object',
+             'type',
+           ],
+           alphabetize: {
+             order: 'asc',
+           },
+           'newlines-between': 'always',
+         },
+       ],
+     },
+   },
  ],

warugakiwarugaki

Eslintの導入|eslint-plugin-unused-imports

未使用のインポートを検知できるように

パッケージのインストール

npm i -D eslint-plugin-unused-imports

公式通りにルール追加
https://github.com/sweepline/eslint-plugin-unused-imports

./.eslintrc.js
  plugins: [
    'react',
    '@typescript-eslint',
    'import',
+  'unused-imports',
  ],
./.eslintrc.js
rules: {
  'react/react-in-jsx-scope': 'off',
  'react/function-component-definition': [
    'error',
    {
      namedComponents: 'arrow-function', // 'function-declaration' | 'function-expression' | 'arrow-function'
    },
  ],
+ '@typescript-eslint/no-unused-vars': 'off',
+ 'unused-imports/no-unused-imports': 'error',
+ 'unused-imports/no-unused-vars': [
+   'warn',
+   {
+     vars: 'all',
+     varsIgnorePattern: '^_',
+     args: 'after-used',
+     argsIgnorePattern: '^_',
+   },
+ ],
},
warugakiwarugaki

Emotionの導入|css-in-js

必要パッケージをインストール

npm i @emotion/react
npm i -D @emotion/babel-plugin
warugakiwarugaki

Emotionの導入|Babelの設定

vite.config.js にBabelの設定を追加

./vite.config.ts
- plugins: [react()],
+ plugins: [
+   react({
+     jsxImportSource: '@emotion/react',
+     babel: {
+       plugins: ['@emotion/babel-plugin'],
+     },
+   }),
+ ],
warugakiwarugaki

Emotionの導入|DEMOコード

DEMOコード
./src/Demo.tsx
import { css } from '@emotion/react';

const style = css`
  & {
    color: #333;
  }

  p {
    font-size: 14px;
  }

  &.large p {
    font-size: 28px;
  }

  @media (min-width: 1024px) {
    p {
      font-size: 28px;
      color: #aaa;
      transition: opacity 0.3s ease-out;
    }

    p:hover {
      opacity: 0.5;
    }

    &.large p {
      font-size: 56px;
    }
  }
`;

type Props = {
  large: boolean;
};

const Demo: React.VFC<Props> = ({ large }: Props) => (
  <div className={`demo ${large ? 'large' : ''}`.trim()} css={style}>
    <p>Demo</p>
  </div>
);

export default Demo;
warugakiwarugaki

Emotionの導入|VSCodeの設定

拡張機能のインストール

tsxでemmet(css)が実行できるようになる
https://marketplace.visualstudio.com/items?itemName=jpoissonnier.vscode-styled-components

追記:上記リンク切れになっていたので
https://marketplace.visualstudio.com/items?itemName=styled-components.vscode-styled-components

エディタ上でcss propsの警告がでないように

./tsconfig.json
{
  "compilerOptions": {
・・・省略
    "jsxImportSource": "@emotion/react"
  }
}
warugakiwarugaki

Stylelintの導入|パッケージのインストール

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

Stylelintの導入|ルール設定

.stylelintrcを作成して以下を追加

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

Stylelintの導入|npm scriptsを追加

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

Stylelintの導入|vscodeの設定

エディタ上でもstylelintが実行できるように

setteing.json記述内容
./.vscode/setteing.json
{
  "editor.codeActionsOnSave": {
    "source.fixAll.stylelint": true
  },
  "css.validate": false,
  "stylelint.validate": ["css", "postcss", "javascriptreact", "typescriptreact"]
}
warugakiwarugaki

Prettierの導入|インストール

npm i -D prettier eslint-config-prettier stylelint-config-prettier
warugakiwarugaki

Prettierの導入|ルールの追加

.prettierrc
{
  "singleQuote": true,
  "trailingComma": "all"
}

warugakiwarugaki

Prettierの導入|npm scriptsの追加

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

Prettierの導入|競合ルールの無効化

.eslintrc.js
extends: [
・・・省略
    'prettier',
  ],
・・・省略
.stylelintrc
  "extends": [
・・・省略
    "stylelint-config-prettier"
  ],
warugakiwarugaki

VSCodeの設定|ファイル保存の自動フォーマット

./.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.formatOnPaste": false,
  "editor.formatOnType": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll.stylelint": true
  },
  "css.validate": false,
  "stylelint.validate": ["css", "javascriptreact", "typescriptreact"]
}
warugakiwarugaki

VSCodeの設定|推奨拡張機能

{
  "recommendations": [
    "editorconfig.editorconfig",
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "stylelint.vscode-stylelint",
    "jpoissonnier.vscode-styled-components"
  ]
}
warugakiwarugaki

Storybookの導入|storybookのeslintの導入

npx sb@next automigrate

eslintのルールをoff


overrides: [
///省略
    {
      files: ['**/*.stories.*'],
      rules: {
        'react/jsx-props-no-spreading': 'off',
      },
    },
  ],
warugakiwarugaki

Storybookの導入|storybookのbabel設定を追加

この設定をしないとemotionがエラーで動作しない

.storybook/.babelrc
{
  "presets": [
    [
      "@babel/preset-react",
      { "runtime": "automatic", "importSource": "@emotion/react" }
    ]
  ],
  "plugins": ["@emotion/babel-plugin"]
}

追記:上記だと Introduction.stories.mdx(storybook)が表示されなくなるので下記のように設定変更が必要

Introduction.stories.mdx が不要の場合は上記でいける

参照
https://github.com/storybookjs/storybook/issues/7540

公式では@emotion/babel-pluginを推奨しているが・・

  1. storybook/.babelrc を削除

  2. .storybook/main.js にbabelの設定を追加

.storybook/main.js
  babel: async (options) => ({
    ...options,
    presets: [...options.presets, '@emotion/babel-preset-css-prop'],
  }),
warugakiwarugaki

最終確認

開発環境するか

npm run dev

ビルドできるか

npm run build

おっとこけたw

s an 'any' type.
  Try `npm i --save-dev @types/babel__core` if it exists or add a new declaration (.d.ts) file containing `declare module '@babel/core';`

1 import type { ParserOptions } from '@babel/core';
s an 'any' type.
  Try `npm i --save-dev @types/babel__core` if it exists or add a new declaration (.d.ts) file containing `declare module '@babel/core';`

3 import type { TransformOptions } from '@babel/core';

以下の型定義がいるらしい

npm i --save-dev @types/babel__core

再ビルド!!今度は成功

ビルドしたものがプレビューできるか

npm run serve

OK!

warugakiwarugaki

## GitHubへPUSH!!

StoryBookが起動しないことに気づいたので修正w

emmotionのcss propsが影響

warugakiwarugaki
このスクラップは2021/12/30にクローズされました