-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: handle specifier as default #804
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Agreed that this fixes the issues in your description and test, but it looks like splitting up the if
statement was actually incorrect.
} else { | ||
this.hadNamedExport = true; | ||
} | ||
if (!this.shouldElideExportedIdentifier(specifierInfo.leftName)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the shouldElideExportedIdentifier
check should actually be kept with the previous if
statement, so that implicitly-elided exports are skipped as well. Otherwise, the module.exports = exports.default;
line will be incorrectly added for this code:
type T = number;
export {T as default};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we kept it, the unit test will fail, because the shouldElideExportedIdentifier
returning value of export { x as default } from './foo'
is true
.
In your case, we can actually export both a value and a type as default at the same time (though with TS errors)
But the output will remain only one export default
and no named export, so we can add module.exports = exports.default
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we kept it, the unit test will fail
Good point, sorry for not trying that out. I think my case above is still valid, though, see babel example. If the export is erased due to being a type, it shouldn't count when deciding whether or not to emit module.exports = exports.default
.
This is actually very similar to #806 that I just implemented, but that fix was just for ESM output since CJS happened to already be working. The core issue, I think, is that export {...}
and export {...} from 'foo'
are handled by the same code path, but only the first one should erase type-only exported names. This didn't actually cause any correctness issues for CJS in normal export elision, but it does matter for this case of implementing enableLegacyBabel5ModuleInterop
. Just like in #806, I think the fix is to look ahead to distinguish the two cases.
This PR certainly puts the feature in better shape, so let me merge it now, and I'll do a quick follow-up to refactor the code from #806 to handle the type case here I mentioned. Thanks again!
we can actually export both a value and a type as default at the same time
Agreed that this is possible, but I think if default
is only a type, then it should be ignored for the purposes of deciding whether to emit module.exports = exports.default
. That's consistent with Babel's behavior linked above.
Also, adding a little context here for myself and future readers, since I was needing to remind myself how When using
|
Benchmark resultsBefore this PR: 321 thousand lines per second Measured change: 0.6% faster (0.75% slower to 1.5% faster) |
Follow-up from #804. * When exporting `{T as default}`, treat it as a type-only export that doesn't count as a real default export. * When explicitly doing `export default T`, treat it as a type-only export. * Treat `export enum` as a named export.
Follow-up from #804. * When exporting `{T as default}`, treat it as a type-only export that doesn't count as a real default export. * When explicitly doing `export default T`, treat it as a type-only export. * Treat `export enum` as a named export.
Add
module.exports = exports.default;
for case: