Skip to content

Commit

Permalink
Make ESM named imports work in Node (#531)
Browse files Browse the repository at this point in the history
Importing slang from a native ESM module is pretty cumbersome in Node
right now. Here's an example of an error you may get if you try to use a
normal named import:

```
% node index.mjs
file:///private/tmp/npmproject-4/index.mjs:6
import { ProductionKind } from "@NomicFoundation/slang/syntax/parser/index.js";
         ^^^^^^^^^^^^^^
SyntaxError: Named export 'ProductionKind' not found. The requested module '@NomicFoundation/slang/syntax/parser/index.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@NomicFoundation/slang/syntax/parser/index.js';
const { ProductionKind } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:190:5)

Node.js v18.16.1
```

This PR changes how we export things in JavaScript so that named imports
from ESM modules work in Node.js.

The difference is really subtle and may be hard to understand at first
glance, so here's an explanation:

* CJS and ESM aren't really compatible, but Node implements a
compatibility mode which is not fully transparent.
* One of the things that is not transparent is the `default` export, as
that doesn't exist in CJS.
* The compatibility layer hence treats reassigning `module.exports` as a
`default` exports, hoping that it was the original intention of the
author. That leads to named imports from ESM not working if you reassign
it.
* If you keep the original `module.exports` and just add properties to
it, those are treated as named exports.
  • Loading branch information
alcuadrado authored Jul 10, 2023
1 parent f77330a commit e3450be
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/nice-flowers-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nomicfoundation/slang": patch
---

Make ESM named imports work in Node.js.
6 changes: 2 additions & 4 deletions crates/solidity/outputs/npm/package/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,5 @@
const language = require("./language");
const syntax = require("./syntax");

module.exports = Object.freeze({
language,
syntax,
});
module.exports.language = language;
module.exports.syntax = syntax;
4 changes: 1 addition & 3 deletions crates/solidity/outputs/npm/package/language/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@

const generated = require("../generated");

module.exports = Object.freeze({
Language: generated.Language,
});
module.exports.Language = generated.Language;
6 changes: 2 additions & 4 deletions crates/solidity/outputs/npm/package/syntax/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,5 @@
const nodes = require("./nodes");
const parser = require("./parser");

module.exports = Object.freeze({
nodes,
parser,
});
module.exports.nodes = nodes;
module.exports.parser = parser;
12 changes: 5 additions & 7 deletions crates/solidity/outputs/npm/package/syntax/nodes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@

const generated = require("../../generated");

module.exports = Object.freeze({
NodeType: generated.NodeType,
RuleKind: generated.RuleKind,
RuleNode: generated.RuleNode,
TokenKind: generated.TokenKind,
TokenNode: generated.TokenNode,
});
module.exports.NodeType = generated.NodeType;
module.exports.RuleKind = generated.RuleKind;
module.exports.RuleNode = generated.RuleNode;
module.exports.TokenKind = generated.TokenKind;
module.exports.TokenNode = generated.TokenNode;
8 changes: 3 additions & 5 deletions crates/solidity/outputs/npm/package/syntax/parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

const generated = require("../../generated");

module.exports = Object.freeze({
ParseError: generated.ParseError,
ParseOutput: generated.ParseOutput,
ProductionKind: generated.ProductionKind,
});
module.exports.ParseError = generated.ParseError;
module.exports.ParseOutput = generated.ParseOutput;
module.exports.ProductionKind = generated.ProductionKind;

0 comments on commit e3450be

Please sign in to comment.