-
Couldn't load subscription status.
- Fork 116
add support for multiple apps using module federation #307
Conversation
|
@kamilogorek I hope you had a good time in your vacation. I recreated the PR I opened earlier. I had to disable some es-lint rules (on specific lines) so I don't introduce breaking changes (if you think we can break support for earlier versions of node, I can update the PR). could you please run the tests? |
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.
Only one small change. Better safe than sorry.
Thanks for your patience, I got pulled off to other things after coming back.
|
Failing test should be trivial to fix, as its just string based assertion. |
reposition eslint comment Co-authored-by: Kamil Ogórek <kamil@sentry.io>
|
@kamilogorek thanks. I approved your suggestion. I’m on mobile, if there are other changes required I l’ll have a look in a few days. (now is my vacation time :) ) |
|
I cannot push to your fork so will have to wait for you. No rush, it won't go anywhere. Enjoy your time off! |
|
Hi @kamilogorek , I think this time I managed to pass the tests. Also added 2 more steps in the integration test that tests my change partially. Can't do a full test because, It would need another test project that uses webpack 5 and that does not work on the older versions of Node. If you would like to have tests for that as well, we can discuss. Otherwise, the PR should be complete and pass the tests at the moment. Could you please run the workflows? |
|
@lobsterkatie @AbhiPrasad @iker-barriocanal can I get a second pair of eyes on this? Would prefer this, as its non-trivial change. +1 from me, so feel free to merge it once approved, as all tests are green. |
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 rather not merging it myself since I don't have context on this webpack plugin, just had a look at the code and can't say whether the bigger picture looks good.
| ) !== -1 | ||
| ) { | ||
| console.log('Saul Goodman, found SENTRY_RELEASE in bundle'); | ||
| process.exit(0); |
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.
Why remove this process.exit, and why not add it to the previous check? Should we expect to find all the assignments? If we successfully find one but fail the others, should we exit? If this is the case, should we move the process.exit(0) in the last block to run after 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.
there used to be only one step check of existence on a string. Now the test does 3-step check (for existence of 3 different strings). when any of them fails, we call process.exit(1). However, calling process.exit(0) should be done when only the last check passes successfully because; let's say if we put it on success case of the first case, the test will simply finish without continuing on the next steps.
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 this is the case, should we move the process.exit(0) in the last block to run after it?
So moving the last process.exit(0) out of the block, so that the logic is the same?
Instead of:
if (!A) exit(1)
if (!B) exit(1)
if (C) exit(0)
if (!C) exit(1)
this instead:
if (!A) exit(1)
if (!B) exit(1)
if (!C) exit(1)
exit(0) <-- and omit this?
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.
Agree with Iker. Updated the test. Last process.exit(0) is redundant anyway, as scripts by default exit with 0
Co-authored-by: iker barriocanal <32816711+iker-barriocanal@users.noreply.github.com>
|
@iker-barriocanal I gave quite an extensive explanation on the context (please see my PR description). If that is not enough, we can move this discussion on a live call and I can explain you the problem we are facing (and other people will face when they start using module federation more and more) and the solution I am proposing. |
|
@hasanayan sorry, I wasn't specific enough. I'm not familiar with this webpack plugin and thus don't want to make the merging decision, which isn't related to your PR at all. Just did a simple review code-wise so I'm definitely not blocking. Updated the comment. |
|
@iker-barriocanal got it. thanks :) |
|
@hasanayan could you verify this change with your current setup before we make any releases? You can use the plugin's master branch with either |
|
@kamilogorek sure! on it now |
|
@kamilogorek it works fine! thanks for all the effort! 👊🏻 |
|
Awesome, thanks for verifying! Released as |
|
Hi @hasanayan, This PR looks interesting. Currently working on Sentry and federated modules in a project.
Could you explain why the remotes need the host app's release version if they have their own respective versions? I assume term |
Hi @raine , accessing versions of remotes from the host app is requirement of our own implementation. We have some cases that require this. For example; if a remote is not accessible at any moment, we want to to be able to report this to the remote's Sentry project with its own respective version. The purpose of this PR was to inject sentry versions of each app (host and all the remotes) into global scope without then colliding with each other. Where you want to access that is up to you. Before this PR, if you would call Sentry.init from any app (host or remote) it would use SENTRY_VERSION variable that is in the global scope and the value would be the hosts version. Because, previously. the variable would be injected only to main (standalone) entrypoint and not the remoteEntry. |
|
@hasanayan I'm investigating a broken build due to ES6 syntax in our app bundle, so forgive me if my assumption is incorrect, but won't this line represent a breaking change: e621cea#diff-e4d441b957e997f8330cdbc7252040be3195c8af431297cf012aa70c00f66c19R5 The injected Sentry release string contains the let sentryRelease = `const _global = (typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}); _global.SENTRY_RELEASE={id:"${version}"};`;but the previous code did not contain the const sentryRelease = `(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}).SENTRY_RELEASE={id:"${version}"};`;So if the consumer of this lib doesn't transpile external libs, it could break on browsers which don't support ES6+ syntax. Happy to provide a PR (and/or create an Issue) if you think the |
|
You are correct @dfdeagle47, thanks for catching this. Updated in #338 |
In #307, a dependency on `webpack-sources` was added to the code, but not to `package.json`. From that PR description: > Adding webpack-sources as dependency breaks the tests (some of the tests use older version(s) of node than webpack-sources requires as minimum). On the other hand, if the user is using module federation, their webpack version is at least 5 and webpack-sources come with it. So, adding webpack-sources as a dependency is not a must. For the same reason, I did not put the require statement at the top of the file (it might be missing for users using an older version of webpack) Though this logic is generally sound, it (specifically the "their webpack version is at least 5 and webpack-sources come with it" part) doesn't account for cases in which webpack is being consumed from a single bundle. In those cases, the _code_ from `webpack-sources` exists in the user's dev environment, but the actual `webpack-sources` _package_ doesn't. (This is true, for example, in nextjs, which pre-compiles many of its dependencies, including webpack[1], into minified bundles.) This can lead to errors when trying to use module federation alongside our nextjs SDK. To fix this, `webpack-sources` has been added as a first-class runtime dependency. Because that guarantees that it will be present and `require`-able, its import has been moved out of a mid-file `try-catch` to instead be a legit import at the top of the file in which it's used. [1] https://github.com/vercel/next.js/blob/c2f48ea86d448c8be1982b46f184b1d2f2d6cd50/packages/next/compiled/webpack/bundle5.js

this is a recreated/clean version of #291
I had to disable a few es-lint rules;
index.js line 82-83: adding webpack-sources as dependency breaks the tests (some of the tests use older version(s) of node than webpack-sources requires as minimum). On the other hand, if the user is using module federation, their webpack version is at least 5 and webpack-sources come with it. So, adding webpack-sources as a dependency is not a must. For the same reason, I did not put the require statement at the top of the file (it might be missing for users using an older version of webpack)
index js line 105; it is what it is, the rule says no-underscore-dangle but the object coming from webpack has it 🤷🏼♂️
TL;DR;
the plugin now injects additional SENTRY_RELEASES variable into global scope as an object that holds versions for all apps keyed by [project]@[org]
When ModuleFederationPlugin is used, assuming the project has a single entry in the webpack config, the build outputs a bundle with two separate entrypoints; usually named as 'main' and 'remoteEntry'. Main is used when the app is running in standalone (host) mode and remoteEntry is used when it is consumed as a remote by another app. In our projects we needed to access the version value for all remotes on our host app so that we can create SentryClient per remote with their own respective versions.
With this PR, the code injected by loader is improved to include a second variable
SENTRY_RELEASESin addition toSENTRY_RELEASE. This code goes to main module and is not loaded when the app is running as remote. So I also added the part to tap into compilation and inject the variable in remoteEntry as well.If this is accepted, we can maybe open another PR on @sentry/browser so that the default release is read from SENTRY_RELEASES and retire SENTRY_RELEASE