eun0leee / practice-monorepo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

2-1주차 배포하기 - 테스트 환경 만들기

apps에 신규 프로젝트 추가한다.

  1. 기존의 apps/wanted 폴더를 copy + paste 한다.

  2. 폴더 이름을 admin 으로 변경

스크린샷 2022-12-12 14 06 07


  1. apps/admin/package.json name 변경 --> @wanted/admin

스크린샷 2022-12-12 14 06 33


  1. apps/admin/pages/api/admin.ts 파일을 생성 후 아래 내용 추가

스크린샷 2023-05-10 17 17 07


// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next';

type Data = {
  name: string;
};

export default function handler(req: NextApiRequest, res: NextApiResponse<Data>) {
  res.status(200).json({ name: 'John Doe' });
}

  1. 터미널에서 yarn 으로 갱신시켜준다.
// root 에서
yarn

  1. @wanted/admin 빌드 되는지 확인.
yarn workspace @wanted/admin build



✅ 아래와 같이 나오면 정상!

스크린샷 2022-12-12 14 04 45










1-2주차 (보충) 대규모 리펙토링

지난시간 monorepo로 구축하고 브레이킹 체인지를 발생시키고, 체킹하는 방법까지 알아보았습니다.

추가로, jscodeshift라는 javascript/typescript 수정도구에 대해서 간단히 인덱싱만 하고 지나가겠습니다.



jscodeshift github

https://github.com/facebook/jscodeshift



토스 사용 사례



react-query 사용사례

https://tanstack.com/query/v4/docs/guides/migrating-to-react-query-4

- import { useQuery } from 'react-query'
- import { ReactQueryDevtools } from 'react-query/devtools'
+ import { useQuery } from '@tanstack/react-query'
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
npx jscodeshift ./path/to/src/ \
  --extensions=ts,tsx \
  --parser=tsx \
  --transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js










1-2주차 typecheck 넣어보기

01. typescript package.json에 script추가

추가해야 할 파일

  • apps/wanted/package.json
  • packages/lib/package.json
  • packages/ui/package.json



typecheck script를 추가합니다.

"scripts": {
  "typecheck": "tsc --project ./tsconfig.json --noEmit"
},



02. Button 컴포넌트 브레이킹 체인지 발생 시켜기.

packages/ui/src/Button.tsx의 props type에 variant 추가 해본다.

import { ButtonHTMLAttributes, MouseEventHandler, ReactNode } from 'react';

export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
  children: ReactNode,
  variant: 'contained' | 'outlined', // 이 부분 추가
  onClick?: MouseEventHandler<HTMLButtonElement>,
};

const Button = (props: ButtonProps) => {
  const { children, onClick, ...other } = props;

  return (
    <button type="button" onClick={onClick} {...other}>
      {children}
    </button>
  );
};

export default Button;



그리고 아래 커맨드를 입력해본다.

yarn workspace @wanted/web typecheck

아래와 같이 에러가 체크됨을 알수 있다.

스크린샷 2022-12-11 21 14 49



03. 모든 프로젝트를 typecheck 하는 scripts 만들어보기

yarn workspace에서 관리하기 위한 기본 plugin을 제공해줍니다. https://yarnpkg.com/api/modules/plugin_workspace_tools.html

workspace-tools plugin 설치하기

yarn plugin import workspace-tools

root package.json 수정하기

"scripts": {
  "g:typecheck": "yarn workspaces foreach -pv run typecheck"
},

g:*를 붙여주는건 global 하게 모든 프로젝트를 실행한다는 의미로 붙여주었다.

yarn workspaces foreach 명령어 option 확인 https://yarnpkg.com/cli/workspaces/foreach

  • -p: 병렬 실행
  • -v: workspace name 출력



yarn g:typecheck 실행해보자

// root 에서
yarn g:typecheck

전체 프로젝트가 실행된 것을 알수 있고, @wanted/web 에 에러를 확인할 수 있음.

스크린샷 2022-12-11 21 16 30



apps/wanted/pages/index.tsx 수정한다.

스크린샷 2022-12-11 21 18 51



그리고, 다시 실행해보면! 모두 에러가 없음을 확인할 수 있었다.

✅ 아래와 같이 에러가 출력되면 성공!

스크린샷 2022-12-11 21 23 12










1-2주차 react library 패키지 만들기.

01. packages/ui 폴더 생성 및 pacakge.json 생성

스크린샷 2022-12-07 22 13 57

cd packages/ui
yarn init

package.json 파일을 열어서 name을 `@wanted/ui`로 변경.
{
  "name": "@wanted/ui",
  "packageManager": "yarn@3.3.0"
}



02. react dependency 설치

// root 이동
cd ../../

// 갱신
yarn


// install
yarn workspace @wanted/ui add typescript react react-dom @types/node @types/react @types/react-dom -D



03. ui 패키지 설정

packages/ui/tsconfig.json 설정

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "baseUrl": "./src",
    "target": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "jsx": "react-jsx",
    "noEmit": false,
    "incremental": true
  },
  "exclude": ["**/node_modules", "**/.*/", "dist", "build"]
}



packages/ui/src/index.ts, packages/ui/src/Button.tsx 파일 생성

스크린샷 2022-12-07 22 12 32



packages/ui/src/Button.tsx 내용추가

import { ButtonHTMLAttributes, MouseEventHandler, ReactNode } from 'react';

export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
  children: ReactNode,
  onClick?: MouseEventHandler<HTMLButtonElement>,
};

const Button = (props: ButtonProps) => {
  const { children, onClick, ...other } = props;

  return (
    <button type="button" onClick={onClick} {...other}>
      {children}
    </button>
  );
};

export default Button;



packages/ui/src/index.ts 내용 추가

export { default as Button } from './Button';



packages/ui/package.json main 추가

{
  "name": "@wanted/ui",
  "packageManager": "yarn@3.3.0",
  "main": "src/index.ts",
  "devDependencies": {
    "@types/node": "^18.11.11",
    "@types/react": "^18.0.26",
    "@types/react-dom": "^18.0.9",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "typescript": "^4.9.3"
  }
}

04. apps/wanted 에서 packages/ui 사용해보기

// root 에서

// @wanted/ui 의존성 설치
yarn workspace @wanted/web add @wanted/ui

// @wanted/web 구동
yarn workspace @wanted/web dev



http://localhost:3000/ 접속해보면 아래와 같은 오류가 난다.

스크린샷 2022-12-07 22 01 19

** 오류 원인 **

브라우저에서 typescript 문법을 해석하지 못해서 발생한다.



** 해결안 **

@wanted/web에서 javascript로 변환(transpile) 해줘야 한다.

// next-transpile-modules 설치
yarn workspace @wanted/web add next-transpile-modules



apps/wanted/next.config.js 파일 수정

// @wanted/ui 패키지를 tranpile 시킨다.
const withTM = require('next-transpile-modules')(['@wanted/ui']);

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
};

module.exports = withTM(nextConfig);

종료하고 다시 실행해본다.

// @wanted/web 구동
yarn workspace @wanted/web dev



✅ 아래와 같이 나왔다면 성공!

스크린샷 2022-12-07 22 06 44










1-2주차 prettier, eslint 설정 공통화



01. root에서 prettier, eslint 설치

yarn add prettier eslint eslint-config-prettier eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks eslint-import-resolver-typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser -D


yarn dlx @yarnpkg/sdks

.vscode/extensions.json 에 익스텐션이 추가 확인

스크린샷 2022-12-07 16 45 14



02. vscode 익스텐션 설치

  • esbenp.prettier-vscode
  • dbaeumer.vscode-eslint

스크린샷 2022-12-07 19 11 12

스크린샷 2022-12-07 16 43 59

.vscode/extensions.json 추가되면 위 그림에 보이는 대로 이 확장은 현재 작업 영역의 사용자가 권장한 항목입니다표시 됩니다.



03. .vscode/settings.json 설정 추가

"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.rulers": [
  120
],

prettier 동작 확인!

prettier-test



04. root에 .eslintrc.js 파일 추가

root에 .eslintrc.js 파일 생성 후 아래 내용 추가

토글 접기/펼치기
module.exports = {
  root: true,

  env: {
    es6: true,
    node: true,
    browser: true,
  },

  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: { jsx: true },
  },

  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'prettier',
  ],
  plugins: ['@typescript-eslint', 'import', 'react', 'react-hooks'],
  settings: { 'import/resolver': { typescript: {} }, react: { version: 'detect' } },
  rules: {
    'no-implicit-coercion': 'error',
    'no-warning-comments': [
      'warn',
      {
        terms: ['TODO', 'FIXME', 'XXX', 'BUG'],
        location: 'anywhere',
      },
    ],
    curly: ['error', 'all'],
    eqeqeq: ['error', 'always', { null: 'ignore' }],

    // Hoisting을 전략적으로 사용한 경우가 많아서
    '@typescript-eslint/no-use-before-define': 'off',
    // 모델 정의 부분에서 class와 interface를 합치기 위해 사용하는 용법도 잡고 있어서
    '@typescript-eslint/no-empty-interface': 'off',
    // 모델 정의 부분에서 파라미터 프로퍼티를 잘 쓰고 있어서
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/no-parameter-properties': 'off',
    '@typescript-eslint/no-var-requires': 'warn',
    '@typescript-eslint/no-non-null-asserted-optional-chain': 'warn',
    '@typescript-eslint/no-inferrable-types': 'warn',
    '@typescript-eslint/no-empty-function': 'off',
    '@typescript-eslint/naming-convention': [
      'error',
      { format: ['camelCase', 'UPPER_CASE', 'PascalCase'], selector: 'variable', leadingUnderscore: 'allow' },
      { format: ['camelCase', 'PascalCase'], selector: 'function' },
      { format: ['PascalCase'], selector: 'interface' },
      { format: ['PascalCase'], selector: 'typeAlias' },
    ],
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
    '@typescript-eslint/no-unused-vars': ['error', { ignoreRestSiblings: true }],
    '@typescript-eslint/member-ordering': [
      'error',
      {
        default: [
          'public-static-field',
          'private-static-field',
          'public-instance-field',
          'private-instance-field',
          'public-constructor',
          'private-constructor',
          'public-instance-method',
          'private-instance-method',
        ],
      },
    ],

    'import/order': [
      'error',
      {
        groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object'],
        alphabetize: { order: 'asc', caseInsensitive: true },
      },
    ],

    'react/prop-types': 'off',
    // React.memo, React.forwardRef에서 사용하는 경우도 막고 있어서
    'react/display-name': 'off',
    'react-hooks/exhaustive-deps': 'error',
    'react/react-in-jsx-scope': 'off',
    'react/no-unknown-property': ['error', { ignore: ['css'] }],
  },
};



05. .vscode/settings.json eslint 설정 추가

"eslint.nodePath": ".yarn/sdks",

// 아래 내용추가
"eslint.packageManager": "yarn",
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],



06. apps/wanted/.eslintrc.json 파일 삭제.

스크린샷 2022-12-07 17 26 06



07. apps/wanted/pages/index.tsx eslint 동작 확인.

스크린샷 2022-12-07 17 26 46



eslint가 정상적으로 동작이 안되면 eslint 서버를 재시작 해본다.

  1. ⌨️ command + shift + p
  2. ESLint: Restart EsLint Server 선택

스크린샷 2022-12-07 17 28 38

eslint 동작 확인!

eslint










1-2주차 tsconfig 설정 공유하기

01. root 디렉토리에 tsconfig.base.json 파일 생성

{
  "compilerOptions": {
    "strict": true,
    "useUnknownInCatchVariables": true,
    "allowJs": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "incremental": true,
    "newLine": "lf"
  },
  "exclude": ["**/node_modules", "**/.*/"]
}

스크린샷 2022-12-07 14 39 01




02. apps/wanted/tsconfig.json 내용추가

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "baseUrl": "./src",
    "target": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "jsx": "preserve",
    "incremental": true
  },
  "exclude": ["**/node_modules", "**/.*/"],
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "**/*.mts",
    "**/*.js",
    "**/*.cjs",
    "**/*.mjs",
    "**/*.jsx",
    "**/*.json"
  ]
}



03. packages/lib/tsconfig.json 내용추가

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "node",
    "target": "ESNext",
    "lib": ["ESNext", "dom"],
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": "./src",
    "noEmit": false,
    "incremental": true,
    "resolveJsonModule": true
  },
  "exclude": ["**/node_modules", "**/.*/", "./dist", "./coverage"],
  "include": ["**/*.ts", "**/*.js", "**/.cjs", "**/*.mjs", "**/*.json"]
}










1-1주차 yarn berry(2.x, 3.x, 4.x) workspace

1. yarn berry 버전 변경

// yarn 버전 확인
yarn -v

// yarn 버전 변경
yarn set version berry
yarn set version stable

// yarn 버전 확인
yarn -v


// project 폴더 생성
mkdir yarn-berry-workspace
cd yarn-berry-workspace



2. yarn workspace 패키지 만들기

// packages 디렉토리 만들기 / 루트 초기화
yarn init -w

https://yarnpkg.com/cli/init




3. root pacakge.json파일 수정

./package.json

apps/* 폴더추가

{
  "name": "yarn-berry-workspace-test",
  "packageManager": "yarn@3.3.0",
  "private": true,
  "workspaces": ["apps/*", "packages/*"]
}



4. apps 폴더에 create next-app 프로젝트 추가

// 1. create-next-app 프로젝트 생성
cd apps
yarn create next-app

저는 아래와 같이 셋팅 하였습니다.

스크린샷 2022-12-07 10 44 06

pacakge.json 수정 name @wanted/web으로 변경 스크린샷 2022-12-07 10 45 09

// 3. root가서 상태 갱신하기

cd ..
yarn


// 4. 실행 확인
yarn workspace @wanted/web run dev



5. typescript error 발생

./apps/wanted/pages/index.tsx 을 열어보면 typescript error가 발생합니다.

yarn berry는 npm과 모듈을 불러오는 방식이 다르기 때문에 생기는 문제입니다. ea1a826f-42c5-46f0-8755-9cd047efc047

yarn add -D typescript
yarn dlx @yarnpkg/sdks vscode



6. yarn PnP 사용을 위한 vscode extension 설치 arcanis.vscode-zipfs

이미 추가 되어 있다면 skip 합니다.

.vscode/extensions.json에 추가

{
  "recommendations": ["arcanis.vscode-zipfs"]
}

스크린샷 2022-12-06 17 02 37




7. pacakges/lib 공통 패키지를 만들어보기

packages/lib 폴더 생성하고, 아래 스크립트를 실행한다.

// lib 폴더 이동
cd packages/lib

// pacakge.json 파일 생성
yarn init



아래와 같이packages/lib/package.json 파일 수정한다.

{
  "name": "@wanted/lib",
  "version": "1.0.0",
  "private": true,
  "main": "./src/index.ts",
  "dependencies": {
    "typescript": "^4.9.3"
  }
}



packages/lib/tsconfig.json 파일 생성 후 설정값 넣기

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "strict": true,
    "useUnknownInCatchVariables": true,
    "allowJs": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "newLine": "lf",
    "module": "ESNext",
    "moduleResolution": "node",
    "target": "ESNext",
    "lib": ["ESNext", "dom"],
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": "./src",
    "noEmit": false,
    "incremental": true,
    "resolveJsonModule": true,
    "paths": {}
  },
  "exclude": ["**/node_modules", "**/.*/", "./dist", "./coverage"],
  "include": ["**/*.ts", "**/*.js", "**/.cjs", "**/*.mjs", "**/*.json"]
}



packages/lib/src/index.ts 파일 생성하기 하고 간단한 코드 넣는다.

export const sayHello = () => {
  console.log('hello from lib');
  return 'hello from lib';
};




8. apps/wanted에서 pacakges/lib 의존해 보기

apps/wanted에 의존성 주입

// root로 이동한다.
cd ../../

// root 실행한다.
yarn workspace @wanted/web add @wanted/lib

apps/wanted/package.json에 의존성이 추가된 것을 확인 합니다.

dadd0545-744d-498e-acc3-a15db42f11d6

9. apps/wanted/pages/index.tsx 파일에서 @wanted/lib 사용해보기

@wanted/libsayHello 함수를 호출해 봅니다. 스크린샷 2022-12-07 10 51 52

그리고, @wanted/web을 구동해 봅니다.

yarn workspace @wanted/web run dev



아래와 같이 hello from lib이 노출된다면 성공 입니다.

스크린샷 2022-12-07 10 54 39

About


Languages

Language:TypeScript 45.7%Language:CSS 30.9%Language:JavaScript 23.4%