리액트 컴포넌트 라이브러리 만들기 (1) - 프로젝트 세팅 및 배포

기운찬곰·2023년 5월 1일
4

Overview

npm에 나만의 라이브러리를 만들어서 배포하고 Weekly Downloads 수가 점점 늘어간다면 얼마나 좋을까요? 정말 기분 좋은 상상일 겁니다. 좋은 경험이 될 수 있고, 한편으로는 좋은 스펙이 될 수도 있을 겁니다.

그래서 한번 저도 라이브러리를 만들어서 배포해보도록 하겠습니다. 퇴사 후 목표 중 하나였으니까요. 일단, 그러기 위해서는 어떤 라이브러리를 만들 것인가? 어디서부터 어떻게 시작해볼 것인가? 그리고 간단한 샘플 라이브러리를 만들어서 실제 npm에 배포해보고 설치하고 사용해보는것까지 진행해보록 하겠습니다.


라이브러리를 굳이 만들 필요가 있을까?

여러 개발 블로그 글을 보면서 다른 사람들도 이런 생각을 한번쯤 하고 있구나 느꼈습니다.

물론 잘 다듬어진 라이브러리를 가져다가 사용하는 건 좋습니다. 시간 절약도 될 것이고 어느정도 최적화가 되어있을 것이기 때문에 직접 만드는 것보다 더 좋을 수 있습니다.

하지만, 해당 라이브러리가 다 좋은데 몇가지 이슈가 있거나 기능이 추가되었으면 좋겠다 싶은데... 하는 경험이 있을 것입니다. 이 때, 직접 github issue를 작성하거나 PR을 날리면 문제 해결은 가능하겠지만... 그게 관리가 잘 안되고 있는 죽은 패키지라면 어떨까요? 직접 fork를 떠서 수정도 가능하겠지만 좀 그렇긴 합니다.

그래서 회사 내에서는 필수 핵심 라이브러리는 직접 개발하기도 하는 거 같습니다. 오픈 소스 라이브러리란 것은 언제 어떻게 바뀔지 모르기 때문에... 그리고 직접 라이브러리를 개발해보는 것도 상당한 도움이 될 것입니다. 모르고 쓰는 거랑 알고 쓰는 건 정말 다를테니까요.


구현 방향 생각해보기 - 라이브러리 선정 및 참고 라이브러리 분석

참고 : https://www.npmjs.com/package/react-modal-sheet
깃허브 : https://github.com/Temzasse/react-modal-sheet

저는 최근에 bottom sheet에 대해 알아본 적이 있었습니다. 그 중에서 react-modal-sheet라는 라이브러리가 있었는데요. 꽤 괜찮아보였고 github pages에 간단한 테스트까지 해볼 수 있어서 이거 쓰면 진짜 편하겠다 라는 생각이 들었습니다. 그래서 저는 이 프로젝트 구조(구성)을 한 번 참고해보겠습니다.

해당 프로젝트를 보니까 tsdx 라는게 눈에 띄더군요. 이걸로 실행도 하고 build도 하는거 같습니다. 배포하기전에 build를 하면 dist 폴더가 생성되는거 같고, main은 dist/index.js 인거 같고요.

아, 그리고 저도 bottom sheet라는 주제로 라이브러리를 만들 예정입니다. 다만, 저 라이브러리를 그대로 카피할 생각은 없고 어느정도 분석은 하긴 할텐데 제 식대로 기능을 단순화해서 만들 예정입니다. 최종적으로는 모바일 웹 뷰에서도 제대로 지원되도록 만들어 보겠습니다.


tsdx가 뭔지 알아보자

공식문서를 참고해보면 다음과 같이 요약해볼 수 있었습니다.

  • TSDX는 TypeScript 패키지 개발을 위한 Zero-config CLI이다.
  • 최근의 모든 과대 광고(?)에도 불구하고 새로운 TypeScript (x React) library 세팅은 힘들 수 있다.
  • Rollup, Jest, tsconfig, yarn resolutions(?), VSCode가 제대로 작동하는 것… 아주 해야 할 일이 많다.
  • TSDX는 모던 타입스크립트 패키지 개발, 테스트 및 publish를 지원하는 zero-config CLI이다. 프로젝트를 구성하는데 오후를 낭비하지 않습니다.

그니까 이런 것들이 기본적으로 다 내장 및 세팅 되어있어서 프로젝트를 구성하는데 시간을 쏟을 필요가 없다는 거 같습니다.

직접 하나씩 세팅해보면서 하는 것도 나쁘지 않지만 tsdx를 사용하는 것도 괜찮은 선택지 인거 같습니다.

아래 명령으로 프로젝트를 시작할 수 있습니다.

npx tsdx create mylib

또한, 3가지 템플릿중 하나를 선택할 수 있다고 합니다.

  • basic
  • react
  • react-with-storybook

템플릿을 선택하면 TSDX가 프로젝트 템플릿이 포함된 폴더를 생성하고 모든 종속성을 설치해줍니다. TypeScript, Rollup, Jest, ESlint 및 기타 모든 설정은 모범 사례와 함께 설정되어있습니다. src/index.ts(tsx)를 편집하고 시작하세요.

저도 tsdx를 사용해서 프로젝트를 시작해보도록 하겠습니다.


tsdx 로 프로젝트 세팅해보기

react 컴포넌트 라이브러리를 개발할 예정이므로 template은 react로 하겠습니다.

npx tsdx create react-bottom-sheet --template react

설치 과정을 보면 이러한 라이브러리가 기본으로 설치가 되네요. 사실 tsdx안에 rollup도 있고 여러가지가 딸려서 같이 설치되긴 합니다.

✔ Created react-bottom-sheet
⠇ Installing npm modules:
    @size-limit/preset-small-lib
    @types/react
    @types/react-dom
    husky
    react
    react-dom
    size-limit
    tsdx
    tslib
    typescript

설치가 끝나고 프로젝트를 보면 기본적으로 src/index.tsx에는 샘플 컴포넌트만 있는 것을 알 수 있습니다.

import * as React from 'react';

// Delete me
export const Thing = () => {
  return <div>the snozzberries taste like snozzberries</div>;
};

그리고 여기서 yarn run start 실행한다고 해서 화면을 볼 수 있는 것도 아닙니다. 대신에 hot reload도 지원하는거 같고, 자체적으로 rollup이 내장되어있는거 같습니다. node_modules 보니까 rollup, rollup-plugin-terser 도 있고, @rollup/plugin-bable… 이런것도 사실 직접 세팅을 해야하는건데 기본적으로 세팅이 되어있는 거 같아서 편하네요.

@rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
⠸ Compiling modules...@rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
✔ Compiled successfully

  Watching for changes

내부 설정이 궁금하다면 한 번 찾아보는것도 좋을 거 같네요. (어휴...야...)

이렇게 실행을 했는데 볼 수 있는 화면이 없어서 참 답답하던 차에 example 폴더에 별도 프로젝트가 하나 더 있었습니다. 여기는 parcel을 사용해서 해당 컴포넌트를 화면을 보면서 테스트해볼 수 있게 해놨네요.

import 'react-app-polyfill/ie11';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Thing } from '../.';

const App = () => {
  return (
    <div>
      <Thing />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

근데 뭐 설치하고 실행 하자마자 에러가 발생하네요. 찾아보니까 parcel 자체 문제인거 같습니다. parcel 버전을 1.12.3으로 낮추면 해결된다고 하고요. (깃허브 이슈 참고, 깃허브 이슈 참고 2)

오래된 문제인거 같은데 왜 해결을 안하는지 모르겠네요...

❯ yarn start
yarn run v1.22.10
$ parcel index.html
Server running at http://localhost:1234 
🚨  /Users/ckstn0777/Documents/react-bottom-sheet/example/index.tsx: Invalid Version: undefined

또 다른 방법으로는 parcel을 새 버전(2.xx)으로 올리라고 하네요. 그리고 나서 index.html 에서 script에서 type="module"을 추가해주면 된다고 합니다.

<body>
  <div id="root"></div>
  <script type="module" src="./index.tsx"></script> // type="module" 추가
</body>

일단 에러는 해결되었습니다. 근데 또 다른 문제로 핫 리로딩은 안되는거 같습니다. tsdx watch 되는게 맞나 의심이 드네요.

근데 몇가지 테스트를 해보다가 느낀 점인데 tsdx watch하면 dist가 바뀌는건 맞는거 같습니다. 즉, parcel 프로젝트에서 tsdx로 개발중인 내 라이브러리를 가져다가 사용하는 부분에서 문제가 있는거 같습니다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Thing3 } from '../.';  // dist 폴더 참조

const App = () => {
  return (
    <div>
      <p>111</p>
      <Thing3 />
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

그래서 찾아보니 parcel에 no-cache 옵션이 적용도 해줬는데.. 그래도 안되네요. 신기한건 저 Thing 이라는 컴포넌트만 제대로 핫 리로딩이 안되며, 나머지 parcel에서의 수정은 잘 바뀝니다...

참고 : https://github.com/parcel-bundler/parcel/issues/6685#issuecomment-971842901

이 문제에 대해 더 알아보니 parcel이 문제가 많은거 같습니다. 아마 현재 상황으로는 parcel 설정만으로는 고칠수 없을거 같습니다.


간단한 라이브러리 만들기

근데 정말 이걸 가지고 라이브러리 배포까지 할 수 있을까요? 그래서 한 번 정말 간단한 껍데기 라이브러리를 만들어서 배포를 해보도록 하겠습니다. CSS도 사용하지 않은 정말 빈 껍데기입니다.

import React from 'react';

interface ReactButtonSheetProps {
  /**
   * The text to display
   */
  text: string;
}

export const ReactButtonSheet = ({ text }: ReactButtonSheetProps) => {
  return <div>{text}</div>;
};

배포 사이즈 알아보기

근데 과연 저 라이브러리의 사이즈는 어떻게 될까요? 라이브러리 사이즈가 크다면 아무도 사용하지 않을 것이기 때문에 사이즈 체크는 배포 전에 꼭 확인해야 될 사항인 거 같습니다.

참고 : https://www.npmjs.com/package/size-limit

tsdx에는 기본적으로 size-limit이라는 라이브러리가 설치되어있는데 이 녀석을 사용하면 배포 사이즈를 잘 알려주는 거 같습니다. cjs 버전과 esm 버전으로 나눠서 잘 알려주네요. 빈껍데라서 그런지 1 kB도 안 넘습니다.

"size": "size-limit",
❯ yarn run size
yarn run v1.22.10
$ size-limit
✔ Adding to empty esbuild project
  
  dist/react-bottom-sheet.cjs.production.min.js
  Size limit: 10 kB
  Size:       323 B with all dependencies, minified and gzipped
  
  dist/react-bottom-sheet.esm.js
  Size limit: 10 kB
  Size:       443 B with all dependencies, minified and gzipped

이제 배포해보도록 합니다

참고로 react-modal-sheet는 np 를 통해 배포하고 있었습니다. np는 또 뭘까요?

"release": "np"

참고 : https://www.npmjs.com/package/np
(”A better npm publish”). npm publish 보다 더 낫다고 하네요.

한 번 사용해봅시다. 글로벌 설치를 해줍니다.

npm install --global np

그리고 실행해보니 이런식으로 대화형으로 물어보네요.

❯ yarn run release
yarn run v1.22.10
$ np
? The following new files will not be part of your published package:
- .github/workflows/main.yml
- .github/workflows/size.yml
- example/index.html
- example/index.tsx
- example/tsconfig.json
- example/yarn.lock
- tsconfig.json
- yarn.lock
The following new files will be published for the first time:
- src/index.tsx
Continue? (y/N)

라이브러리 배포를 하려면 버전까지 바꿔줘야 합니다. 버전 여부도 물어봐줍니다.

Publish a new version of chan-bottom-sheet (current: 0.1.0)

아... 근데 중간에 user 인증 부분에서 막혔네요.

? How should this pre-release version be tagged in npm? next

  ❯ Prerequisite check
    ✔ Ping npm registry
    ✔ Check npm version
    ✔ Check yarn version
    ✖ Verify user is authenticated
      → You must be logged in. Use `npm login` and try again.
      Check git version
      Check git remote
      Validate version
      Check for pre-release version
      Check git tag existence
    Git
    Installing dependencies using Yarn
    Running tests using Yarn
    Bumping version using Yarn
    Publishing package using Yarn
    Pushing tags
    Creating release draft on GitHub

✖ You must be logged in. Use `npm login` and try again.

Aborted!
error Command failed with exit code 1.

npm login을 해줍니다. 근데 그래도 안되네요... 찾아보니까 react-bottom-sheet는 누가 이미 사용중이라서 그럴 수 있다네요. 그래서 라이브러리 명을 chan-bottom-sheet로 바꿔줬습니다.

그리고 나서 package.json에 publishConfig 속성도 추가해주었습니다.

"publishConfig": {
    "registry": "https://registry.npmjs.org"
  },

인증에러는 이제 해결되었는데 test 코드 에러가 발생하네요. 크... 철저합니다.

✖ Running tests using Yarn
    → info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
    Bumping version using Yarn
    Publishing package using Yarn
    Pushing tags
    Creating release draft on GitHub

✖ Command failed with exit code 1: yarn test

test 코드 자체 문제는 아닌거 같고 tsdx 문제인거 같은데 도저히 해결할 수 없어서 그냥 tsdx test 버리고, jest 명령을 사용하도록 하겠습니다. 드디어 성공했네요.

Registry:
https://registry.npmjs.org

? Select semver increment or specify new version patch  0.1.1

  ✔ Prerequisite check
  ✔ Git
  ✔ Installing dependencies using Yarn
  ✔ Running tests using Yarn
  ✔ Bumping version using Yarn
  ✔ Publishing package using Yarn
  ✔ Pushing tags
  ✔ Creating release draft on GitHub

 chan-bottom-sheet 0.1.1 published 🎉
✨  Done in 17.13s.

그러면 깃허브에 이렇게 나오는데 publish release하면...

이렇게 나오고

npm에도 잘 올라간 것을 볼 수 있습니다. README.md는 수정 좀 해야겠네요.


실제 가져다가 사용해보기

라이브러리 배포도 했는데 사용도 안하고 끝내면 섭하죠...? 사이드 프로젝트에서 설치해서 사용해보도록 했습니다.

pnpm install chan-bottom-sheet
Packages: +1
+

dependencies:
+ chan-bottom-sheet 0.1.1

Progress: resolved 425, reused 412, downloaded 1, added 1, done
Done in 3.2s

그리고 사용해봅니다. 타입스크립트 지원도 기본적으로 잘 되네요.

import { ReactButtonSheet } from "chan-bottom-sheet";

&<ReactButtonSheet text="react bottom sheet 테스트" />

node_modules에 다운 받은 라이브러리를 보면 다음과 같이 들어있습니다.

이제 본격적으로 라이브러리 개발을 할 준비가 되었습니다.


마치면서

이제 첫 삽을 뜬 거나 마찬가지네요. 중간에 놓치 않고 이번에는 끝까지 해봤으면 좋겠다는게 제 바람입니다...

profile
배움을 좋아합니다. 새로운 것을 좋아합니다.

0개의 댓글