mike-lischke / antlr4ng

Next Generation TypeScript runtime for ANTLR4
Other
65 stars 11 forks source link

Class extends value undefined is not a constructor or null #60

Closed NicoLaval closed 2 months ago

NicoLaval commented 2 months ago

I have a generated lexer:

import * as antlr from "antlr4ng";
import { Token } from "antlr4ng";
export class MyLexer extends antlr.Lexer {
...
}

Exposed by the root index.ts:

export { MyLexer as Lexer } from "./generated/MyLexer";

I deploy it on npm thanks to tsc, with this tsconfig.json file:

{
    "compilerOptions": {
        "module": "CommonJS",
        "moduleResolution": "node",
        "target": "ES2020",
        "lib": ["es2022"],
        "declaration": true,
        "sourceMap": true,
        "outDir": "./dist",
        "newLine": "LF",
        "noUnusedLocals": false,
        "noUnusedParameters": false,
        "incremental": true,
        "strict": true,
        "downlevelIteration": true,
        "jsx": "react-jsx",
        "noFallthroughCasesInSwitch": true,
        "strictPropertyInitialization": false
    },
    "include": ["src"]
}

I consume this package in a simple CRA app and have this error : Class extends value undefined is not a constructor or null

Any idea?

Use case is reproductible:

NicoLaval commented 2 months ago

Working in a ViteJs app

NicoLaval commented 2 months ago

The issue with CRA is because of the dual bundle CJS / ESM.

Hand test, deleting ESM fields in your package.json in my node-modules, it works.

Do you really need to bundle in ESM?

https://github.com/garronej/ts-ci?tab=readme-ov-file#cjs-only-default

mike-lischke commented 2 months ago

If it were just me, I would only bundle for ESM (and for a while the package was set up like this), but for some scenarios (like jest testing using Node.js) it's easier to have a CJS bundle too (even though also for this situation it's possible to use ESM).

To me your problem sounds like some of the fields in package.json are not correct (but I checked them carefully). But since nobody else has reported such an issue like yours, it could well be the problem is on the importing side.

NicoLaval commented 2 months ago

What’s the use case for needing ESM instead of CJS?

mike-lischke commented 2 months ago

That's like asking why should we use 64bit, if we have 32bit 😀. ESM is the future. Forget CJS, AMD and what not. Browsers only support ESM, Node.js is on the way to support ESM (still not complete unfortunately). But alternatives like Deno already work only with ESM. CJS is the past.

NicoLaval commented 2 months ago

Future, maybe, not the present.

CJS provide stability, serve Browser and Node env easily, while ESM impose constraints in actual stacks.

ESM > CJS only when you are using dynamic import or default export in your lib, for other use cases, I think CJA is better if only for its interoperability