Published on

package.json 정리

Authors
  • avatar
    Name
    sulmo
    Twitter

exports와 files 옵션

**1. exportsfiles **

exports

  • 목적: 다른 워크스페이스에서 특정 파일들만 노출하거나, API 표면만 제한적으로 공개하고 싶을 때.
  • 장점:
    • 패키지 외부에서 사용할 수 있는 경로를 명시적으로 제어.
    • 노출할 경로를 지정하여 의도치 않은 파일 사용을 방지.
    • ESM과 CommonJS 모듈 시스템을 동시에 지원 가능.
{
  "type": "module", // 기본 모듈 타입을 ESM으로 설정
  "exports": {
    "./module": {
      "require": "./dist/module.cjs", // CJS 파일
      "import": "./dist/module.js" // ESM 파일
    }
  }
}


// 위와 같이 모듈타입별로 파일을 작성하여 내보내야한다.
  • 단점:
    • 모든 사용 가능한 파일 경로를 세밀히 정의해야 하므로, 관리 포인트가 늘어날 수 있음.

예: 특정 경로만 노출하고 싶다면 다음과 같이 설정:

{
  "exports": {
    ".": "./index.js",
    "./utils": "./src/utils.js",
    "./config": "./src/config.js"
  }
}
  • 이렇게 하면, require('package-name/utils')는 동작하지만, require('package-name/src/other-file.js')는 접근할 수 없음.

files가 적합한 경우

  • 목적: 패키지를 **배포(npm publish)**하거나, 디스크 공간을 절약하고자 특정 파일만 포함하려고 할 때.
  • 장점:
    • 배포 크기를 줄이기 위해 필요한 파일만 포함 가능.
    • 외부 사용과는 무관하며, 배포 아카이브의 크기 최적화에 도움.
  • 단점:
    • 파일 노출에는 영향을 미치지 않음. 단지 배포 크기만 제어.

예: 필요한 파일만 배포하고 싶다면 다음과 같이 설정:

{
  "files": ["index.js", "src/", "config/*.json"]
}
  • 이렇게 하면 index.js, src/ 디렉토리, 그리고 config 디렉토리의 .json 파일만 배포됩니다.
  • 하지만 파일이 배포되었더라도, exports가 정의되어 있으면 접근 제한이 적용됩니다.

모노레포에서는 보통 exports가 더 적합

  • 다른 워크스페이스에서 사용할 때도 API 표면만 노출하고 나머지 파일을 숨길 필요가 있기 때문.
  • 모듈이 확장될 경우, 특정 경로가 외부에 노출되거나 의도치 않은 파일을 참조할 위험을 줄일 수 있음.

2. 아무 세팅도 안 되어 있으면 기본 동작은?

a) exports가 없는 경우

  • 모든 파일이 노출됩니다.
  • 다른 워크스페이스나 외부 패키지에서 require() 또는 import로 패키지 내부의 모든 파일과 경로에 접근할 수 있습니다.
  • 예를 들어, 아래와 같은 디렉토리 구조라면:
package/
├── index.js
├── utils/
│   ├── helper.js
└── config/
	└── settings.json

다른 워크스페이스에서 다음과 같이 모두 접근 가능합니다:

const helper = require('package/utils/helper')
const settings = require('package/config/settings.json')

b) files가 없는 경우

  • 기본적으로 .npmignore(또는 .gitignore) 파일이 적용됩니다.
  • .npmignore가 없으면, 모든 파일이 npm 패키지에 포함됩니다.
  • 그러나 파일이 배포되더라도, 이는 노출 범위와는 무관하며, 실제로 다른 워크스페이스에서 파일을 사용 가능 여부는 exports 설정 여부에 따라 결정됩니다.

c) exportsfiles 모두 없는 경우

  • Node.js: 모든 파일이 노출됩니다.
  • npm 배포: .npmignore나 기본 규칙에 따라 모든 파일이 포함됩니다.

3. 모노레포에서 최적의 설정

모노레포에서 다른 워크스페이스가 패키지를 참조할 때 exports를 설정하는 것이 더 중요합니다.
files는 주로 npm registry로 배포할 때 크기를 줄이기 위한 용도로 사용됩니다.

권장 설정

  1. 필요한 API 표면만 노출 (exports):

    • 내부 구현 파일이 외부에서 참조되지 않도록 보호.
    • 패키지의 명확한 API 표면을 제공.
    • 예:
{
  "exports": {
    ".": "./index.js",
    "./utils": "./src/utils.js",
    "./config": "./src/config.js"
  }
}
  1. 배포 크기 제어 (files):

    • 불필요한 파일을 배포에서 제외.
    • 예:
{
  "files": ["index.js", "src/", "README.md"]
}
  1. ESM 및 CommonJS 동시 지원:

    • 모듈 시스템 간 호환성을 고려.
    • 예:
{
  "type": "module",
  "exports": {
    ".": {
      "import": "./index.mjs",
      "require": "./index.cjs"
    }
  },
  "main": "./index.cjs"
}

peerDependencies

peerDependencies vs dependencies vs devDependencies

  • dependencies: 패키지가 동작하기 위해 반드시 설치되어야 하는 의존성.
  • devDependencies: 개발 환경에서만 필요한 의존성 (예: 빌드 도구, 테스트 라이브러리).
  • peerDependencies: 패키지가 다른 패키지와 함께 동작하도록 요구하는 의존성. 설치는 사용자에게 맡김.

"사용자에게 설치를 맡긴다"의 의미

peerDependencies는 의존성 패키지가 설치될 환경(사용자의 프로젝트)에 따라 다른 버전이 필요할 수 있는 경우에 사용됩니다. 따라서 패키지를 사용하는 최종 사용자가 직접 해당 패키지를 명시적으로 설치하도록 설계된 것입니다.

예시

  1. 라이브러리 제작자의 입장:

    json

    복사편집

    { "name": "my-library", "peerDependencies": { "react": "^17.0.0" } }

    • my-libraryreact가 필요하다고 명시합니다.
    • 하지만 react를 직접 설치하지 않습니다. (프로젝트의 React 버전은 사용자에 따라 다를 수 있기 때문입니다.)
  2. 라이브러리를 사용하는 사용자 입장:

    • 사용자가 my-library를 설치할 때, react가 프로젝트에 없으면 npm은 경고를 출력하거나(혹은 npm 7 이상에서는 충돌하지 않는 범위에서 자동 설치) 오류를 발생시킵니다.
    • 사용자는 명시적으로 자신의 프로젝트에 맞는 react 버전을 설치해야 합니다. bash 복사편집 npm install react@17 react-dom@17