내가 계속 배포한 패키징 버그 (그리고 이를 멈추기 위해 만든 도구)
Source: Dev.to
무엇이 잘못되었는가
1. CJS/ESM 형식 불일치
package.json에 다음과 같이 적혀 있습니다:
{
"exports": {
"require": "./dist/cjs/index.cjs"
}
}
하지만 ./dist/cjs/index.cjs 파일 안에는 import/export 구문이 들어 있습니다—즉 실제로는 ESM입니다.
Webpack과 esbuild는 문제 없이 동작하지만 Node.js는 ERR_REQUIRE_ESM 오류를 발생시킵니다. 이는 빌드 도구가 CJS를 목표로 했음에도 불구하고 ESM 구문을 출력할 때 발생합니다.
2. 조건 순서가 잘못됨
{
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
"types"는 첫 번째에 와야 합니다. TypeScript는 조건을 위에서 아래로 순차적으로 확인하고 첫 번째 매치에서 멈춥니다. 여기서는 "import"가 먼저 매치되어 "types"를 전혀 보지 못하고, 모든 것에 대해 any를 추론하게 됩니다.
3. 서브패스에 대한 선언 파일 누락
{
"exports": {
"./utils": "./dist/utils.js",
"./hooks": "./dist/hooks.js"
}
}
dist/utils.d.ts(또는 dist/hooks.d.ts) 파일이 존재하지 않으면, your-package/utils와 같이 서브패스를 import 하는 소비자는 any 타입이 되거나 “cannot find module” 오류가 발생합니다. 직접 소스 파일을 import 하는 자체 테스트는 통과할 수 있어, 문제가 보고될 때까지 눈치채지 못합니다.
도구
나는 tspub을 만들어 이러한 문제들을 잡아냅니다. 이 도구는 exports, types, files, metadata, imports, package size 등 약 70개의 규칙을 검사합니다.
$ npx @tspub-dev/tspub check
exports/format-mismatch ./dist/cjs/index.cjs contains ESM syntax
exports/types-first "types" should be first in conditions
types/no-any-export ./dist/index.d.ts exports 12 `any` types
3 problems (1 auto-fixable)
눈에 띄는 규칙
exports/cjs-esmodule-interop–__esModule플래그를 사용하는 CJS 파일을 감지합니다. 이 파일들은 Webpack, Node, esbuild에서 동작 방식이 다릅니다.types/no-any-export– 선언 파일에서any타입이 과도하게 사용된 경우를 표시합니다(대개 빌드 도구 설정 오류).exports/format-mismatch– 파일 확장자만 보는 것이 아니라 실제 파일 내용을 읽어 형식을 검증합니다.files/sensitive–.env, 개인 키, 자격 증명 등 민감한 파일이 실수로 배포 패키지에 포함되는 경우를 잡아냅니다.
자동 수정
$ npx @tspub-dev/tspub check --fix
조건 순서를 안전하게 재배열하고, 기타 사소한 문제들을 자동으로 고칩니다.
패키지를 설치하지 않고 검사하기
웹 버전이 제공됩니다: tspub.dev/check/YOUR-PACKAGE 를 통해 npm 패키지를 즉시 검증할 수 있습니다.
검사 외 기능
tspub은 빌드, 타입 선언 테스트, 새 패키지 스캐폴딩, 배포까지 모두 처리합니다.
tspub init # 올바르게 설정된 패키지 스캐폴드
tspub build # ESM + CJS + .d.ts 생성
tspub check # 70개 규칙 검증
tspub test-types # 타입 수준 테스트 러너
tspub publish # npm + GitHub 릴리즈
여러 패키지에서 빌드, 린트, 타입 테스트, 배포 설정을 각각 관리하던 것이 감당하기 어려워졌기에, 나는 이 모든 기능을 하나의 도구로 통합했습니다. 체크 기능은 다른 기능을 사용하지 않더라도 독립적으로 동작합니다.
GitHub
npm: npm i -D @tspub-dev/tspub
Web: https://tspub.dev/