$npx -y skills add rstackjs/agent-skills --skill rslib-modern-packageOpinionated Rslib recommendations for modern JS/TS npm package design covering pure ESM, strict TypeScript, explicit exports, small stable APIs, pragmatic dependencies, accurate sideEffects, correct declarations, package validation, provenance, README.md, and AGENTS.md. Use when
| 1 | # Rslib Modern Package |
| 2 | |
| 3 | Use this skill when creating a new Rslib library, modernizing an existing JS/TS package, or reviewing a package against an opinionated modern library standard. |
| 4 | |
| 5 | This skill is opinionated: it describes a recommended modern package contract and may suggest breaking changes when they make the package simpler, safer, and easier for modern consumers. |
| 6 | |
| 7 | ## Standard |
| 8 | |
| 9 | Default recommendation for new JS/TS libraries: |
| 10 | |
| 11 | - ESM-first, preferably pure ESM. |
| 12 | - Strict TypeScript and correct declaration files. |
| 13 | - Explicit public API through `package.json#exports`. |
| 14 | - Small named-export API surface. |
| 15 | - Few runtime dependencies, without treating zero dependencies as a religion. |
| 16 | - Small, tree-shakeable output with accurate `sideEffects`. |
| 17 | - Clear dependency placement: runtime dependencies, peer dependencies, optional dependencies, and dev dependencies are not interchangeable. |
| 18 | - Published package is tested as an artifact, not just as source files. |
| 19 | - Release flow is automated, traceable, and SemVer-aware. |
| 20 | - README.md explains usage for humans; AGENTS.md preserves package invariants for future agents. |
| 21 | |
| 22 | ## Workflow |
| 23 | |
| 24 | 1. **Inspect the package contract first** |
| 25 | - Read `package.json`, lockfile/package manager, `rslib.config.*`, `tsconfig*`, CI/release config, README.md, AGENTS.md, and existing `dist` output. |
| 26 | - Identify package kind: Node utility, browser library, isomorphic utility, CLI, UI/component library, framework plugin, SDK, or adapter. |
| 27 | - List supported runtimes, current entry points, deep imports, runtime dependencies, peer dependencies, optional integrations, files with side effects, and published files. |
| 28 | - Run `npm pack --dry-run` early when changing package shape so the real tarball contents guide the review. |
| 29 | |
| 30 | 2. **Define target environments explicitly** |
| 31 | - Do not say "supports modern environments" without defining them. |
| 32 | - Verify the current Node.js release schedule before choosing `engines`. |
| 33 | - As of May 9, 2026, Node.js 22 and 24 are LTS, and Node.js 20 is EOL. For new Node-facing packages, recommend `engines.node >=22` unless real consumers need an older runtime. |
| 34 | - Browser packages should state whether they require native ESM, a bundler, Workers support, SSR compatibility, DOM APIs, CSS processing, or specific browser baselines. |
| 35 | - Compatibility drops are breaking changes: old Node/browser versions, undocumented deep imports, default/named export shape, bundled vs external dependency behavior, and import side effects. |
| 36 | |
| 37 | 3. **Prefer pure ESM, but explain compatibility cost** |
| 38 | - New packages should use `"type": "module"` and ESM source/output. |
| 39 | - Rslib's default format is ESM; keep that default unless there is a clear reason to add another format. |
| 40 | - Evaluate compatibility from real consumers and supported runtimes instead of assuming every historical module format is required. |
| 41 | - Modern Node.js can load synchronous ESM from CommonJS via `require(esm)`; do not assume CJS consumers always require a separate CJS build. |
| 42 | - If you rely on `require(esm)` compatibility, document and test its constraints: supported Node versions, no top-level `await` in the loaded graph, namespace-object return shape, default export behavior, and CJS/ESM cycle limits. |
| 43 | - Prefer Node built-in specifiers such as `node:fs/promises`. |
| 44 | |
| 45 | 4. **Make `exports` the public API** |
| 46 | - Treat `package.json#exports` as the product contract. |
| 47 | - Export only paths users are meant to import. |
| 48 | - Do not allow imports like `pkg/dist/foo.js` by exporting `./dist/*`. That makes the generated output layout part of the public API and turns internal file moves into breaking changes. |
| 49 | - Instead, expose only intentional public paths such as `pkg` and `pkg/foo.js`, mapped to the actual files in `dist`. |
| 50 | - Keep subpath style consistent: either all with extensions such as `./foo.js`, or all without extensions. Prefer paths with extensions when browser import maps matter. |
| 51 | - Keep `"types"` first inside conditional exports. |
| 52 | - Adding `exports` to an older package can be breaking because undeclared deep imports stop working. |
| 53 | - Add `./package.json` only when consumers legitimately need package metadata. |
| 54 | |
| 55 | 5. **Design a small API surface** |
| 56 | - Prefer named exports for multi-API packages. |
| 57 | - Avoid default-export objects that gather every function into one object. |
| 58 | - Public functions should be few, stable, well-named, and semver-maintained. |
| 59 | - Keep internal types, caches, helper functio |