Repository navigation
Add ESM support - #16
lfbittencourt wants to merge 2 commits into
Conversation
export = is CJS-only syntax and errors when targeting ESM modules. export default works for both CJS (with esModuleInterop) and ESM, and is already what the test imports expect. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add tsconfig.cjs.json: compiles to dist/cjs/ with declaration files - Add tsconfig.esm.json: compiles to dist/esm/ with ESNext modules - Update package.json: exports map, main → dist/cjs/index.js, types field, updated build script - Update README: remove CJS-only note, show both require and import examples Closes #12 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces dual-package (CommonJS + ES module) support for string-expansion, updating the TypeScript build outputs and package entrypoints so consumers can use either require or import.
Changes:
- Added separate TypeScript build configs for CJS (
dist/cjs/) and ESM (dist/esm/). - Switched entrypoint exports from
export =toexport default. - Updated
package.json(main,types, andexports) and refreshed README usage examples.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.esm.json | Adds an ESM build output configuration. |
| tsconfig.cjs.json | Adds a CJS build output configuration with declarations. |
| src/pattern-to-tree.ts | Converts export = to export default. |
| src/index.ts | Converts export = to export default for the package entrypoint. |
| package.json | Adds conditional exports + updates build script and entry fields. |
| README.md | Updates documentation to show both CJS and ESM usage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "types": "dist/cjs/index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "import": "./dist/esm/index.js", |
There was a problem hiding this comment.
The ESM export points to ./dist/esm/index.js, but this package has no "type": "module" (so .js files are treated as CommonJS by Node). That means import 'string-expansion' will likely try to parse the ESM build as CJS and throw a syntax error. Consider either emitting ESM as .mjs, or adding dist/esm/package.json with { "type": "module" } and keeping the .js extension, or switching the package to type: module and emitting the CJS build with a .cjs extension.
| "import": "./dist/esm/index.js", |
| { | ||
| "extends": "./tsconfig.json", | ||
| "compilerOptions": { | ||
| "module": "ESNext", |
There was a problem hiding this comment.
Compiling to ESM with module: ESNext while keeping the base moduleResolution (currently node10) will emit extensionless relative imports (e.g. import './expand-tree'), which are not resolvable by Node's ESM loader without flags. If the goal is Node ESM support, consider using module/moduleResolution: NodeNext (or a bundler) and updating source imports to include .js extensions so the emitted ESM can be executed directly by Node.
| "module": "ESNext", | |
| "module": "ESNext", | |
| "moduleResolution": "NodeNext", |
| import patternToTree from './pattern-to-tree'; | ||
|
|
||
| export = (pattern: string) => expandTree(patternToTree(pattern)); | ||
| export default (pattern: string) => expandTree(patternToTree(pattern)); |
There was a problem hiding this comment.
Switching the entrypoint to export default changes the CommonJS shape when compiled with module: CommonJS: require('string-expansion') will return an object with a .default property rather than the function itself. If you want to preserve the existing CJS API, consider adding a small CJS wrapper entry that assigns module.exports = <default export>, and point the exports.require/main fields at that wrapper.
| export default (pattern: string) => expandTree(patternToTree(pattern)); | |
| declare const module: any; | |
| const expand = (pattern: string) => expandTree(patternToTree(pattern)); | |
| export default expand; | |
| (module as any).exports = expand; |
|
|
||
| ```js | ||
| // CommonJS | ||
| const expand = require('string-expansion'); |
There was a problem hiding this comment.
The CommonJS example implies require('string-expansion') returns a callable function. With the current TypeScript change to export default, the compiled CJS build will typically require consumers to access .default (or destructure it). Either adjust the CJS build to keep the old require shape, or update this example to match the published API.
| const expand = require('string-expansion'); | |
| const expand = require('string-expansion').default; |
Summary
export =toexport defaultinsrc/index.tsandsrc/pattern-to-tree.ts—export =is CJS-only and errors when targeting ES modulestsconfig.cjs.jsoncompiling todist/cjs/with declaration filestsconfig.esm.jsoncompiling todist/esm/withmodule: ESNextpackage.jsonwith anexportsmap,mainpointing todist/cjs/index.js, and atypesfieldrequireandimportexamplesCloses #12
Test plan
yarn buildcompiles both CJS (dist/cjs/) and ESM (dist/esm/) without errorsyarn test— all 34 tests pass*.d.ts) are generated indist/cjs/🤖 Generated with Claude Code