You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When bundling a library with parcel and relying on @parcel/transformer-typescript-types to generate a bundled .d.ts file, you'll get incorrect output if there is a naming conflict between a top-level export and the contents of a module that's exported with a wildcard export (e.g. export * from "foo).
Interestingly, the bug will appear or not depending on the order of the top-level exports (see below)
exportconstnameConflict={messageFromIndex: "this instance of nameConflict is from index.ts"};export*from"./name-conflict";// Note: this comes _after_ the top-level export above.
src/name-conflict.ts
exportconstnameConflict={messageFromNameConflict: "this instance of nameConflict is from name-conflict.ts"};
😯 Current Behavior
When you run the parcel build, parcel generates the following index.d.ts file:
However, when you consume the library in a different project, the nameConflict export at runtime will be the top-level export from index.ts:
import{nameConflict}from"test-parcel-library";// @ts-expect-error: the d.ts file generated by parcel is incorrectconsole.log(nameConflict.messageFromIndex);// prints "this instance of nameConflict is from index.ts"
🤔 Expected Behavior
The index.d.ts file generated by parcel should be:
Interestingly, if you switch the order of the exports in index.ts, you'll get this correct output:
index.ts
export*from"./name-conflict";// Note: this comes _before_ the top-level export below, which fixes the problem.exportconstnameConflict={messageFromIndex: "this instance of nameConflict is from index.ts"};
If you build the same project with tsc directly, the .d.ts files generated will correctly describe the package, regardless of the order of the exports (although it looks slightly different from what you'd expect from parcel because tsc can't bundle the .d.ts files for commonjs projects).
💁 Possible Solution
In TSModuleGraph.propegate we first collect all the top-level export names in an array with a call to getAllExports, and iterate through them:
In the example above (where the bug reproduces), this array will have these (simplified) contents, in this order:
[
{ name: "nameConflict", module: <TSModule for 'index.ts"> }
{ name: "nameConflict", module: <TSModule for 'nameConflict.ts"> }
]
The call to exportedNames.set(e.name, e.module) will thus happen twice with the same name, over-writing the previous value. At the end of the loop, exportedNames will be:
{ "nameConflict": <TSModule for 'nameConflict.ts"> }
Further down, when we assign unique names, we do this check:
exportedNames.get(name) === m will be true when we're passing through nameConflict.ts, so we skip renaming it. When we pass through index.ts, it will be false, so we'll proceed to assign a disambiguator to it.
If you flip the order of the exports in index.ts that will change the contents of exportedNames, and you'll get the opposite (correct) behavior - i.e. the export from nameConflict.ts gets the disambiguator, and the top-level export from index.ts does not.
One solution would be to check when we are about to over-write entries to exportedNames and somehow find a way to deterministically prefer top-level exports over implicit exports that happen through a wildcard.
🔦 Context
I was working on a PR add support for namespace exports to @parcel/transformer-typescript-types (fixing #5911), and I ran across this issue in the process.
🐛 bug report
When bundling a library with parcel and relying on
@parcel/transformer-typescript-types
to generate a bundled.d.ts
file, you'll get incorrect output if there is a naming conflict between a top-level export and the contents of a module that's exported with a wildcard export (e.g.export * from "foo
).Interestingly, the bug will appear or not depending on the order of the top-level exports (see below)
🎛 Configuration (.babelrc, package.json, cli command)
package.json
src/index.ts
src/name-conflict.ts
😯 Current Behavior
When you run the
parcel build
, parcel generates the followingindex.d.ts
file:types.d.ts
However, when you consume the library in a different project, the
nameConflict
export at runtime will be the top-level export fromindex.ts
:🤔 Expected Behavior
The
index.d.ts
file generated by parcel should be:Interestingly, if you switch the order of the exports in
index.ts
, you'll get this correct output:index.ts
If you build the same project with
tsc
directly, the.d.ts
files generated will correctly describe the package, regardless of the order of the exports (although it looks slightly different from what you'd expect from parcel becausetsc
can't bundle the.d.ts
files for commonjs projects).💁 Possible Solution
In
TSModuleGraph.propegate
we first collect all the top-level export names in an array with a call togetAllExports
, and iterate through them:parcel/packages/transformers/typescript-types/src/TSModuleGraph.js
Lines 202 to 208 in 62f64ca
In the example above (where the bug reproduces), this array will have these (simplified) contents, in this order:
The call to
exportedNames.set(e.name, e.module)
will thus happen twice with the same name, over-writing the previous value. At the end of the loop,exportedNames
will be:Further down, when we assign unique names, we do this check:
parcel/packages/transformers/typescript-types/src/TSModuleGraph.js
Lines 213 to 217 in 62f64ca
exportedNames.get(name) === m
will betrue
when we're passing throughnameConflict.ts
, so we skip renaming it. When we pass throughindex.ts
, it will be false, so we'll proceed to assign a disambiguator to it.If you flip the order of the exports in
index.ts
that will change the contents ofexportedNames
, and you'll get the opposite (correct) behavior - i.e. the export fromnameConflict.ts
gets the disambiguator, and the top-level export fromindex.ts
does not.One solution would be to check when we are about to over-write entries to
exportedNames
and somehow find a way to deterministically prefer top-level exports over implicit exports that happen through a wildcard.🔦 Context
I was working on a PR add support for namespace exports to
@parcel/transformer-typescript-types
(fixing #5911), and I ran across this issue in the process.💻 Code Sample
You can see a reproduction of the problem in this github repo
🌍 Your Environment
The text was updated successfully, but these errors were encountered: