prepare-package
v2.1.0
Published
Prepare a Node.js package before being published
Maintainers
Readme
Install
npm install prepare-package --save-devQuick Setup
Run the interactive CLI to configure your project:
npx ppThis will walk you through selecting a build type (copy or bundle), configuring formats, and auto-deriving IIFE settings (global name from package name in TitleCase, filename as {name}.min.js). The CLI writes the preparePackage config and scripts directly to your package.json.
You can also use the full name:
npx prepare-packageFeatures
- Two modes: copy (default) and bundle (esbuild)
- Copy mode: copies
src/todist/, replaces{version}in main file - Bundle mode: builds ESM, CJS, and/or IIFE outputs via esbuild
- Before/after hooks — run arbitrary shell commands as part of the prepare lifecycle
- Blocks
npm publishwhen localfile:dependencies are detected - Cleans up sensitive files (
.env,.DS_Store, etc.) before publish - Purges jsDelivr CDN cache after publish
- Watch mode for both copy and bundle types
- Auto-adds
prepareandprepare:watchscripts to consumer'spackage.json
Configuration
All configuration lives in the preparePackage key in your package.json.
Copy Mode (default)
Copies files from input to output and replaces {version} in the main file.
{
"main": "dist/index.js",
"preparePackage": {
"input": "src",
"output": "dist"
}
}| Key | Default | Description |
|-----|---------|-------------|
| type | "copy" | Processing mode |
| input | "src" | Source directory to copy from |
| output | "dist" | Destination directory to copy to |
| replace | {} | Additional replacements (reserved) |
Bundle Mode
Uses esbuild to produce optimized builds in multiple module formats.
{
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"preparePackage": {
"input": "src",
"output": "dist",
"type": "bundle",
"build": {
"formats": ["esm", "cjs", "iife"],
"iife": {
"globalName": "MyLib",
"fileName": "my-lib.min.js"
}
}
}
}| Key | Default | Description |
|-----|---------|-------------|
| type | — | Must be "bundle" to enable this mode |
| build.entry | "{input}/index.js" | Entry point for esbuild |
| build.formats | ["esm", "cjs"] | Output formats: "esm", "cjs", "iife" |
| build.target | "es2020" | esbuild target for ESM/CJS builds |
| build.platform | "neutral" | esbuild platform |
| build.external | [] | Packages to exclude from bundle |
| build.sourcemap | false | Generate source maps |
| build.cjs.footer | "module.exports=module.exports.default\|\|module.exports;" | CJS footer — unwraps export default so require() returns the value directly |
| build.iife.globalName | — | Required when "iife" is in formats. The global variable name (e.g., window.MyLib) |
| build.iife.fileName | "{name}.min.js" | Output filename for IIFE build |
| build.iife.target | "es2015" | esbuild target for IIFE build |
Output files
| Format | File | Minified |
|--------|------|----------|
| ESM | dist/index.mjs | No |
| CJS | dist/index.js | No |
| IIFE | dist/{fileName} | Yes |
Version replacement
In bundle mode, all occurrences of {version} in .js source files are replaced with the version from package.json at build time via an esbuild plugin.
CJS default export
The CJS build automatically appends a footer that unwraps export default so require('your-package') returns the function/class directly — not { default: fn }. This means both of these just work:
// ESM
import MyLib from 'your-package';
// CJS
const MyLib = require('your-package');To override the footer, set build.cjs.footer in your config.
IIFE global export
The IIFE build automatically unwraps the default export so window[globalName] is the class/function directly, not a { default } wrapper.
Hooks
Run arbitrary shell commands before or after the copy/bundle step. Useful for fetching remote data, generating files, uploading artifacts, or running any command that needs to happen as part of the prepare lifecycle — so the output lands in both your git commits and your published tarball.
{
"preparePackage": {
"input": "src",
"output": "dist",
"hooks": {
"before": "node scripts/update-disposable-domains.js",
"after": "node scripts/notify-deploy.js"
}
}
}| Hook | When it runs | On failure |
|------|-------------|-----------|
| before | After publish safety checks, before the copy/bundle step | Blocks — throws and aborts prepare |
| after | After the copy/bundle step, before the CDN purge | Warns — logs a warning and continues |
Both hooks accept a single command string or an array of commands:
{
"preparePackage": {
"hooks": {
"before": [
"node scripts/update-disposable-domains.js",
"node scripts/build-manifest.js"
]
}
}
}Commands run synchronously from the package root with stdio inherited, so their output appears in the parent process. Hooks are skipped in watch mode (single-file updates) and during postinstall — they only run on full prepare runs (npm run prepare, npm publish, etc.).
Usage
# Build once
npm run prepare
# Watch for changes
npm run prepare:watch
# These scripts are auto-added to your package.json:
# "prepare": "node -e \"require('prepare-package')()\""
# "prepare:watch": "node -e \"require('prepare-package/watch')()\""Publish Safety
When running via npm publish, prepare-package will:
- Block local dependencies — fails if any
file:,../,./,/, or~dependency versions are found - Remove sensitive files — deletes
.env,.env.local,.env.development,.env.production,firebase-debug.log,.DS_Store,Thumbs.dbfrom the package - Purge CDN cache — purges the jsDelivr cache for your package after publish
Questions
If you are still having difficulty, post a question to the Prepare Package issues page.
