본문 바로가기
프론트엔드

npm 라이브러리를 만들어보자!

반응형

안녕하세요, 메리입니다.

개발 공부를 하다 보면 '우와! 언젠간 이런것도 <경험>해보고 싶다'라는 생각을 종종 하곤 하는데요.

 

그중에서도 저는 제가 만든 라이브러리를 배포해보고 싶었습니다. 

그래서 시간적 여유가 있는 지금, 라이브러리를 하나 만들어 보았습니다. 


1. npm이란?

 

npm이란 노드 패키지 매니저(Node Package Manager)로 말 그대로 노드 패키지를 관리해 주는 툴입니다.

npm을 사용하면 개발자들이 자바스크립트로 만든 다양한 패키지를 온라인 데이터 베이스에 올리고 패키지 관리자를 통해 설치 및 삭제가 가능합니다. 

이때 패키지들의 의존성 관리가 중요한데(하나의 문제가 발생하면 다른것도 영향을 받음), 그래서 이를 관리하기 위해 package.json이 사용됩니다.

 

2. npm 회원가입

패키지를 만들기 전 npm계정이 없다면, 먼저 계정을 생성해 줍니다. 

 

npm | Home

Bring the best of open source to you, your team, and your company Relied upon by more than 17 million developers worldwide, npm is committed to making JavaScript development elegant, productive, and safe. The free npm Registry has become the center of Java

www.npmjs.com

 

3. npm 배포

먼저 사전에 만들어 둔, 소스코드가 없다는 가정 하에 예제 코드로 배포하는 방법을 포스팅해보겠습니다. 

 

1. 원하는 이름으로 된 폴더를 생성합니다. 저는 'npm-test-merry' 라는 폴더를 생성했습니다.

2. npm을 설치 후, 초기설정을 진행합니다.

npm init

package name: (npm-test-merry)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)

Is this OK? (yes)

 

3. 배포를 위한 package.json을 수정합니다. 자세한 내용은 공식 문서를 참고합니다. 저는 대충 아래 예제 정도로만 수정해두었습니다.

{
  "name": "npm-test-merry",
  "version": "0.0.1",
  "main": "index.js",
  "license": "MIT"
}

 

name : npm이 배포될 때 사용되는 이름입니다. 중복이 있으면 배포 시 에러가 발생하니 npm에 사용하고 싶은 이름을 검색해 미리 확인해 보시는 걸 추천드립니다.

version : 배포할 때 사용되는 버전입니다. 각 자릿수는 순서대로 'major'-'minor'-'patch' 버전을 의미합니다.

main : 라이브러리를 사용할 때 기본 진입점입니다. 

license : 라이브러리의 라이센스를 의미합니다. 라이센스의 종류는 많으니 공식문서를 참고하시길 바랍니다. 

 

4. index.js 파일을 생성해 아래와 같이 작성합니다.

function Hello() {
  return "Hello, I am free dobby!";
}

module.exports = {
  Hello,
};

 

5. npm 로그인 후, 배포해 줍니다.

npm login //npm 로그인

npm publish //npm 배포

 

정상적으로 배포되면 위와 같은 모습을 확인할 수 있습니다. 또한, npm 사이트의 계정 packages에서도 확인 할 수 있습니다. 

 

6. 배포한 패키지 사용해 보기 

 npm i npm-test-merry

 

여러분이 배포한 라이브러리를 설치합니다. 설치가 정상적으로 된다면,

package.jsonpackage-lock.json, node-modules 폴더에서 확인할 수 있습니다.

 

그리고 index.js에서 라이브러리를 실행시키기 위해, index.js에 아래와 같이 작성합니다.

const { Hello } = require("npm-test-merry");

console.log(Hello());

 

실행시켜 보면 아래와 같이 작동하는 걸 확인할 수 있습니다. 

node index.js


4. ES Module 지원

앞서 우리가 만든 라이브러리는 CommonJs 형태로 작성되었는데요. CommonJs(CJS) 외에도 여러 모듈 시스템이 존재합니다.

CJS, AMD, UMD, ESM에 대해 순서대로 알아봅니다. 

 

- CJS(CommonJS)

CJS는 NodeJS에서 지원하는 모듈 시스템으로 알려져 있습니다. 

모듈을 불러올 때는 require을 통해 동기적으로 불러오고, 내보낼 때는 module.exports를 사용합니다. 

(저희가 아까 이 방식으로 모듈을 불러오고, 내보냈습니다.)

 

module.exports는 전역 스코프로 취급되기 때문에 보안성을 해치는 단점이 있습니다. 

불러온 모듈을 수정하면 해당 모듈을 사용하는 다른 곳에도 영향을 끼칠 수 있습니다. 

 

- AMD(Asynchronous Module Definition)

NodeJS에서 > 브라우저 환경에도 적합한 모듈 시스템의 필요성이 커지면서 등장하게 된 모듈 시스템입니다. 

AMD는 어플리케이션의 성능을 위해 모듈을 비동기적으로 불러옵니다. 

모듈을 불러올 때는 require를 통해 비동기적으로 불러오고, 내보낼 때는 define을 사용합니다. 

//moduleAMD.js
define(function () {
  return function () {
    console.log("Hello dobby");
  };
});

require(["moduleAMD"], function (moduleAMD) {
  moduleAMD();
});

 

- UMD(Universal Module Definition)

자바스크립트 입장에서는 어느 환경에서 모듈을 실행할지 알 수 없기 때문에 각각의 형태(NodeJS(CJS) / 브라우저(AMD) 모듈)을 모두 지원해야 했습니다. 이러한 문제를 해소하고자 UMD가 등장하였습니다. 

 

- ESM(ECMAScript Modules)

ESM은 별도의 설정 없이 브라우저 환경의 지원을 받아 실행할 수 있는 모듈 시스템입니다. 

모듈을 불러올 때는 import를 통해 비동기적으로 불러오고, 내보낼 때는 export를 사용합니다. 

 

다른 모듈 시스템과 다르게 정적 분석을 통해 모듈을 관리하여 빌드 단계에서 사용하지 않는

코드를 번들에서 제외하는 트리 쉐이킹(Tree Shaking)이 가능합니다. 

 

살펴본 바로는 모듈 시스템은 기본적으로 동작이 다르고, 호환되기 어렵습니다. 

때문에 CJS, ESM에 모두 대응하는 라이브러리를 개발할 필요가 있습니다. 

 

우선 기존에 만든 라이브러리를 ESM을 지원하도록 수정해 봅시다. 

기존에 작성한 package.json에서 "type" : "module"을 추가해 줍니다.

 

type 필드에는 'commonjs'와 'module' 두 가지 속성이 있고, 각각 CJS, ESM을 가리킵니다. 

{
  "name": "npm-test-merry",
  "version": "0.0.1",
  "type": "module",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "npm-test-merry": "^0.0.1"
  }
}

 

수정 후에는 patch 버전을 올려준 후 재배포해줍니다. 버전을 올리지 않으면 배포 시 오류가 나니 주의해 주세요.

npm version patch

npm publish

 

배포 후에는 설치한 라이브러리의 버전을 올리고(최신 버전으로 재설치) 테스트를 해줍니다.

import { Hello } from "npm-test-merry";

console.log(Hello());

 

하지만, CJS와 ESM 둘 중 하나만 쓰는 프로젝트만(있다면 얼마나 좋을까요? 터벅...) 있는 것은 아니기 때문에

두 방식 모두 대응하는 라이브러리를 개발해야 합니다.


5. ESM + CJS 지원

CJS과 ESM을 동시에 지원하기 위해서는 package.json의 export 필드를 추가해주어야 합니다. 

export 필드는 상대경로로 작성되어야 하고 해당 경로는 라이브러리의 subpath를 의미합니다.

{
  "exports": {
    ".": {
      "import": "./index.js", // esm 환경
      "require": "./index.cjs", // cjs 환경
      "default": "./index.js" // default 환경
    }
  }
}

 

이런 식으로 작성하면 두가지 방식으로 사용가능한 라이브러리를 만들 수 있습니다.

import { Hello } from "npm-test-merry"; // ESM

const { Hello } = require("npm-test-merry"); // CJS

 

이런식으로 간단한 라이브러리를 배포해 보았습니다. 

다음 포스팅에서는 Typescript 지원Github Actions를 사용한 배포 자동화에 대해서 다뤄보고자 합니다. 

 

제가 만든 라이브러리는 아래에서 확인하실 수 있습니다. 

 

ios-react-time-picker

ios style time picker for React app.. Latest version: 0.2.2, last published: 18 hours ago. Start using ios-react-time-picker in your project by running `npm i ios-react-time-picker`. There are no other projects in the npm registry using ios-react-time-pick

www.npmjs.com

반응형