-
Notifications
You must be signed in to change notification settings - Fork 64
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
feat: JavaScript file configuration of apps #474
feat: JavaScript file configuration of apps #474
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #474 +/- ##
==========================================
+ Coverage 82.87% 83.05% +0.17%
==========================================
Files 40 40
Lines 1051 1062 +11
Branches 189 194 +5
==========================================
+ Hits 871 882 +11
Misses 168 168
Partials 12 12
☔ View full report in Codecov by Sentry. |
@@ -75,6 +75,7 @@ | |||
}, | |||
"peerDependencies": { | |||
"@edx/paragon": ">= 10.0.0 < 21.0.0", | |||
"@edx/frontend-build": ">= 8.1.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.
This is the version of frontend-build that enables env.config
as a magic import. So we didn't have a peer dependency here before, but we technically do now. It's unlikely to bite anyone since 8.1.0 was quite a while ago.
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.
[curious/thinking aloud] Is there a way we could treat @edx/frontend-build
as an optional dependency instead (docs)? In theory, someone may have created or could create an MFE using @edx/frontend-platform
without @edx/frontend-build
; it feels like introducing the peer dependency is potentially a breaking change as a result, even though I agree it's probably fair to assume this won't bite anyone.
I believe the challenge with treating @edx/frontend-build
as an optionalDependency
would be conditionally importing env.config.js
and only using it, if the import was successful.
FWIW, I don't feel too strongly about this suggestion; just thinking of potential alternatives that don't require a coupling with @edx/frontend-build
for the Webpack implementation should consumers of @edx/frontend-platform
ever want to use a different implementation of Webpack than @edx/frontend-build
😃
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.
For the record (Adam and I talked about this a bit offline) - the only way I could get env.config
to work as an import was to use specialized webpack config (in frontend-build) to fallback to an empty import if the file couldn't be found. Since the entire mechanism is predicated on that behavior, and it's implemented in frontend-build, it feels a bit unavoidable to add the peer dependency. There's just not a way I've ever found to do this without that added magic (which was merged into frontend-build some time ago in openedx/frontend-build#200)
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.
FWIW, we may have ended up needing to do something similar anyways given the direction this PR is headed to be able to fallback to a local Paragon version in the externally hosted Paragon CSS urls or if a externally hosted Paragon CSS urls fails to load, we need to expose the paths to the locally installed Paragon theme via frontend-build such that frontend-platform has access to them (otherwise, each MFE would have to pass args to initialize
which feels like could be avoided).
/* | ||
* Set or overrides configuration through an API. | ||
* This method allows runtime configuration. | ||
* Set a basic configuration when an error happen and allow initError and display the ErrorPage. | ||
*/ | ||
|
||
export async function runtimeConfig() { | ||
async function runtimeConfig() { |
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 took away the export
on this line intentionally, as this is an internal function and nothing is consuming the export.
I do not have my head fully wrapped around this, but I trust the reviews of those that do. With my Build-Test-Release hat on, though, the questions that the ADR leaves me with are: Does this jive well with runtime configuration, which is now required by the community release? And are you happy with how runtime config is implemented, now that there's a deprecation path for |
const loggingServiceImpl = getConfig().loggingService || loggingService; | ||
const analyticsServiceImpl = getConfig().analyticsService || analyticsService; | ||
const authServiceImpl = getConfig().authService || authService; |
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.
Neat 🔥
For the above reasons, we will deprecate environment variable configuration in favor of JavaScript | ||
file configuration. |
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 might want to keep the legacy environment variable configuration around and not deprecate it. There's not much reason to deprecate it that I can think of (e.g., not much maintenance overhead to support it), though it'll probably start to get used less with the introduction of env.config
and the MFE runtime config API.
We could observe usage over time and, if we see that very few MFEs use the environment variable configuration mechanism then, deprecate at that time.
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 hear you - the thing that comes to mind is that if we start using env.config.js so that we can pass real data types into the app instead of just strings, we'll presumably start removing the code that converts "false"
to false
, etc., in which case for given MFEs the old config won't work properly anymore. Unless we just make the logic more complicated to accommodate both. 😬 I guess this is a problem even in the interim before an official deprecation/removal. Hm - will have to think about this more.
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.
On second thought, it may not be too much of a problem. The MFEs tend to have arguments in their calls to initialize
where they pull config out of process.env
if it exists. The new jsFileConfig
function runs after that. The first can continue to massage strings into other data types, and the second doesn't have to worry about it. They can co-exist.
@kdmccormick So this is compatible with runtime config, and solves some use cases that that can't solve around extensibility and customization. In their load order, runtime config wins/is the last applied. If I had to look in a crystal ball, I'd say we ultimately use runtime config for most configuration that JSON can handle, so to speak, and this becomes a mechanism for doing more complex config at build-time, maybe centered around customization of classes, functions, etc. If/when modular MFEs become a thing it's possible all of this becomes moot and we re-invent the whole system, but I figure we'll cross that bridge when we come to it. Between this and @adamstankiewicz 's comments, I'm open to backing off the stance in the ADR. But it does sort of suck to have to leave in a bunch of data massaging from strings to ints/bools/nulls/arrays/etc whenever something gets loaded via |
@davidjoy Cool, thanks for the clarification! I recommend adding that note the ADR.
Since Olive, the community-supported release requires runtime config (static config isn't even an option). Furthermore, if some setting values need to be changed between releases (eg |
b684963
to
6d62612
Compare
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.
This looks really cool!
373c2f4
to
1c5b644
Compare
@kdmccormick and @adamstankiewicz - so I think after reading through everything here, I'm not going to back off the deprecation of environment variable config. I'm also not 100% sure I have the will to fully follow through on getting rid of it myself. I think this probably looks like filing a DEPR ticket with all the deets on how we get rid of it, yeah? Just trying to think through how to deliver on the intention in the ADR. 🤔 |
This adds the ability to configure an application via an env.config.js file rather than environment variables or .env files. This mechanism is much more flexible and powerful than environment variables as described in the associated ADR. It also improves documentation around how to configure applications, providing more detail on the various methods. Finally, it allows the logging, analytics, and auth services to be configured via the configuration document now that we can supply an alternate implementation in an env.config.js file. This allows configuration of these services without forking the MFE.
fixing a few typos, adding a section about the relationship between JS file config and runtime config, and cleaning up some formatting.
Based on PR feedback - be clearer about how the configuration methods overlap and what their best use cases are.
1c5b644
to
1458037
Compare
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.
This is great! Thanks David!
Sounds good! If you are able to write a DEPR ticket with removal steps, and then nudge it in the direction of actually happening (eg, emitting a warning when static config is used), then I think it's pretty likely someone in Frontend WG would eventually be able to drive the removal. |
Turns out if you put each test in its own file, jest.mock can be used to change the implementation of env.config.js for each test file. This lets us test all the clauses in jsFileConfig. It also means we no longer need the actual env.config.js file, since we’re mocking it!
Previous commit removed this file, forgetting that it’s also necessary for the example app. Reinstated it here with a value specific to the example app so we can still prove the test suite works.
ff80c6c
to
e44f959
Compare
So I'm going to merge this first, then create the DEPR ticket if only so I can link to the ADR in this PR once it hits its final home on master. |
My only concern with the deprecation of the In a world with only MFE runtime config and This becomes a developer experience issue in that I need to have the MFE runtime config API configured in edx-platform to be able to do any development with my private config setting in the MFE, whereas before we could just create a Is there a possibility we could support a |
@@ -75,6 +75,7 @@ | |||
}, | |||
"peerDependencies": { | |||
"@edx/paragon": ">= 10.0.0 < 21.0.0", | |||
"@edx/frontend-build": ">= 8.1.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.
FWIW, we may have ended up needing to do something similar anyways given the direction this PR is headed to be able to fallback to a local Paragon version in the externally hosted Paragon CSS urls or if a externally hosted Paragon CSS urls fails to load, we need to expose the paths to the locally installed Paragon theme via frontend-build such that frontend-platform has access to them (otherwise, each MFE would have to pass args to initialize
which feels like could be avoided).
Note that the env.config.js file in frontend-platform's root directory is NOT used by the actual | ||
initialization code, it's just there for the test suite and example application. | ||
*/ | ||
import envConfig from 'env.config'; // eslint-disable-line import/no-unresolved |
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.
[curious] Could we modify the default ESLint rules in @edx/frontend-build
to disable the import/no-unresolved
rule specifically for env.config
? That way, we wouldn't need to disable the ESLint rule here. Given the file is exposed via @edx/frontend-build
, it feels reasonable to have @edx/frontend-build
make it pass ESLint, too.
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.
Can you do that with import/no-unresolved? If so, sure, sounds like a nice piece of polish. 😄
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 also think this is a good idea. Having a quick and easy way to override anything that's coming from runtime config when doing local dev is huge. |
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.
This is awesome! ❤️ how well documented everything is!
Picking out the relevant bit to reply to the whole of @adamstankiewicz's comment:
I was assuming The only question I still have is about an |
So this is up for debate, but I was assuming (and didn't explicitly say anywhere) that env.config.js would be as @arbrandes describes - it wouldn't be checked in, but there'd be an env.config.js.example file that is, and that file would probably contain a helpful comment and a reasonable development/local configuration. I think that solves the 'private' situation. env.config.js would be .gitignore'd. As for testing, we could add something like this to the
That would work, and not require us to have a test version of the The alternative might be to go back to frontend-build and try to make it do something more conditional based on |
We have agreed we’d like to DEPR environment variable config, so I’m going to merge the ADR as “Accepted”
0c1df3b
to
84adafd
Compare
|
Thanks everyone for your input and smarts. 😄 Next up, a DEPR ticket and guidance on how to move forward. |
Hi @davidjoy! I am currently working on upgrading the frontend-app-learner-portal-programs to React 17. However, I am facing an issue when upgrading the frontend platform to version |
@Mashal-m Note that See this comment thread for a bit more detail on this coupling with From the linked comment thread above:
Looks like our assumption at the time that introducing the coupling between Based on your screenshots, the specific issue is importing If you're also running into issues when running/building // from https://github.com/openedx/frontend-build/blob/master/config/webpack.common.config.js
// (applied during `npm start` and `npm run build`)
{
// ....
resolve: {
alias: {
'env.config': path.resolve(process.cwd(), './env.config'),
},
fallback: {
// This causes the system to return an empty object if it can't find an env.config.js file in
// the application being built.
'env.config': false,
},
} |
Oof, I think @adamstankiewicz covered it well, so I don't have much to add. Let us know how it goes. |
This adds the ability to configure an application via an env.config.js file rather than environment variables or .env files. This mechanism is much more flexible and powerful than environment variables as described in the associated ADR.
It also improves documentation around how to configure applications, providing more detail on the various methods.
Finally, it allows the logging, analytics, and auth services to be configured via the configuration document now that we can supply an alternate implementation in an env.config.js file. This allows configuration of these services without forking the MFE.
It doesn't remove the ability to supply a service implementation via the
initialize()
function's arguments since that would technically be a breaking change and it could conceivably be in use in forks today. At a later date we could choose to remove that mechanism.fixes openedx/wg-frontend#11
Description:
Describe what this pull request changes, and why. Include implications for people using this change.
Merge checklist:
frontend-platform
. This can be done by runningnpm start
and opening http://localhost:8080.module.config.js
file infrontend-build
.fix
,feat
) and is appropriate for your code change. Consider whether your code is a breaking change, and modify your commit accordingly.Post merge: