파크로그
article thumbnail

cos-ui

cos-ui 의 루트에는 eslintrc.js 가 없고, 각 패키지의 루트에 eslintrc 가 존재했다. 그래서인지 다른 곳에서 사용하던 방식으로는 오류가 났다.

cos-ui/
패키지별로 각각의 설정파일이 존재했다.

 

 

// lint-staged.config.js

module.exports = {
  '*.{js,jsx,ts,tsx}': 'eslint --fix',
};

 

 

이유를 생각해보았을 때, eslint 를 실행하는 곳 ( /cos-ui ) 에 eslint 관련 설정 파일이 없어 생기는 문제라고 생각했다.

 

찾아보니 두 가지 방법이 있었다.

  1. 각 패키지별로 eslintrc 설정파일을 찾아 실행하도록
  2. 공통된 eslintrc 를 만들어서 사용

 

1번 방법은 다소 번거롭지만 lint-staged 에서 경로별로 설정하여 사용한다.

module.exports = {
  'packages/react/**/*.+(js|jsx|ts|tsx)': 'eslint --fix',
  'packages/playground-react/**/*.+(js|jsx|ts|tsx)': 'eslint --fix',
  'packages/primitives/**/*.+(js|jsx|ts|tsx)': 'eslint --fix',
};

eslint 만 하면 그래도 적은 편이지만, tsc 까지 고려한다면 2배로 늘어난다.

module.exports = {
  'packages/react/**/*.+(js|jsx|ts|tsx)': 'eslint --fix',
  'packages/react/**/*.+(ts|tsx)': () => 'tsc -p packages/react/tsconfig.json --noEmit',
  'packages/playground-react/**/*.+(js|jsx|ts|tsx)': 'eslint --fix',
  'packages/playground-react/**/*.+(ts|tsx)': () => 'tsc -p packages/playground-react/tsconfig.json --noEmit',
  'packages/primitives/**/*.+(js|jsx|ts|tsx)': 'eslint --fix',
  'packages/primitives/**/*.+(ts|tsx)': () => 'tsc -p packages/primitives/tsconfig.json --noEmit',
};

 

결론적으로는 2번 방법을 택했다.

 

패키지별로 eslint 설정파일을 다룬다면 A 패키지에서 결정난 룰을 B 패키지에서도 수동으로 추가해야하는 번거로움이 있기에 eslint 는 공통된 설정 파일로 관리하는게 맞다고 생각하여 분리하는 과정을 거쳤다.

 

eslint 가 parserOption 으로 tsconfig.json 를 찾기 때문에 각 패키지의 공통된 tsconfig 속성들을 비교하고 분리해주어 cos-ui 루트에 tsconfig.json 을 생성하였고, 각 패키지는 해당 tsconfig.json 을 extends 하여 사용하도록 변경했다.

 

여기서 핵심은 린팅을 제대로 해주기 위해서는 eslint 에서 각 tsconfig.json 을 찾아갈 수 있도록 import resolver 설정을 각각의 tsconfig.json 로 설정해주어야 했다.

 

각 패키지의 tsconfig 관련 파일들이 많이 줄었다.

// packages/react/tsconfig.json


// 이전

{
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "dist",
    "target": "ESNext",
    "module": "commonjs",
    "moduleResolution": "Node",
    "declaration": true,
    "declarationMap": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "allowJs": true,
    "strict": true,
    "noImplicitAny": false,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  },
  "include": ["src"],
  "exclude": ["node_modules"],
  "extends": "./tsconfig.path.json"
}

// + tsconfig.path.json, tsconfig.eslint.json...

// 이후

// 베이스 tsconfig.json
{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
    "target": "ESNext",
    "module": "commonjs",
    "moduleResolution": "node",
    "isolatedModules": true,
    "allowJs": true,
    "strict": true,
    "noImplicitAny": false,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "exclude": [
    "packages/**/dist/**",
    "lint-staged.config.js",
    "packages/**/*.config.js"
  ]
}


// packages/react/tsconfig.json

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "dist",
    "declaration": true,
    "declarationMap": true,
    "jsx": "react-jsx",
    "paths": {
      "@components/*": ["src/components/*"],
      "@styles/*": ["src/styles/*"]
    }
  },
  "include": ["src"]
}

 

 

// eslintrc.js

{
  ...,
  overrides: [
    {
      files: ['packages/playground-react/**/*.ts?(x)'],
      settings: {
        'import/resolver': {
          typescript: {
            project: './packages/playground-react/tsconfig.json',
          },
        },
      },
    },
    {
      files: ['packages/primitives/**/*.ts?(x)'],
      settings: {
        'import/resolver': {
          typescript: {
            project: './packages/primitives/tsconfig.json',
          },
        },
      },
    },
    {
      files: ['packages/react/**/*.ts?(x)'],
      settings: {
        'import/resolver': {
          typescript: {
            project: './packages/react/tsconfig.json',
          },
        },
      },
    },
  ]
}

 

eslint 테스트 성공

 

Type check 는 tsconfig 들이 각각 다른 설정을 가질 확률이 높기 때문에 별도의 스크립트를 작성하여 주었다.

 

module.exports = {
  '*.{js,jsx,ts,tsx}': ['eslint --fix'],
  'packages/react/**/*.+(ts|tsx)': () =>
    'tsc -p packages/react/tsconfig.json --noEmit',
  'packages/playground-react/**/*.+(ts|tsx)': () =>
    'tsc -p packages/playground-react/tsconfig.json --noEmit',
  'packages/primitives/**/*.+(ts|tsx)': () =>
    'tsc -p packages/primitives/tsconfig.json --noEmit',
};

 

lint-staged 가 바뀐 부분만 eslint 를 체크해주니 type check 도 바뀐 파일만 할까? 궁금했다.

A 파일에서 선언한 B 타입을 수정하고, B 타입을 사용하는 C 파일이 타입체크에 걸리는지 테스트해보았다. 

결론은 수정된 파일만 확인하는게 아니라 타입체크를 제대로 해주는 것을 볼 수 있었다.

 

 

prettier write 까지 추가하고 마무리했다.

 

module.exports = {
  '*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
  'packages/react/**/*.+(ts|tsx)': () =>
    'tsc -p packages/react/tsconfig.json --noEmit',
  'packages/playground-react/**/*.+(ts|tsx)': () =>
    'tsc -p packages/playground-react/tsconfig.json --noEmit',
  'packages/primitives/**/*.+(ts|tsx)': () =>
    'tsc -p packages/primitives/tsconfig.json --noEmit',
};

 

 

참고

- https://techblog.woowahan.com/7976/

profile

파크로그

@파크park

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!