Show HN: Export-map-generator – Generate package.json exports from build outputs

4 days ago 2

Declarative and extensible tooling to automate exports generation for multi-format packages. Updates package.json with a consistent exports field generated by analyzing the distribution files.

export-map-generator provides a plugin-oriented pipeline that allows developers to control, extend, or override every part of the export-map generation process.

Manually maintaining complex export maps for multiple formats is error-prone and fragile. This tool reduces mistakes, enforces consistency, and integrates cleanly with any build system.

The generator is built around several core ideas, all of which are designed to enhance the developer experience and ensure that the generated export maps are correct and easy to work with.

Convention-first design, with override flexibility

A clear structure, while allowing full customization through plugins and presets.

export default defineConfig({ presets: [ dts(), cjs(), esm(), standard(), ], });

Distribution-based analysis

Inspects built output rather than source files, works with any build system.

dist ├── cjs │ └── array.cjs ├── esm │ └── array.mjs └── types └── array.d.ts

Format-aware export generation

ESM, CJS, DTS, and hybrid module setups with precise path resolution.

{ "exports": { "./array.js": { "types": "./dist/types/array.d.ts", "import": "./dist/esm/array.mjs", "require": "./dist/cjs/array.cjs", "default": "./src/array.ts" } } }

Conflict avoidance by construction:

Resolves path ambiguities in complex export maps.

{ "exports": { "./array.d.ts": { "types": "./dist/types/array.d.ts", "default": "./src/array.ts" }, "./array.js": { "types": "./dist/types/array.d.ts", "import": "./dist/esm/array.mjs", "require": "./dist/cjs/array.cjs", "default": "./src/array.ts" }, "./array": { "types": "./dist/types/array.d.ts", "import": "./dist/esm/array.mjs", "require": "./dist/cjs/array.cjs", "default": "./src/array.ts" } } }

Add, extend, or replace behaviors at every stage: from file discovery to reporting.

export default defineConfig({ extensions: [ barrel(), ], });
{ "exports": { "./index.js": { "types": "./dist/types/index.d.ts", "import": "./dist/esm/index.mjs", "require": "./dist/cjs/index.cjs", "default": "./src/index.ts" }, ".": { "types": "./dist/types/index.d.ts", "import": "./dist/esm/index.mjs", "require": "./dist/cjs/index.cjs", "default": "./src/index.ts" } } }

Use interactively via terminal or integrate programmatically into custom workflows.

> export-map-generator Usage: export-map-generator [options] [command] Options: -V, --version output the version number --cwd <PATH> path to the working directory -c, --config <PATH> path to the configuration file --dry-run preview changes without writing to disk (default: false) -h, --help display help for command Commands: config configuration commands context context commands generate [options] generate export map help [command] display help for command

The package is available on npm and can be installed with any compatible package manager.

npm install --save-dev export-map-generator
Troubleshooting: Cannot load configuration?

The library uses cosmiconfig to load the configuration file. If you encounter issues with loading the configuration, you may need to install cosmiconfig as a peer dependency.

npm install --save-dev cosmiconfig
Troubleshooting: Cannot run CLI commands?

The library uses commander for the CLI commands. If you encounter issues with running the CLI commands, you may need to install commander as a peer dependency. Additionally, pretty-format is used for formatting the outputs of the inspect commands, so you may need to install it as well.

npm install --save-dev commander pretty-format

By default, the generator does not include any activated functionality. This design ensures that the export strategy remains explicit and intentional. All logic -from analyzing directories to writing the final export map- is handled via extensions and presets.

The library includes a set of built-in presets that can be used to quickly set up the export map generation without needing to define everything from scratch.

The CLI provides a convenient way to interact with the generator. You can use it to generate the export map, preview changes, and inspect the context.

To preview the changes without writing to disk, you can use the --dry-run and --stdout options together:

export-map-generator --dry-run generate --stdout

Note: The --stdout option does not prevent the generator from updating the package.json file. To achieve that, you need to use the --dry-run option.

For programmatic usage, you can import the library and use it in your scripts:

import { resolveContext } from "export-map-generator/context"; import { generateExportMapByContext } from "export-map-generator/export-map"; const context = await resolveContext({ dryRun: true }); const exportMap = await generateExportMapByContext(context);

The generator without any configuration cannot generate an exports map, this is by design to ensure that the user explicitly defines how the exports should be structured. The configuration allows you to specify presets, plugins, and other options to customize the export map generation process.

The configuration for export-map-generator can be done via these files:

  • exports.config.cjs
  • exports.config.js
  • exports.config.mjs (recommended)
  • exports.config.ts (recommended)

The configuration file should export either a default object or a function that returns an object.

import defineConfig from "export-map-generator/config"; export default defineConfig({});

Extensions are the plugins that provide core or additional functionalities to the generator. An extension can implement any method listed in the table below.

Method Description
setup Initialize the extension and set up any necessary state.
resolveConfig Resolve the configuration for the extension.
resolveContext Resolve the context for the extension.
produceDirentRefs Produce directory entries (e.g. matching a pattern).
produceEntriesByDirentRef Produce export-map entries based on the given directory entry.
produceEntries Produce export-map entries, (e.g. additional entries).
handleEntryByDirentRef Handle the entry by directory entry.
handleEntry Handle the entry (any entry).
aggregateExportMap Consolidate the generated entries and produce the final export map.
sortExportMap Sort the export map entries (e.g. to avoid conflicts).
reportExportMap Report the generated export map (e.g. update the package.json file).

Presets are predefined configurations that encapsulate common export patterns and conventions. They can be used to quickly set up the export map generation without needing to define everything from scratch. The library comes with a set of built-in presets that can be used directly or extended as needed.

The CJS preset is designed for projects that distribute their code using the CommonJS module format.

Example: Using the CJS preset
import defineConfig from "export-map-generator/config"; import cjs from "export-map-generator/presets/cjs"; export default defineConfig({ presets: [ cjs(), ], });
Example: Using the CJS preset for TypeScript source files
import defineConfig from "export-map-generator/config"; import cjs from "export-map-generator/presets/cjs"; export default defineConfig({ presets: [ cjs({ src: { extension: ".ts", }, }), ], });

The DTS preset is designed for projects that distribute TypeScript declarations.

Example: Using the DTS preset
import defineConfig from "export-map-generator/config"; import dts from "export-map-generator/presets/dts"; export default defineConfig({ presets: [ dts(), ], });
Example: Using the DTS preset for TypeScript source files
import defineConfig from "export-map-generator/config"; import dts from "export-map-generator/presets/dts"; export default defineConfig({ presets: [ dts({ src: { extension: ".ts", }, }), ], });

The ESM preset is designed for projects that distribute their code using the ECMAScript module format.

Example: Using the ESM preset
import defineConfig from "export-map-generator/config"; import esm from "export-map-generator/presets/esm"; export default defineConfig({ presets: [ esm(), ], });
Example: Using the ESM preset for TypeScript source files
import defineConfig from "export-map-generator/config"; import esm from "export-map-generator/presets/esm"; export default defineConfig({ presets: [ esm({ src: { extension: ".ts", }, }), ], });

The generic preset is designed to provide a flexible configuration for projects that do not fit into the standard module formats. It allows defining custom export patterns and conventions.

Example: Using the generic preset
import defineConfig from "export-map-generator/config"; import generic from "export-map-generator/presets/generic"; export default defineConfig({ presets: [ generic({ conditions: [ "license", ], dist: { path: "licenses", extension: "", }, filter: (direntRef) => { return ( direntRef.dirent.isFile() && ["", ".md", ".txt"].includes(direntRef.parsedPath.ext) ); }, virtual: { extension: ".license" }, }), ], });

The Package-JSON preset is designed for projects that include the package.json file in their distribution.

Example: Using the Package-JSON preset
import defineConfig from "export-map-generator/config"; import packageJSON from "export-map-generator/presets/package-json"; export default defineConfig({ presets: [ packageJSON(), ], });

The standard preset provides a comprehensive configuration that combines extensions that are responsible for these core functionalities:

  • Analyzing the distribution for barrel files (index files)
  • Generating exports from directories that contain barrel files
  • Consolidating the export patterns per import path
  • Preventing import path conflicts by organizing them in correct order
  • Preventing runtime condition conflicts by organizing the exports in correct order
  • Updating the exports field in the package.json file
Example: Using the standard preset
import defineConfig from "export-map-generator/config"; import standard from "export-map-generator/presets/standard"; export default defineConfig({ presets: [ standard(), ], });

The work of export-map-generator can be seen in the package.json file of this repository. The exports field is generated based on the distribution files and the configuration provided in the exports.config.ts file. The generator analyzes the distribution files and generates the exports field based on the conventions defined in the configuration.

This project is licensed under the MIT License. See the LICENSE file for details.

Read Entire Article