이전 블로그에서 yarn berry workspace를 이용하여, NextJS, Nest, React Native 와 공유 라이브러리에 대해 정리하였습니다.
그 내용을 바탕으로 프로젝트를 진행하면서, 추가할 내용과 조금 더 설명되어야 할 부분들이 생겨 조금 더 상세하게 연재하도록 하겠습니다.
이번 블로그에서는 yarn berry 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 폴더에는 독립적으로 실행 될 앱들이 들어갈 폴더 입니다.
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 폴더에 있는 라이브러리들에서 상속받아 사용할 기본적인 타입스크립트 설정 입니다.
최대한의 호환성을 줄수 있는 설정입니다.
"outDir"의 설정은 배포 등 전체 라이브러리를 빌드하고 한곳에 모을 필요가 있을때 사용되는 빌드 폴더 입니다.
먼저 zipfs 플러그인을 설치 합니다.
다음은 yarn plugin을 설치 합니다.
yarn dlx @yarnpkg/sdks vscode
안전상의 이유로 VSCode에서는 사용자 지정 타입스크립트 설정을 명시적으로 활성화해야 합니다.
typescript 파일을 열어 놓습니다. (없으면 간단히 비어있는 .ts 파일을 생성)
ctrl+shift+p를 누릅니다.
"Select TypeScript Version" 을 선택 합니다.
"Use Workspace Version" 을 선택 합니다.
최소한의 설정만 진행 하겠습니다.
세부적인 항목은 사용하는 코딩 표준이나, 개발 환경에 맞춰 옵션을 조정 하시면 됩니다.
먼저 필요한 패키지를 설치 합니다.
저는
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 관련 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"
}
}
}
최근 Chat GPT와 장시간 토론을 거쳐서 약간의 수정을 하기로 합의(?) 하였습니다.
이런 목표로 이번 시리즈의 모든 내용을 조금씩 수정하도록 하겠습니다.
이번 시리즈에서 목표로 하는 범위는 벗어나지만, 혹시 필요할때를 위해 esbuild를 이용하는 방법을 기록 차원에서 서술 하겠습니다.
root
+ packages
+ sample-cli
package.json
tsconfig.json
+ scripts
build.js
+ src
run.ts
+ sample-libs
+ src
hello.ts
package.json
tsconfig.json
위와같은 구조로 샘플을 만들도록 하겠습니다.
초기화
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';
};
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"
}
}
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();
yarn workspace sample-cli build
yarn workspace sample-cli start
원하는 결과가 출력되는것을 확인할 수 있습니다.
// 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
정상적으로 실행 됩니다.
https://maxrohde.com/2021/09/30/typescript-monorepo-with-yarn-and-project-references
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/