Yarn Berry(v3) Workspace #1 - workspace 설정

projaguar·2023년 2월 2일
2

Yarn Berry Workspace

목록 보기
1/5
post-thumbnail

Intro

이전 블로그에서 yarn berry workspace를 이용하여, NextJS, Nest, React Native 와 공유 라이브러리에 대해 정리하였습니다.
그 내용을 바탕으로 프로젝트를 진행하면서, 추가할 내용과 조금 더 설명되어야 할 부분들이 생겨 조금 더 상세하게 연재하도록 하겠습니다.

목표

  • 가급적 최소한의 설정.
  • NextJS, Nest, React Native 모두를 포함할 수 있는 설정

이번 블로그에서는 yarn berry workspace의 기본적인 설정을 진행 하겠습니다.

주요 내용

  • yarn workspace 생성
  • typescript 설정
  • eslint / prettier 설정
  • jest 설정

수정

  • 2023.07.06 - eslint prettier vscode 설정 수정
  • 2023.02.10 - typescript 설정 변경
  • 2023.02.10 - eslint 설정 변경
  • 2023.02.12 - jest.config.json 수정
  • 2023.03.16 - 전반적인 구성 및 사용법 변경

workspace 생성

프로젝트 루트 폴더를 생성하고 yarn을 설정 합니다.

# 프로젝트 폴더 생성
mkdir yarn3-mono
cd yarn3-mono

yarn set version berry
yarn init -w

yarn init 의 -w 옵션은 package.json에 workspaces 항목을 추가하고, "projects" 폴더 생성해주고, .gitignore 설정을 해줍니다.

이제 packages 폴더에 원하는 앱, 라이브러리 등을 생성 또는 설치하여 monorepo를 사용할 수 있습니다.

package.json을 수정 합니다.

{
  "name": "yarn3-mono",
  "packageManager": "yarn@3.4.1",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*",
  ]
}

packages 폴더에는 공유하게 될 라이브러리의 폴더로 사용될 것이고, apps 폴더에는 독립적으로 실행 될 앱들이 들어갈 폴더 입니다.

typescript 설정

1. 기본 typescript 설정

root 폴더에서 typescript 모듈을 설치 합니다.

yarn add -D typescript @types/node

그리고 yarn add 명령으로 패키지를 설치할 때 자동으로 @types/~~ 설치 파일을 찾아 설치해주는 유틸리티를 설치 합니다.

yarn plugin import typescript

다음은 root에 tsconfig.base.json을 생성합니다.

// tsconfig.base.json
{
  "compilerOptions": {
    "target": "es2017",
    "module": "commonjs",
    "lib": ["es2017", "dom"],
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "rootDir": ".",
    "outDir": "./dist",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "incremental": true
  }
}

packages 폴더에 있는 라이브러리들에서 상속받아 사용할 기본적인 타입스크립트 설정 입니다.

  • "declaration": true
    모듈 밖에서 사용할 수 있도록 type information을 생성 해 줍니다. (.d.ts 파일이 생성 됩니다.)
  • "declarationMap": true
    .d.ts정의에 대해 원래의 ts파일위치 맵을 만듭니다. 에디터에서 '정의로 이동' 같은 코드 네비게이션 기능을 사용할 수 있게 합니다.
  • "incremental" :true
    컴파일 시 캐싱등을 이용하여 속도를 높일수 있도록 합니다.

최대한의 호환성을 줄수 있는 설정입니다.
"outDir"의 설정은 배포 등 전체 라이브러리를 빌드하고 한곳에 모을 필요가 있을때 사용되는 빌드 폴더 입니다.

2. vscode 플러그인 설정

먼저 zipfs 플러그인을 설치 합니다.

다음은 yarn plugin을 설치 합니다.

yarn dlx @yarnpkg/sdks vscode

Visual Studo Code 설정

안전상의 이유로 VSCode에서는 사용자 지정 타입스크립트 설정을 명시적으로 활성화해야 합니다.

  1. typescript 파일을 열어 놓습니다. (없으면 간단히 비어있는 .ts 파일을 생성)

  2. ctrl+shift+p를 누릅니다.

  3. "Select TypeScript Version" 을 선택 합니다.

  4. "Use Workspace Version" 을 선택 합니다.

참고문서

ESLint / Prettier 설정

최소한의 설정만 진행 하겠습니다.
세부적인 항목은 사용하는 코딩 표준이나, 개발 환경에 맞춰 옵션을 조정 하시면 됩니다.

먼저 필요한 패키지를 설치 합니다.

저는
npm init @eslint/config 으로 기본적인 설정과 기본적인 패키지를 자동으로 설정하고
prettier 관련된 package 들만 추가로 설정 하였습니다.

이 문서를 작성하는 시점에서 prettier 3.0.0 에서 오류가 발생하여 2.8.8 버전을 사용 하였습니다.

yarn add -D @types/eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier eslint-config-standard-with-typescript eslint-plugin-import eslint-plugin-n eslint-plugin-prettier eslint-plugin-promise eslint-plugin-react prettier prettier-plugin-tailwindcss

yarn dlx @yarnpkg/sdks vscode

다음은 워크스페이스 루트에 .eslintrc.js 을 생성합니다.

// .eslintrc.js
module.exports = {
    parser: '@typescript-eslint/parser',
    env: {
      browser: true,
      es2021: true,
      node: true,
    },
    extends: ["standard-with-typescript", "plugin:react/recommended", "plugin:prettier/recommended"],
    overrides: [
      {
        env: {
          node: true,
        },
        files: [".eslintrc.{js,cjs}"],
        parserOptions: {
          sourceType: "script",
        },
      },
    ],
    parserOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      tsconfigRootDir: __dirname,
      project: "./tsconfig.base.json",
    },
    plugins: ['react', '@typescript-eslint/eslint-plugin', "prettier"],
    rules: {

    },
    ignorePatterns: ['.eslintrc.js', 'dist'],
    settings: {
      react: {
       version: "detect",
      },
    },
};
  

eslint와 prettier를 같이 사용하는 기본적인 설정입니다, 자동으로 생성된 내용에 workspace 및 prettier와 같이 사용할 내용 몇가지만 추가하였습니다. 필요에 따라 수정하여 사용하시면 됩니다.

.prettierrc 파일을 생성하고 code formatting 옵션을 설정 합니다.

// .prettierrc
{
  "semi": true,
  "trailingComma": "all",
  "singleQuote": true,
  "printWidth": 120,
  "tabWidth": 2,
  "useTabs": false,
  "plugins": ["prettier-plugin-tailwindcss"]
}

cmd + shift + p 를누른후 'Open Workspace Setting (JSON)'을 선택하여 설정 파일을 열고, eslint/prettier를 사용하도록 설정 합니다.

{
  ...
  "editor.formatOnSave": false,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  ...
}

Jest 설정

jest 관련 package를 설치 합니다.

yarn add -D jest @types/jest ts-jest

jest 설정파일을 생성합니다.

// jest.config.json
{
  "preset": "ts-jest",
  "testEnvironment": "node",
  "roots": ["<rootDir>/src"],
  "transform": {
    "^.+\\.tsx?$": "ts-jest"
  },
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
  "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
  "moduleNameMapper": {
    "^@/(.*)$": "<rootDir>/src/$1"
  },
  "setupFilesAfterEnv": ["jest-extended"],
  "globals": {
    "ts-jest": {
      "tsconfig": "<rootDir>/tsconfig.json"
    }
  }
}

Conclusion

최근 Chat GPT와 장시간 토론을 거쳐서 약간의 수정을 하기로 합의(?) 하였습니다.

  • Yarn Berrey의 기능을 최대한 사용한다.
  • 설정을 조금 더 간단히 할 수 있도록 한다.
  • 다양한 환경에서의 호환성을 조금 더 부여한다.

이런 목표로 이번 시리즈의 모든 내용을 조금씩 수정하도록 하겠습니다.

부록 - esbuild

이번 시리즈에서 목표로 하는 범위는 벗어나지만, 혹시 필요할때를 위해 esbuild를 이용하는 방법을 기록 차원에서 서술 하겠습니다.

root
    + packages
        + sample-cli
            package.json
            tsconfig.json
            + scripts
                build.js
            + src
                run.ts
        + sample-libs
            + src
                hello.ts
            package.json
            tsconfig.json

위와같은 구조로 샘플을 만들도록 하겠습니다.

1. sampe-libs 구성

초기화

cd packages
mkdir sample-libs
cd sample-libs
yarn init -y

pakcage.json 수정

// packages/sample-libs/package.json
{
  "name": "sample-cli",
  "packageManager": "yarn@3.4.1",
  "main": "src/hello.ts" // 외부 참조를 위해
}

tsconfig.json 생성

// packages/sample-libs/tsconfig.json
{
  "extends": "./../../tsconfig.base.json",
  "references": [],
  "include": ["src/**/*"],
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "."
  }
}

hello.ts 생성

// packages/sample-libs/src/hello.ts
export const hello = () => {
  console.log('hello');
  return 'hello';
};

2. sampe-cli 구성

cd packages
mkdir sample-cli
cd sample-cli
yarn init -y
yarn add -D typescript

pakcage.json 수정

// packages/sample-cli/package.json
{
  "name": "sample-cli",
  "packageManager": "yarn@3.4.1",
  "scripts": {
    "build": "tsc --build",
    "start": "yarn node ./dist/src/main"
  }
}
  • tsc --build 옵션으로 외부 참조 모듈의 빌드가 필요할때 같이 빌드를 진행 합니다.
  • node_modules 없이 node를 실행하기 위해서 'yarn node' 로 node 명령을 실행 합니다. (Pnp 모드에서만)

tsconfig.json 생성

// packages/sample-cli/tsconfig.json
{
  "extends": "./../../tsconfig.base.json",
  "references": [],
  "include": ["src/**/*"],
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "."
  }
}

sample 소스 생성

// packages/sample-cli/src/main.ts
export const main = () => {
  console.log('main !!!');
};
main();

3. 테스트

yarn workspace sample-cli build
yarn workspace sample-cli start

원하는 결과가 출력되는것을 확인할 수 있습니다.

4. sampe-cli에서 sample-lib 모듈 참조

// packages/sample-cli/src/main.ts
import { hello } from 'sample-libs';

export const main = () => {
  console.log('main !!!');
  console.log('reference', hello());
};
main();
// packages/sample-cli/tsconfig.json
{
  "extends": "./../../tsconfig.base.json",
  "include": ["src/**/*"],
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "."
  },
  "references": [{ "path": "../sample-libs" }] // reference 항목 추가
}
yarn workspace sample-cli build
yarn workspace sample-cli start

빌드는 정상적으로 이루어지지만, 외부 참조 모듈에대한 아래와 비슷한 오류가 발생 합니다.
dist 폴더 내에 컴파일된 소스를 보면 외부 참조 모듈에 대해 정보가 없어서 입니다.

빌드 시 외부 참조 모듈을 포함하여 번들링 하기 위한 번들러 중, esbuild를 이용하여 문제를 수정하도록 하겠습니다.

esbuild 관련 패키지를 설치 합니다.

yarn add -D esbuild @yarnpkg/esbuild-plugin-pnp

build script를 생성 합니다.
'packages/sample-cli/scripts' 폴더를 생성하고 그곳에 build.js 파일을 만듭니다.

// packages/sample-cli/scripts/build.js
const { pnpPlugin } = require('@yarnpkg/esbuild-plugin-pnp');
const esbuild = require('esbuild');

esbuild
  .build({
    plugins: [pnpPlugin()],
    bundle: true,
    entryPoints: ['dist/src/main.js'], // 컴파일된 코드의 entry point
    outfile: 'dist/cli.js', // 결과 출력 파일
  })
  .catch((e) => {
    console.log('Build not successful', e.message);
    process.exit(1);
  });

다음은 package.json 파일을 수정 합니다

{
  "name": "sample-cli",
  "packageManager": "yarn@3.4.1",
  "scripts": {
    "build": "tsc --build && yarn node ./scripts/build.js",
    "start": "yarn node ./dist/cli"
  },
  "devDependencies": {
    "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.15",
    "esbuild": "^0.17.5",
    "typescript": "^4.9.5"
  }
}

빌드 및 실행을 합니다.

yarn workspace sample-cli build
yarn workspace sample-cli start

정상적으로 실행 됩니다.

References

https://maxrohde.com/2021/09/30/typescript-monorepo-with-yarn-and-project-references

https://dev.to/vinibgoulart/configuring-lerna-monorepo-to-use-prettier-and-eslint-with-typescript-3log

https://tech.osci.kr/2022/11/23/환상적인-케미-webpack-esbuild/

https://cathalmacdonnacha.com/setting-up-eslint-prettier-in-vitejs

https://velog.io/@njh7799/Eslint-Prettier-설정-방법

https://blog.logrocket.com/linting-typescript-eslint-prettier/

profile
아직도 개발하고 있는 개발자 입니다

0개의 댓글