포스트

npm 패키지 제작기 4

패키지 업데이트

패키지 배포를 한 후에 기능들을 업데이트하고, typescript 도 적용했다.

해당 내용을 버전과 함께 업데이트 해보자.

패키지 버전 업데이트

패키지 버전 업데이트를 위해선 package.json에 명시된 버전을 수정하고, 재배포하면 된다.

npm 에서 package.json의 버전 업데이트를 위한 명령어를 제공한다.

1
2
3
4
5
# 1. 버전 업데이트
npm version x.x.x

# 2. 패키지 재배포
npm publish

TypeScript 설정

수많은 삽질 끝에 TypeScript 설정법을 알아냈다.

나 말고 대부분의 경우는 아마 TypeScript 파일로 개발하고, tsc를 통해 js 파일과 type 명시 파일을 생성하는 방법을 사용하는 것 같다.

나같은 경우는 이미 js 패키지로 만들어 놓은 상태라서, 여기에 type 명시 파일만 추가해주면 된다.

대부분 type 명시 파일은 파일명.d.ts 형태로 네이밍을 하고, 여기에 type을 명시한다.

명시해야 할 내용은 모듈 파일(cjs, mjs)에 있는 export 에 사용되는 내용의 type이다.(사용자가 불러와서 사용할 수 있는 것들)

예를 들어 다음과 같은 모듈이 있다고 가정하자.

1
2
3
4
5
6
7
8
9
10
// common js module

/**
 * input name, age. Then print info.
 * @param {string} name person's name
 * @param {number} age person's age
 */
exports.person = (name, age = 20) => {
    return `name : ${name}, age : ${age}`;
};

위 모듈이 제공하는 함수 person 에 대한 type을 지정해줘야 한다.

이 경우에는 다음과 같은 내용을 작성하면 된다.

1
2
3
4
5
6
/**
 * input name, age. Then print info.
 * @param {string} name person's name
 * @param {number} age person's age
 */
declare function person(name: string, age?: number)

cjs, esm

모듈을 사용하거나 제공하는 방식을 알아야 내가 만들 모듈 내부에서도 다른 모듈을 불러와서 쓸 수 있고, 최종적으로는 사용자에게 제공할 수 있다.

자바스크립트의 모듈에는 2가지 종류 CJS(Common JS Module), ESM(ECMA Script Module)이 있는데, 관련된 내용은 알아보고 포스트를 따로 게시해야겠다.

간단하게 사용법만 말하자면

cjs(common js)의 경우에는 requiremodule.exports 를 사용한다.

esm(ECMA Script module)의 경우에는 importexport 를 사용한다.

이를 더 쉽게 이해하기 위해, 간단한 예시를 들어보자.

내가 만든 모듈의 함수 중 하나의 코드를 가져와서 알아보겠다.

CJS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const {parse} = require("marked");
const prettify = require("@liquify/prettify");

/**
 * parse Markdown Text to Grouped Html text.
 * @param {string} markdownText text data written in markdown syntax
 * @param {number} minLevel min level to start grouping
 * @param {string} selector Selector that you want to use between id and class.(Possible values - All upper or lower cases of "class" and "id")
 * @param {string} prefix prefix string of class or id.( "_" -> \<section class="_h1-1"> )
 * @param {string} postfix postfix string of class or id.( "--" -> \<section class="_h1--1"> )
 * @returns {string} html text data grouped by section tag
 */
exports.parseToGroup = (markdownText, minLevel=1, selector="id", prefix="_", postfix="-") => {
    selector = selector.toLowerCase();
    if(!["id", "class"].includes(selector.toLowerCase())) {
        throw new Error(`"${selector}" is invalid name for a selector.`);
    }

    markdownText = encodeHeaderTag(markdownText);
    const html = parse(markdownText);
    const resultBeforeDecode = prettify.formatSync(findHeader(html, minLevel, 1, "", selector, prefix, postfix), {
        language: 'html',
        indentSize: 2
      });
    const result = prettify.formatSync(decodeHeaderTag(resultBeforeDecode), {
        language: 'html',
        indentSize: 2
      });

    return result;
}

최상단 부분의 코드가 바로 사용할 모듈을 불러오는 코드이다. 보이는대로 require 함수를 사용해 필요한 모듈을 불러오고 있다.

아래의 코드에서 exports.parseToGroup 이라는 곳에 함수를 선언했다.

이는 parseToGroup 이라는 함수를 내가 사용자에게 제공하겠다 라는 뜻이다. CJS에서 exports 란 사용자에게 제공할 객체 그 자체로 생각하면 쉬울 것 같다.

따라서 사용자 입장에서는 내가 제공한 함수를 아래와 같이 사용할 수 있다.

1
2
3
const { parseToGroup } = require("모듈이름");

parseToGroup(...)

ESM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import {parse} from "marked";
import prettify from "@liquify/prettify";

/**
 * parse Markdown Text to Grouped Html text.
 * @param {string} markdownText text data written in markdown syntax
 * @param {number} minLevel min level to start grouping
 * @param {string} selector Selector that you want to use between id and class.(Possible values - All upper or lower cases of "class" and "id")
 * @param {string} prefix prefix string of class or id.( "_" -> \<section class="_h1-1"> )
 * @param {string} postfix postfix string of class or id.( "--" -> \<section class="_h1--1"> )
 * @returns {string} html text data grouped by section tag
 */
export const parseToGroup = (markdownText, minLevel=1, selector="id", prefix="_", postfix="-") => {
    selector = selector.toLowerCase();
    if(!["id", "class"].includes(selector.toLowerCase())) {
        throw new Error(`"${selector}" is invalid name for a selector.`);
    }

    if(!markdownDoc) {
        markdownDoc = new MarkdownDocument();
    }

    markdownDoc.setDocument(false, markdownText, minLevel, 1, "", selector, prefix, postfix);

    return markdownDoc.html;
}

CJS와 다른점은 내가 사용할 모듈을 불러올 때는 import ~ from ~ 코드를 사용하고, 사용자에게 제공할 때는 export 키워드를 사용하고 뒤에 제공할 내용을 적어주면 된다. 특이한 점은 이 때 선언(declaration) 형식으로 적어주어야 한다는 점이다. export const ~, export let ~, export function ~ 이런 식으로 말이다.


참조

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.