ข้ามไปเนื้อหาหลัก

Category: reference

package.json Modern Fields — exports, type, engines

Fields สำคัญใน package.json สำหรับ modern npm packages: exports map, type: module, engines, files, และ npm publish workflow

· อ่านประมาณ 3 นาที

สารบัญ

exports — Package Entry Points

// package.json
{
  "name": "my-lib",
  "version": "1.0.0",

  // ✓ exports map (Node 12+ / Bundlers)
  "exports": {
    ".": {
      "import": "./dist/index.mjs",    // ESM
      "require": "./dist/index.cjs",   // CommonJS
      "types": "./dist/index.d.ts"     // TypeScript
    },
    "./utils": {
      "import": "./dist/utils.mjs",
      "require": "./dist/utils.cjs",
      "types": "./dist/utils.d.ts"
    },
    "./package.json": "./package.json"  // ให้ access ได้
  },

  // Legacy fallback (Node 10 หรือ bundler เก่า)
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts"
}
// Consumer import
import { helper } from 'my-lib';          // → dist/index.mjs (ESM)
const { helper } = require('my-lib');     // → dist/index.cjs (CJS)
import { util } from 'my-lib/utils';      // → dist/utils.mjs
import 'my-lib/no-exist';                 // ❌ Error (exports map ไม่มี key นี้)

type: module

{
  "type": "module"   // ✓ ทำให้ .js files เป็น ESM by default
                     // ถ้าต้องการ CJS ใช้ .cjs extension แทน
}
{
  "type": "commonjs"  // default — .js files เป็น CJS
                       // ถ้าต้องการ ESM ใช้ .mjs extension
}

files — ควบคุมสิ่งที่ publish

{
  "files": [
    "dist/",       // ✓ include
    "!dist/**/*.map"  // ✗ exclude source maps (ไม่ได้ผลใน files[])
  ]
}

files whitelist สิ่งที่จะ publish — สิ่งที่ไม่ได้ระบุจะไม่ถูก upload
.npmignore เป็น blacklist (ถ้ามี files field จะใช้แทน .npmignore)

สิ่งที่ถูก include เสมอ:

  • package.json
  • README.md, CHANGELOG.md, LICENSE
  • ไฟล์ที่ระบุใน main, module, types

สิ่งที่ถูก exclude เสมอ:

  • node_modules/
  • .git/, .github/
  • src/ (ถ้าไม่ได้ระบุใน files)
  • test files

engines — ระบุ Node.js version

{
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  }
}

scripts ที่ควรมี

{
  "scripts": {
    "build": "tsc && rollup -c",
    "build:check": "tsc --noEmit",
    "test": "vitest",
    "lint": "eslint src",
    "prepublishOnly": "npm run build && npm test",
    "release": "npm version patch && npm publish"
  }
}

prepublishOnly รันอัตโนมัติก่อน npm publish — ป้องกันการ publish โดยไม่ได้ build


TypeScript: tsconfig สำหรับ Library

// tsconfig.json สำหรับ build library
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,           // สร้าง .d.ts
    "declarationMap": true,        // source maps สำหรับ .d.ts
    "sourceMap": true,
    "strict": true,
    "stripInternal": true          // ลบ @internal comments ออกจาก .d.ts
  },
  "include": ["src"],
  "exclude": ["**/*.test.ts", "**/*.spec.ts"]
}

Dual Package (CJS + ESM) ด้วย tsup

npm install --save-dev tsup
// tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts', 'src/utils.ts'],
  format: ['cjs', 'esm'],   // build ทั้ง CJS และ ESM
  dts: true,                // สร้าง .d.ts
  splitting: true,          // code splitting
  clean: true,              // ลบ dist/ ก่อน build
  sourcemap: true,
});
// package.json — ผล output จาก tsup
{
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  }
}

npm Publish Workflow

# 1. ตรวจดูว่า publish อะไร
npm pack --dry-run

# 2. ดู size ของ package
npm pack && tar -tf *.tgz

# 3. bump version (ตาม semver)
npm version patch   # 1.0.0 → 1.0.1 (bug fix)
npm version minor   # 1.0.0 → 1.1.0 (new feature, backward compatible)
npm version major   # 1.0.0 → 2.0.0 (breaking change)

# 4. publish
npm publish

# 5. publish beta version
npm version 1.1.0-beta.1 --no-git-tag-version
npm publish --tag beta

# Consumer ติดตั้ง beta:
npm install my-lib@beta

Semantic Versioning

MAJOR.MINOR.PATCH

1.0.0  → 1.0.1  patch: bug fix, ไม่เพิ่ม feature
1.0.0  → 1.1.0  minor: feature ใหม่, backward compatible
1.0.0  → 2.0.0  major: breaking changes (API เปลี่ยน)

Pre-release:
1.0.0-alpha.1    ทดสอบภายใน
1.0.0-beta.1     ทดสอบกับ users จำกัด
1.0.0-rc.1       release candidate ก่อน stable

Range syntax ใน package.json:
^1.2.3   → >=1.2.3 <2.0.0  (minor + patch updates)
~1.2.3   → >=1.2.3 <1.3.0  (patch updates only)
1.2.3    → exact version
*        → latest (อันตราย)

.npmrc สำหรับ Scoped Packages

# .npmrc
@myorg:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
// package.json
{
  "name": "@myorg/my-lib",
  "publishConfig": {
    "registry": "https://npm.pkg.github.com",
    "access": "public"
  }
}