-
Notifications
You must be signed in to change notification settings - Fork 143
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
Interoperability issue of embroider and loader.js #539
Comments
Thanks @simonihmig, nice work. |
Here is a PoC PR: #540 |
FWIW, I want to remove that functionality. See ember-cli/loader.js#114 (which was what lead to creating the option you mentioned ember-cli/loader.js#129). I'd like to try to push forward the work in ember-cli/loader.js#128 and deprecate/remove that functionality in |
I'd prefer if we could avoid having differing behaviors here between "classic build" and Embroider builds, so making |
@rwjblue Thanks for chiming in, and adding this context! Do you expect this to be done (i.e. remove that functionality, release a new major) in a relatively short period of time (like days instead of weeks)? Or should we try to get a workaround added to embroider as an interim solution? The thing is that
I agree! |
We definitely can get it done quickly, but I'd need help reviving that PR and getting it over the line. I've got time to help with reviews/releases/etc but not impl.
IMHO, landing the fix in your other PR is totally fine, but I want to also land the loader.js changes so that we attack the issue from both angles and eventually as projects upgrade the divergence is reduced. |
Sure. But it seems the PR's author has addressed most of your feedback after your initial review over there! Could you re-review this, or what would the next step be? If the PR needs someone to continue the work, in case the original submitter is not available anymore - it's been >3 years 🙀 - then please ping me, maybe I can help there! |
Currently the I18n module shim return an object. Per AMD/loader.js, the properties on the object becomes named exports of the module, i.e. `import { t } from 'I18n';`. However, this is not how we actually consume this module. We always do `import I18n from 'I18n';`. The returned object from the shim (`window.I18n`) does NOT have a `default` property on it. This is only working because loader.js has a `makeDefaultExport` feature that defaults to true, which we are relying on to synthesize the default export for us. That feature has been noted as undesirable and may some day be deprecated. In Embroider, it specifically disables the feature in loader.js. embroider-build/embroider#539
Currently the I18n module shim return an object. Per AMD/loader.js, the properties on the object becomes named exports of the module, i.e. `import { t } from 'I18n';`. However, this is not how we actually consume this module. We always do `import I18n from 'I18n';`. The returned object from the shim (`window.I18n`) does NOT have a `default` property on it. This is only working because loader.js has a `makeDefaultExport` feature that defaults to true, which we are relying on to synthesize the default export for us. That feature has been noted as undesirable and may some day be deprecated. In Embroider, it specifically disables the feature in loader.js. embroider-build/embroider#539
seems I have a talent for the ugly issues (after #509), just spent most of the day pulling my hair out on this one...
Tests were failing for me randomly in an addon, but only when building with Embroider. It turned out that a component could be wrongly resolved, depending on the timing.
Having components A and B, and B extending from A, if B was resolved before A, everything seems fine. The other way around however, when resolving B you would get back the module for A.
After a long debugging session, I think I have found the reason.
ember-resolver
would try to get the default export of a module if available here.This works fine in a classic build, when you look at the compiled vendor.js, then each module in its AMD form has an explicit default export, like this:
This is however not the case with a Webpack build.
Now the problem lies with
loader.js
, which mutates a module export by creating a default export here, if it is not already present (remember, it is present in a classic build) and themakeDefaultExport
option is set (which it is by default).But in the case of a webpack-build module that exports a component, this creates a
default
property on the exported class! 😱So when B is resolved first, it creates
B.default
(pointing toB
again). If thenA
is resolved,A.default
does not exist, so alsoA.default
is created (pointing toa
). This side-effect of extending the classes seems ugly enough, but at least it works so far.Now the other way around:
A
is resolved first,A.default
is created, referencingA
again. Now it is the turn forB
, and here this mess breaks everything: so asB
extends fromA
,B.default
is already defined, but it still points toA
! So nodefault
is created forB
by loader.js, as it already inherited it fromA
. Butember-resolver
will now useB.default
(same place here) which still refers toA
. So by trying to resolve componentB
, you get a reference to classA
! 🙈When patching my local
loader.js
, specifically settingmakeDefaultExport
to false here, all the failing tests were gone. So that confirms my observation.Tbh, the choice to also extend a function as the module export here seems odd to me! 🤔
The text was updated successfully, but these errors were encountered: