Skip to main content

3.0 migration

Shifted supported platform versions

Since Node.js v14 has reached end of life, Packemon now requires at minimum v16.12 and above to run. Furthermore, we're entirely dropping v12 support, and shifting v14 into legacy, v16 into stable, v18 into current, and the new v19 into experimental. As part of this process, we are also bumping minimum requirements and coupled npm versions.

The updated support compatibility table is as follows.


node>= 12.22.0>= 14.15.0>= 16.12.0>= 18.0.0
npm>= 6.14.0>= 6.14.0>= 8.1.0>= 8.5.0
nativeiOS 12iOS 13iOS 14iOS 15


node>= 14.15.0>= 16.12.0>= 18.12.0>= 19.0.0
npm>= 6.14.0>= 8.1.0>= 8.19.0>= 9.0.0
nativeiOS 13iOS 14iOS 15iOS 16

Notable changes:

Dropped ES5 support

Furthermore, we have dropped es5 support from the legacy target, and replaced it with es2018. The stable target has also been updated to es2019.

No longer workspaces aware by default

Packemon was originally designed to work in both polyrepo's and monorepo's. When the packemon command was ran in a workspace root, it would apply to all packages in the workspace. This was pretty cool and worked great. However, it overcomplicated our implementation and required many poly vs mono checks everywhere. It was becoming a nightmare to maintain and ensure correct boundaries.

To remedy this, we refactored every piece of Packemon from the ground up to break these 2 patterns apart. The packemon build, packemon pack, and other commands (below) will only apply to 1 package now, the one found in the current working directory.

For workspaces, we've added new packemon build-workspace and packemon pack-workspace commands, which mimic the previous functionality, and should be ran in the workspace root.

Commands must now be ran from the package root

Because of the above change, all the primary commands -- build, clean, files, init, pack, validate, watch -- must now be ran from the package root, as our tooling assumes the package is located in the current working directory. They can no longer be ran from the workspace root if using a monorepo.

This does not apply to the scaffold command (and the new build-workspace and pack-workspace commands), as they should always be ran from the repository root.

TypeScript declarations now require explicitly named configs

When the --declaration option is passed, Packemon will generate TypeScript declarations for all inputs. This process would assume that a tsconfig.json existed in the package root. This file could then be overridden with the --declarationConfig option.

However, in TypeScript v4.7, the new .cts and .mts file extensions were released. With this release, the declaration outputs have also changed, and may produce different outputs depending on the source file type (cjs vs esm). Because of this, we can no longer generate declarations for all formats using a single tsconfig, especially when building multiple formats in parallel!

To solve this problem, Packemon now requires a tsconfig.<format>.json file. For example, if you're building the formats lib and esm, you'll now need tsconfig.lib.json and tsconfig.esm.json files. This cannot be changed, as as such, the --declarationConfig option has been removed.

TypeScript declaration output directory has changed

As a side-effect of the change above, the output directory of declarations have also changed. Instead of generating to a dts folder, they will now generate to the format folders, lib, esm, etc.

If using project references, you'll need to manually update outDir as we cannot pass the --outDir option for composite builds.

"extends": "../../tsconfig.options.json",
"compilerOptions": {
"outDir": "lib"
"include": ["src/**/*"]

Package exports have changed

To support the TypeScript differences mentioned above, the package.json exports had to also change. Instead of having a types export at the top-level, it will now be nested within import or require, depending on the format and combinations. This also means that import and require may have different type declarations if need be.

// Before
".": {
"types": "./dts/index.d.ts",
"node": "./lib/index.js",
"default": "./lib/index.js"

// After
".": {
"node": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
"default": "./lib/index.js"

Publishable files are now lenient

When the --addFiles option is passed, we update the files field in the package's package.json with a whitelist of files that should be published. Previously, this would use a glob with a strict match on file extension, for example src/**/*.{ts,tsx,json} or cjs/**/*.{cjs,mjs,map}.

With the amount of file extensions now available in the JavaScript ecosystem, this has become very tedious to determine accurately, and as such, these globs have dropped the file extension requirement. For example, these are simply now src/**/* and cjs/**/*.

Do note, we do not remove the previous globs, so you'll need to manually fix each package.json!

Removed sourcemaps from Node.js

Packemon would always create sourcemaps, as it provides a mechanism for consumers to debug issues with their code, specifically when it was bundled with Webpack or Metro. However, this wasn't really necessary for Node.js packages, as they are typically developer tooling or scripts related, and are not bundled. Consumers can inspect node_modules directly to debug these packages.

Because of this, we have removed sourcemaps entirely from Node.js based packages. This will grealy reduce the overall package size.

Other minor changes

  • The pack and pack-workspace commands will automatically set NODE_ENV=production now.
  • The type field in package.json will no longer be set.
  • The lib format is no longer automatically enabled when using the esm format.
  • Removed most of the React/Ink integration for rendering to the terminal, as it was major bottleneck for performance.
  • Removed babelrcRoots support from our internal Babel configuration.
  • Removed the engines version constraint feature.
  • Removed the npm engine when adding engines with --addEngines.
  • Removed the --files option from packemon validate.