-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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: support canonical module #5040
Conversation
test/unit/utils.spec.js
Outdated
@@ -288,6 +290,27 @@ describe('lib/utils', function () { | |||
].join('\n'); | |||
expect(stringify(expected), 'to be', actual); | |||
}); | |||
|
|||
it('should represent modules', async function () { | |||
if (process.browser) { |
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.
The esm-utils
and node:path
modules both come through as undefined in browser (which is kinda expected).
In theory though, it probably isn't necessary to use esm-utils
at all, and the path logic we are using is just a very basic join, which we can probably safely default to __dirname + '/fixtures/module.mjs'
and load via a dynamic import import()
(Maybe keep the path module around for node+windows support)
However, it appears the current version of rollup has issues parsing that. It appears rollup is ~2 major versions out of date, so I wouldn't be surprised if it just isn't equipped to handle "modern" js syntax.
I tried bumping rollup version and it was not straightforward. I'm sure someone with more rollup experience can easily knock it out, but it felt out of scope for what I was trying to achieve with this fix.
Updated original ticket with better reproduction: #4887 Still open to alternative approaches to handle the "this should only run as part of serverside tests", but that is more on the testing front rather than the implementation. |
lib/utils.js
Outdated
@@ -399,6 +399,12 @@ exports.canonicalize = function canonicalize(value, stack, typeHint) { | |||
break; | |||
} | |||
/* falls through */ | |||
case 'module': |
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.
With a bit more manual testing (when trying to reproduce) I think this issue may fundamentally occur anytime you are dealing with null-prototyped instances...
Which is an overall rare occurrence, but maybe this isn't the right approach?
e.g.
const foo = Object.create(null, {
[Symbol.toStringTag]: { value: 'Foo' },
bing: { get: () => 'bong' }
});
Object.prototype.toString.call(x); // '[object Foo]'
foo + ''; // Uncaught TypeError: Cannot convert object to primitive value
So while this solution works for modules, I don't think it actually solves the underlying issue
}); | ||
const expected = [ | ||
'{', | ||
' "[Symbol.toStringTag]": "Foo"', |
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 wanted to either:
- Always expose the
toStringTag
if present - Never expose the
toStringTag
Then we could just return object
instead of null-prototype
and the logic would work.
Only really need a special case if we are conditionally exposing it...
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 don't have a strong preference either way. What's working now fixes the issue and is nicely informative on my end.
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.
Looks great to me, thanks - and with great tests! Confirmed that linking locally fixes the issue. ✅
Will wait a bit for another reviewer just to be safe.
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.
Generally approve 👍
lib/utils.js
Outdated
} else if ( | ||
typeof value === 'object' && | ||
// eslint-disable-next-line no-prototype-builtins | ||
!Object.prototype.isPrototypeOf(value) | ||
) { |
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.
We can probably do this instead? And avoid having to opt out of the eslint rules?
} else if ( | |
typeof value === 'object' && | |
// eslint-disable-next-line no-prototype-builtins | |
!Object.prototype.isPrototypeOf(value) | |
) { | |
} else if (Object.getPrototypeOf(value) === null) { |
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.
Yup that is cleaner, pushed a small update
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.
🚀 🚀
Released in |
ORIGINAL PR: #4888
Closed out of staleness, but now trying to re-open under new maintenance
Description of the Change
Handle canonicalizing Module, prevent implicit stringification failures
Alternate Designs
Why should this be in core?
Current module canonicalization is broken, see #4887
Benefits
Tests can properly handle errors with a Module inside
Possible Drawbacks
Small chance there is some internal/custom handling expecting canonicalization of modules to fail... Seems unlikely?
Applicable issues
Fixes #4887
Bug fix, patch release