소개
최근 @devcomfort/text-transcoder
v0.3
업데이트를 진행했습니다.
v0.3
패치는 v0.2
의 타입스크립트 앰비언트 파일(d.ts) 인식 불가 이슈로 발생하는 불완전한 타입스크립트 지원을 보완하는 패치였습니다.
이번 포스트에서는 제가 겪은 이슈를 해결하는 과정과 함께 조건부 내보내기 conditional exports
의 사용법과 타입스크립트 라이브러리를 배포하기 위한 설정법을 공유하려고 합니다.
주의사항
이 문서는 package.json
과 tsconfig.json
에 대한 이해도가 부족하다면 이해하기 힘들 수 있습니다.
사전지식: Conditional Exports가 뭔가요?
Node.js v12부터 추가된 기능입니다.
ECMAScript(ESM)과 CommonJS(CJS) 등 라이브러리 사용자의 프로젝트 상황에 다른 코드를 내보내야 하는 경우, 요청 경로에 따라 다른 스크립트 코드를 제공해야 하는 경우 등
프로젝트 환경에 따라 다양한 코드를 상황에 맞게 제공해야 하는 경우에 사용됩니다.
Conditional Exports는 package.json
내부에 exports
필드를 설정하여 사용할 수 있으며, 사용자가 접근 하는 경로
를 기준으로 다양한 내보내기 설정을 입력할 수 있습니다.
자세한 내용은 해결 과정에서 소개하고 있습니다.
v0.2 이슈 소개
@devcomfort/text-transcoder v0.2
의 이슈는 package.json에 이미 types
필드를 설정했음에도 사용 시 타입 힌트가 인식되지 않았던 문제였습니다.
해결 과정
이슈 해결을 위해 다음 내용을 추가하였습니다.
tsconfig.json
에declaration
필드를 설정하여 빌드 시 자동으로 타입 힌트 파일(d.ts)이 빌드되도록 설정하였습니다.package.json
exports
필드를 추가하여 조건부 내보내기를 추가하였습니다.
1. tsconfig.json
설정하기: declaration
필드 설정
tsconfig.json
에서 declaration
필드를 true
로 설정하면 빌드 시 자동으로 앰비언트 파일이 빌드되도록 설정할 수 있습니다.
반대로 false
로 설정하면 앰비언트 파일이 생성되지 않습니다.
아래와 같이 설정하고 빌드하며 결과물에 앰비언트 파일을 추가할 수 있습니다.
json
{// ..."compilerOptions": {// ..."declaration": true// ...}// ...}
2. package.json
설정하기: exports
필드 설정: Conditional Exports 추가
package.json
내에 exports
필드 설정을 추가하면 ECMAScript(ESM), CommonJS(CJS) 상황에 맞게 다른 파일을 제공하도록 라이브러리를 개발할 수 있습니다.
Conditional Exports 설정상의 주의점: 완벽한 상대경로의 필요
exports
필드 설정을 위해서는 진입 경로
를 기본으로 설정해야 합니다.
진입 경로
는 상대 경로
로 지정해야 하며, .
으로 시작해야 합니다.
예를 들어 package.json
파일을 기준으로 동일한 경로에 위치한 index.js
를 가리키려면 ./index.js
로 설정해야 하고 src
디렉토리 내의 index.js
를 가리키려면 ./src/index.js
설정해야 합니다.
exports
필드는 위와 같이 .
으로 시작하는 완벽한 상대경로만 인식합니다.
Conditional Exports 내용 설정하기
진입 경로를 설정한 후에는 node
, default
, types
, require
, import
와 같은 5가지 조건 설정을 원하는대로 적용할 수 있습니다.
필요하지 않은 설정은 생략할 수 있습니다.
node
: Node.js를 통해 라이브러리에 접근할 때,node
필드 값에 해당하는 경로의 JavaScript 코드가 로드됩니다.default
: 환경과 무관하게 기본적으로default
필드 값에 해당하는 경로의 JavaScript 코드가 로드됩니다.types
: 타입스크립트와 호환되는 선언 파일을 사용하려면types
필드 값에 해당 파일의 경로를 입력해야 합니다. 이렇게 선언하면 진입 경로에 맞춰 해당 타입 힌트가 적용됩니다.require
: CommonJS(CJS) 환경에서 사용할 JavaScript 코드의 경로를 지정하면, 해당 경로의 JavaScript 코드가 로드됩니다.import
: ECMAScript(ESM) 환경에서 사용할 JavaScript 코드의 경로를 지정하면, 해당 경로의 JavaScript 코드가 로드됩니다.
다음은 라이브러리의 .
경로를 호출하는 상황을 가정하여 ESM/CJS 지원, 타입스크립트 지원이 가능한 package.json
코드를 작성하였습니다.
@devcomfort/text-transcoder v0.3 패치 노트의 예시를 그대로 사용하였으며,
일반적으로 라이브러리를 배포하기 위해 빌드된 파일은 dist
폴더에 저장하기 때문에 아래와 같이 작성하였습니다.
json
{// ..."exports": {// "기본 경로를 호출하는 경우"".": {"import": "./dist/esm/index.js", // ECMAScript(ESM) 기반 프로젝트에서는 ./dist/esm/index.js 경로의 코드를 제공합니다."require": "./dist/cjs/index.js", // CommonJS(CJS) 기반 프로젝트에서는 ./dist/cjs/index.js 경로의 코드를 제공합니다."types": "./dist/index.d.ts" // 타입 힌트는 ./dist/index.d.ts 경로의 파일을 기반으로 제공합니다.}}// ...}
Conditional Exports의 동작 이해하기: 설정한 상대 경로가 실제로 어떻게 동작할까요?
json
{"exports": {".": {"import": "./dist/esm/index.js","require": "./dist/cjs/index.js","types": "./dist/index.d.ts"}}}
위와 같이 @devcomfort/text-transcoder v0.3 프로젝트에서는 .
경로를 기준으로 하였지만, ./dist
경로 설정했다고 가정할 수도 있습니다.
.
, ./dist
2가지 설정에 따라 사용자의 호출 코드가 어떻게 동작하는지 보여드리겠습니다.
라이브러리 이름이 @devcomfort/text-transcoder
인 경우:
exports
경로를.
로 설정하면 (위에서 제시된 설정):javascript// ECMAScript(ESM)import { reEncode } from '@devcomfort/text-transcoder'// CommonJS(CJS)const { reEncode } = require('@devcomfort/text-transcoder')exports
경로를./dist
로 설정하면 (.
→./dist
로 경로 변경):javascript// ECMAScript(ESM)import { reEncode } from '@devcomfort/text-transcoder/dist'// CommonJS(CJS)const { reEncode } = require('@devcomfort/text-transcoder/dist')
경로를 변경하면 위와 같이 호출할 때의 경로가 변경되게 됩니다.
위의 예시를 참고하면 더욱 올바른 조건부 내보내기(conditional exports) 설정을 할 수 있을 것이라 기대합니다.