๐Ÿ› /Dev Tool

[Storybook] ๋ฆฌ์•กํŠธ๋กœ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์‹œ ์œ ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๊ด€๋ฆฌ ๋„๊ตฌ, ์Šคํ† ๋ฆฌ๋ถ์„ ๋„์ž…ํ•ด๋ณด๊ธฐ - 2

ํ•œ๋‚˜ 2022. 2. 4. 15:10

๋ฆฌ์•กํŠธ๋กœ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์‹œ ์œ ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๊ด€๋ฆฌ ๋„๊ตฌ, ์Šคํ† ๋ฆฌ๋ถ์„ ๋„์ž…ํ•ด๋ณด๊ธฐ

(CRA + Prettier + ESLint + TypeScript + Storybook + chromatic)

2022.01.28 - [๐Ÿ› /Dev Tool] - [Storybook] ๋ฆฌ์•กํŠธ๋กœ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์‹œ ์œ ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๊ด€๋ฆฌ ๋„๊ตฌ, ์Šคํ† ๋ฆฌ๋ถ์„ ๋„์ž…ํ•ด๋ณด๊ธฐ - 1

 

[Storybook] ๋ฆฌ์•กํŠธ๋กœ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์‹œ ์œ ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๊ด€๋ฆฌ ๋„๊ตฌ, ์Šคํ† ๋ฆฌ๋ถ์„ ๋„์ž…ํ•ด๋ณด๊ธฐ - 1

๋ฆฌ์•กํŠธ๋กœ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์‹œ ์œ ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๊ด€๋ฆฌ ๋„๊ตฌ, ์Šคํ† ๋ฆฌ๋ถ์„ ๋„์ž…ํ•ด๋ณด๊ธฐ (CRA + ESLint + TypeScript + Storybook + chromatic) ์˜ˆ์ „ ํ”„๋กœ์ ํŠธ์—์„œ ๋””์ž์ธ์ด ์ˆ˜์‹œ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”๋ฐ, ๋””์ž์ธ ๋ฒ„์ „ ๊ด€๋ฆฌ

uiyoji-journal.tistory.com

 


Prettier

yarn add -D prettier

# ๋˜๋Š”

npm install --save-dev prettier

์ด์ œ ๋ฏธ๋ฆฌ ์–ด๋–ค ํฌ๋งท์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ์˜ root์—์„œ .prettierrc ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

{
  "singleQuote": false,
  "semi": true,
  "useTabs": false,
  "tabWidth": 2,
  "printWidth": 80,
  "arrowParens": "always",
  "trailingComma": "all",
  "bracketSpacing": true,
  "proseWrap": "preserve",
  "requirePragma": false,
  "overrides": [
    {
      "files": "*.css",
      "options": {
        "parser": "css"
      }
    },
    {
      "files": ["*.mts", "*.cts", "*.ts"],
      "options": {
        "parser": "typescript"
      }
    }
  ]
}

 

- css ํŒŒ์ผ์˜ prettier๊ฐ€ ์—๋Ÿฌ๋ผ๊ณ  ์žก์•„๋‚ด๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด์„œ override๋กœ ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

- "parset": "typescript"๋ฅผ override ์•ˆ์— ๋„ฃ์–ด์ฃผ์–ด์•ผ ์“ธ๋ฐ์—†๋Š” ์—๋Ÿฌ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

์ด์ œ npx prettier --check ./src ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด๋ณธ๋‹ค.

์ผ๋ถ€๋Ÿฌ ๊ธฐํ˜ธ ํ•˜๋‚˜๋ฅผ ๋„ฃ์–ด๋‘์—ˆ๋Š”๋ฐ, ์‚ฌ์‹ค ์œ„์— ์ž‘์„ฑํ•œ ๊ฒƒ๊ณผ๋Š” ํฌ๊ฒŒ ๊ด€๋ จ ์—†๊ธด ํ•˜์ง€๋งŒ, ์ด๋Ÿฐ ์‹์œผ๋กœ ํฌ๋งท ์‹คํ–‰ ์‹œ ์—๋Ÿฌ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

๋งŒ์ผ prettier๋กœ ํฌ๋งทํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด, .prettierignore ํŒŒ์ผ์„ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— ์ƒ์„ฑํ•ด์„œ gitignore์ฒ˜๋Ÿผ ๋‚ด๋ฒ„๋ ค ๋‘๊ณ ์ž ํ•˜๋Š” ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ๋‚˜๋Š” MDX ํŒŒ์ผ์„ ๊ณ„์† ์—๋Ÿฌ๋กœ ์žก๊ธธ๋ž˜ ์•„๋ž˜์ฒ˜๋Ÿผ ํ•ด์ฃผ์—ˆ๋‹ค.

# .prettierignore

# Ignore all MDX files:
*.mdx

ํ•˜์ง€๋งŒ ๋งค๋ฒˆ ์ด๋ ‡๊ฒŒ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๊ท€์ฐฎ์œผ๋‹ˆ, vscode ์—๋””ํ„ฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ, extension์˜ ๋„์›€์„ ๋ฐ›๊ณ ์ž ํ•œ๋‹ค.

command + Shift + P -> settings.json

"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,

์œ„ ์ฝ”๋“œ๋ฅผ ์ค‘๊ฐ„์— ์‚ฝ์ž…ํ•˜๋ฉด, ์ด์ œ ์ฝ”๋“œ๋ฅผ ์ €์žฅํ•  ๋•Œ๋งˆ๋‹ค ์•Œ์•„์„œ prettier๊ฐ€ ์ฝ”๋“œ๋ฅผ .prettierrc์— ์ง€์ •ํ•œ ๋Œ€๋กœ ๊ณ ์ณ์ค„ ๊ฒƒ์ด๋‹ค.

ESLint

ESLint๋Š” EcmaSript + Lint์˜ ํ•ฉ์„ฑ์–ด์ธ๋ฐ, Lint๋Š” ์ž ์žฌ์ ์œผ๋กœ ๋ฒ„๊ทธ๋‚˜ ์—๋Ÿฌ๋ฅผ ๋‚ผ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•ด ๋ณด์—ฌ์ค€๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ

npm install --save-dev eslint

# ๋˜๋Š”

yarn add -D eslint

๋””ํŽœ๋˜์‹œ๋ฅผ ์„ค์น˜ํ•ด์ค€๋‹ค.

์ด์ œ npx eslint --init

To check syntax and find problems

JavaScript modules (import/export)

React

Yes

๋ธŒ๋ผ์šฐ์ €์™€ ๋…ธ๋“œ ์œ„์—์„œ ๋ชจ๋‘ ์ฝ”๋“œ๋ฅผ ๋Œ๋ฆฐ๋‹ค๊ณ  ํ•˜๋ฉด ์ŠคํŽ˜์ด์Šค ๋ฐ”๋ฅผ ๋ˆŒ๋Ÿฌ์„œ ๋‘˜๋‹ค ์„ ํƒํ•ด์ฃผ๊ณ  ์—”ํ„ฐ๋ฅผ ์นœ๋‹ค.

JSON์œผ๋กœ ์„ ํƒํ–ˆ์ง€๋งŒ, ๋‚˜์ค‘์— ts๋กœ ๋ฐ”๊พธ๊ฒŒ ๋˜์—ˆ๋‹ค.

 

๋งˆ์ง€๋ง‰์— eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest๋ฅผ npm์œผ๋กœ ๋‹ค์šด ๋ฐ›๊ฒ ๋ƒ๊ณ  ํ•˜๋Š”๋ฐ, ๋‚˜๋Š” yarn์„ ์“ฐ๊ณ  ์žˆ์–ด์„œ No๋ฅผ ํƒํ–ˆ๊ณ ,

yarn add -D eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest

์œ„ ๋ช…๋ น์–ด๋กœ ๋””ํŽœ๋˜์‹œ๋ฅผ ๊น”์•„์ฃผ์—ˆ๋‹ค. npm์œผ๋กœ ๋ชจ๋“ˆ์„ ๋‹ค์šด๋ฐ›๊ณ  ์žˆ์—ˆ๋‹ค๋ฉด ๊ทธ๋ƒฅ yes๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋œ๋‹ค.

// .eslintrc.ts
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: ["eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/recommended"],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: "latest",
    sourceType: "module",
    project: "./tsconfig.json",
  },
  plugins: ["react", "@typescript-eslint", "prettier"],
  settings: {
    react: {
      version: "detect",
    },
  },
  rules: {
    // General
    "no-console": "error",
    // TypeScript
    "@typescript-eslint/consistent-type-imports": "error",
    "@typescript-eslint/explicit-function-return-type": "off",
    "@typescript-eslint/explicit-member-accessibility": "off",
    "@typescript-eslint/indent": "off",
    "@typescript-eslint/member-delimiter-style": "off",
    "@typescript-eslint/no-confusing-void-expression": [
      "error",
      { ignoreArrowShorthand: true, ignoreVoidOperator: true },
    ],
    "no-duplicate-imports": "off",
    "@typescript-eslint/no-duplicate-imports": "error",
    "@typescript-eslint/no-implicit-any-catch": "error",
    "no-invalid-this": "off",
    "@typescript-eslint/no-invalid-this": "error",
    "@typescript-eslint/no-invalid-void-type": "error",
    "no-loop-func": "off",
    "@typescript-eslint/no-loop-func": "error",
    "no-loss-of-precision": "off",
    "@typescript-eslint/no-loss-of-precision": "error",
    "@typescript-eslint/no-parameter-properties": "off",
    "no-redeclare": "off",
    "@typescript-eslint/no-redeclare": "error",
    "no-shadow": "off",
    "@typescript-eslint/no-shadow": "error",
    "no-throw-literal": "off",
    "@typescript-eslint/no-throw-literal": "error",
    "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
    "@typescript-eslint/no-unnecessary-condition": "error",
    "@typescript-eslint/no-unnecessary-type-arguments": "error",
    "no-unused-expressions": "off",
    "@typescript-eslint/no-unused-expressions": "error",
    "@typescript-eslint/no-unused-vars": "off",
    "@typescript-eslint/no-use-before-define": ["error", { variables: false }],
    "@typescript-eslint/prefer-enum-initializers": "error",
    "@typescript-eslint/prefer-for-of": "error",
    "@typescript-eslint/prefer-includes": "error",
    "@typescript-eslint/prefer-nullish-coalescing": "error",
    "@typescript-eslint/prefer-optional-chain": "error",
    "@typescript-eslint/prefer-reduce-type-parameter": "error",
    "@typescript-eslint/prefer-string-starts-ends-with": "error",
    "@typescript-eslint/prefer-ts-expect-error": "error",
    "@typescript-eslint/promise-function-async": "error",
    "no-return-await": "off",
    "@typescript-eslint/return-await": "error",
    "@typescript-eslint/strict-boolean-expressions": "error",
    "@typescript-eslint/switch-exhaustiveness-check": "error",

    // React
    "react/jsx-boolean-value": "warn",
    "react/jsx-curly-brace-presence": "warn",
    "react/jsx-fragments": "warn",
    "react/jsx-no-useless-fragment": "warn",
    "react/jsx-uses-react": "off",
    "react/prefer-stateless-function": "warn",
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off",

    // Functional
    "functional/prefer-readonly-type": [
      "warn",
      {
        allowLocalMutation: true,
        allowMutableReturnType: true,
        ignoreClass: true,
      },
    ],
  },
};

 

๋‹ค์Œ ๋ฒˆ์—๋Š” ์ฝ”๋“œ husky์™€ lint-staged๋ฅผ ํ†ตํ•ด์„œ ์ฝ”๋“œ ํฌ๋งท ์ž๋™ํ™”๋ฅผ ํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ๋‹ค๋ฃจ๊ณ ์ž ํ•œ๋‹ค.