thumnail.png

이번에는 라이브러리를 직접 만들어 npm에 배포해보려고 한다. 팀에서 라이브러리를 만들어야 하는 이슈를 맡을 수도 있어 라이브러리를 미리 한번 배포해보려고 하는데 학습 목적이니 간단한 util함수만 만들어서 배포해보려고 한다.

라이브러리를 배포하는데 필요한 환경도 구성했다. 다음과 같은 환경으로 작업할 예정이다. nodemon, eslint, prettier, TypeScript는 다른 포스트에서도 많이 진행했기 때문에 생략하고 진행할 예정이다.

  • nodemon, Eslint, prettier 등 개발 환경
  • TypeScript
  • rollup

TypeScript + Eslint + prettier 설정하기

이번 포스트에서 작업한 내용은 다음 레포지토리에서 작업했다.

rollup 설치 및 작업 환경설정

rollup이란?

rollup은 번들러의 한 종류로 webpack, parcel 등이 있으며 쉽게 이야기하면 의존성이 있는 모듈들을 하나의 파일로 통합시켜주는 도구이다. 그런데 라이브러리를 배포하는데 rollup이 왜 필요할까?

webpack은 es module 형태로 번들링을 해주기 때문에 tree-shaking이 지원되지 않는다. 그렇다면 우리가 만든 라이브러리를 사용하는 다른 서비스에서는 사용한 코드만 가져오는 것이 아니라 라이브러리 전체 코드를 가져오게 된다. 그렇기 때문에 tree-shaking을 지원하는 rollup을 사용하게 되었다.

rollup 및 플러그인 설치

우선 rollup 환경 설정에 필요한 모듈 및 플러그인들을 설치한다.

yarn add -D rollup
yarn add -D @rollup/plugin-alias @rollup/plugin-commonjs @rollup/plugin-node-resolve
yarn add -D rollup-plugin-dts rollup-plugin-prettier rollup-plugin-typescript2 rollup-plugin-uglify
  • rollup: rollup 모듈
  • @rollup/plugin-alias: 번들링 시 alias(절대경로)를 인식하게 해주는 플러그인
  • @rollup/plugin-commonjs: commonjs 형태의 모듈을 es모듈로 변환해주는 플러그인
  • @rollup/plugin-node-resolve: node_modules에서 써드파티 모듈을 사용할 수 있게해주는 플러그인
  • rollup-plugin-dts: typescript 번들링 플러그인 (타입 정의파일도 가능)
  • rollup-plugin-prettier: 번들링된 파일에 스타일을 적용해주는 플러그인
  • rollup-plugin-typescript2: typescript 번들링 플러그인
    • @rollup/plugin-typescript을 사용하지 않은 이유는 rollup-plugin-typescript2가 해당 라이브러리를 fork해 컴파일러 에러를 개선한 버전이라고 해서 사용함
  • rollup-plugin-uglify: 번들링된 파일 난독화 및 minify

TypeScript 플러그인을 rollup-plugin-typescript2rollup-plugin-dts, 2가지로 사용한 이유는 rollup-plugin-typescript2는 type 정의 파일을 번들링해주지 않았기 때문에 2가지를 사용했다.

rollup 설정

// rollup.config.js

import typescript from 'rollup-plugin-typescript2';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { uglify } from 'rollup-plugin-uglify';
import prettier from 'rollup-plugin-prettier';
import alias from '@rollup/plugin-alias';
import dts from 'rollup-plugin-dts';

import path from 'path';

const extensions = ['.js', '.ts'];

export default [
  // js 번들링
  {
    // 번들링 기준 파일
    input: 'src/index.ts',
    // 번들링 결과 파일과 형식(esm -> es modules, cjs -> commonjs)
    output: [{ file: 'dist/index.js', format: 'esm' }],

    plugins: [
      // typescript에서 alias를 사용했다면 번들링 시 명시해줘야 함
      alias({
        entries: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
      }),
      commonjs(),
      typescript({
        clean: true,
        sourceMap: false,
      }),
      resolve({ extensions }),
			// 번들링 파일 크기를 최소화하고 난독화하기 위해 사용
      uglify(),
    ],
  },
	// 타입 정의 파일 번들링
  {
    input: 'src/index.ts',
    output: [{ file: 'dist/index.d.ts', format: 'cjs' }],

    plugins: [
      dts(),
      alias({
        entries: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
      }),
			// 타입 정의 파일은 가독성을 위해 prettier 적용 
      prettier({
        tabWidth: 2,
      }),
    ],
  },
];

다음과 같이 rollup.config.js에 일반 index.js로 번들링 될 파일과 타입 정의 파일을 index.d.ts로 번들링하도록 설정했다. rollup의 장점이 이런 input에 따른 여러 output을 설정하는 것이 쉬운 것 같다. 각각 원하는 input과 output에 알맞은 plugin을 적용하면 된다.

// package.json

...
"scripts": {
    "dev": "nodemon --exec ts-node -r tsconfig-paths/register ./src/index.ts",
    "build": "rollup -c"
  },
...

설정을 모두 했다면 이제 package.json에 번들링을 위한 명령어을 작성한다. rollup의 -c 옵션은 config파일 설정을 적용해 실행하겠다는 의미이다.

이제 환경설정은 모두 완료했으니 직접 라이브러리를 만들어 배포를 해보자!

라이브러리 작성

function isPromise(value: any): boolean {
  return (
    Boolean(value) &&
    ['object', 'function'].includes(typeof value) &&
    typeof value.then === 'function'
  );
}

export default isPromise;

거창한 라이브러리는 아니고 간단하게 특정한 값이 Promise인지 검사하는 함수를 작성했다.

npm 배포 설정

자! 이제 라이브러리도 작성했으니 npm에 배포할 일만 남았다.

// package.json

...
// 배포하려는 package 명
"name": "@cyjo/util",
  // 버전 명
  "version": "0.1.0",
  // 메인 파일과 type 정의 파일
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  // 레포지토리 주소
  "repository": "https://github.com/cyjo9603/cy-util.git",
  // 작성자
  "author": "Chanyeong Cho <cyjo9603@gmail.com>",
  "license": "MIT",
  // npm 검색 시 명령어
  "keywords": [
    "chanyeong",
    "cyjo",
    "cy",
    "util"
  ],
  // 버그 제보
  "bugs": {
    "email": "cyjo9603@gmail.com"
  },
...

우선 package.json에 다음과 같은 설정들을 추가해준다. 모든 값이 필수값은 아니지만 명시해주면 좋을 것 같은 값들은 적어놓았다.

# .npmignore

node_modules/
.eslintrc.js
.prettierrc
rollup.config.js
tsconfig.json
tsconfig.paths.json
yarn.lock

작업 디렉터리에 있는 모든 파일을 npm에 배포할 필요는 없다. 그렇기 때문에 .npmignore라는 파일을 만들어 배포 시 제외할 파일들을 명시해놓는다.

일반적으로 package.json파일을 제외한 나머지 설정파일들은 필요가 없기 때문에 모두 제외시켜주었다.

npm 배포

이제 npm에 라이브러리를 배포하기 위해서는 우선 npm 계정이 필요하다. 계정이 없다면 npm홈페이지에서 회원가입을 진행해야 한다. https://www.npmjs.com/

cd project

npm login

계정이 준비되었다면 다음 명령어를 통해 프로젝트 폴더로 이동 후 npm에 로그인을 한다.

npm publish --access=public

로그인이 완료되면 다음 명령어를 통해 npm에 라이브러리를 배포할 수 있다. 다만, 배포할 패키지 명에 @cyjo/util과 같이 @가 포함되는 폴더형태로 이름을 작성하면 에러가 발생한다.

1.png

그렇다면 npm홈페이지에서 다음 Add Organization을 통해 @앞에 표기할 organization을 생성 후 진행하면 에러가 발생하지 않는다.

2.png

그러면 다음과 같이 npm에 정상적으로 라이브러리가 배포된 것을 확인할 수 있다.

본 포스트는 다음 문서를 참고해 작성했습니다.

https://rollupjs.org/guide/en/

https://flamingotiger.github.io/frontend/DevEnv/rollup-setup/