Category: reference
package.json Modern Fields — exports, type, engines
Fields สำคัญใน package.json สำหรับ modern npm packages: exports map, type: module, engines, files, และ npm publish workflow
สารบัญ
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[])
]
}
fileswhitelist สิ่งที่จะ publish — สิ่งที่ไม่ได้ระบุจะไม่ถูก upload
.npmignoreเป็น blacklist (ถ้ามีfilesfield จะใช้แทน.npmignore)
สิ่งที่ถูก include เสมอ:
package.jsonREADME.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"
}
}