handlebars-lang / handlebars-lang/handlebars-parser

CJS build is unusable: dist/cjs/*.js are CommonJS but package "type":"module" makes Node parse them as ESM ("exports is not defined")

Open
#33 1 comment 1 reaction 2 assignees Claimed by @NullVoxPopuli View on GitHub
Dominant language
JavaScript
Stars
43
Forks
19
PR merge metrics
No merged PRs in 30d

Description

## Summary

`@handlebars/parser@2.2.2` cannot be loaded via `require()` from a CommonJS
module. The package sets `"type": "module"` in `package.json`, but the CommonJS
build in `dist/cjs/` emits **`.js`** files that use CommonJS syntax
(`exports`, `require`). Because of `"type": "module"`, Node treats every `.js`
file in the package as ESM, so loading the CJS entry throws:

```
ReferenceError: exports is not defined in ES module scope
```

The `require` export condition points at exactly this file, so any CommonJS
consumer crashes on import.

## Environment

- `@handlebars/parser`: **2.2.2**
- Node.js: **v24.13.1** (also reproducible on other Node 20/22/24 versions)
- OS: Windows 11 (not OS-specific)

## Relevant `package.json` fields

```json
{
"type": "module",
"main": "dist/cjs/index.js",
"exports": {
".": {
"require": { "types": "./types/index.d.ts", "default": "./dist/cjs/index.js" },
"import": { "types": "./types/index.d.ts", "default": "./dist/esm/index.js" },
"default": { "types": "./types/index.d.ts", "default": "./dist/cjs/index.js" }
}
}
}
```

With `"type": "module"`, the `require` condition resolves to
`./dist/cjs/index.js`, but that `.js` file is parsed as **ESM** — so its
CommonJS `exports`/`require` usage is invalid.

## Steps to reproduce

Create a CommonJS project (no `"type": "module"`), install the package, and:

```js
// index.cjs
const parser = require('@handlebars/parser');
console.log(parser);
```

```
node index.cjs
```

## Actual result

```
.../node_modules/@handlebars/parser/dist/cjs/index.js:5
Object.defineProperty(exports, "__esModule", { value: true });
^
ReferenceError: exports is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file
extension and '.../node_modules/@handlebars/parser/package.json' contains
"type": "module". To treat it as a CommonJS script, rename it to use the
'.cjs' file extension.
at ModuleJobSync.runSync (node:internal/modules/esm/module_job)
at loadESMFromCJS (node:internal/modules/cjs/loader)
...
```

## Expected result

`require('@handlebars/parser')` returns the module exports without throwing.

## Root cause

`"type": "module"` forces Node to interpret **all** `.js` files in the package
as ESM. The CommonJS output in `dist/cjs/` therefore must not use the `.js`
extension (or the directory must opt back into CommonJS).

## Suggested fixes (any one resolves it)

1. **Emit `.cjs` for the CommonJS build** and update the `require` /
`main` / `default` targets to `./dist/cjs/index.cjs`. (Cleanest.)
2. **Add a nested `dist/cjs/package.json`** containing `{ "type": "commonjs" }`
so files under `dist/cjs/` are treated as CommonJS regardless of the
top-level `"type": "module"`.
3. Move `"type": "module"` out and instead mark the ESM build with a nested
`dist/esm/package.json` of `{ "type": "module" }`.

Note: the current `build:cjs` script (`tsc --module commonjs ... --outDir dist/cjs`)
produces the CommonJS syntax correctly — the only problem is the file
extension / package `type` mismatch, not the transpiled code itself.

## Impact

Any CommonJS consumer (including transitive dependents that `require()` the
package rather than bundling it) fails to load at runtime. Bundlers such as
esbuild that inline and resolve the conditions at build time are unaffected,
which can mask the issue until an unbundled `require()` path is exercised.

In my case, I wanted to use your package in a vscode extension (https://github.com/JoernBerkefeld/vscode-sfmc-language/) which only worked with a manual rewrite

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.