Skip to content
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: expose application config as separate context #13

Merged
merged 10 commits into from
Aug 8, 2019
Merged

Conversation

amcgee
Copy link
Member

@amcgee amcgee commented Jun 11, 2019

This change does three things:

  1. Add a config service which is the parent context of all other services, providing application configuration values such as base url and app name (to be expanded). Expose the new hook useAppConfig allowing access to this config information

  2. consolidate all runtime providers (currently just ConfigProvider and DataProvider) into a single exported Provider component which includes everything needed by a DHIS2 app

  3. Fix/update some of the top-level scripts and service/runtime build configs. Also update examples/cra to use hooks instead of consumer components.

I'm leaving DataProvider in as a top-level export to prevent a breaking change at this stage, it seems like we don't need it just yet and I want to be prudent about what we'd want to include in a 2.0 release.

@amcgee amcgee requested a review from varl June 12, 2019 12:05
@amcgee
Copy link
Member Author

amcgee commented Jun 12, 2019

More eyes and thoughts on the api welcome.

Copy link
Contributor

@HendrikThePendric HendrikThePendric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rethink the CurriedProviders component. I think the main purpose of having this component, is to prevent (potentially very deep) nesting of Providers. But IMO the current implementation comes with too many downsides. Loosing the Provider names is my biggest objection.

import React from 'react'
import PropTypes from 'prop-types'

export const CurriedProviders = ({ providers, children }) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this was implemented as a React component, this shows up as a component in React DevTools. We could possibly consider just implementing this as a function to prevent it happening. Or perhaps change the component name, so it reflects the purpose of this component rather than its technical implementation....

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since each provider is actually exported by its respective service package with the name Provider, we might need to manually override the displayName if we want them to be more informative in DevTools

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that is a good suggestion. Just tried setting a displayName: it works fine, but TypeScript doesn't like it.

However, since we are already doing this

import { Provider as ConfigProvider } from '@dhis2/app-service-config'
import { Provider as DataProvider } from '@dhis2/app-service-data'

and additionally, we'd have to set a displayName....

Wouldn't it make more sense to just use a descriptive prefix in the exported variable name?

Or are there compelling reasons to keep the naming identical in every service?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HendrikThePendric I like this idea. I went ahead and renamed all the exports from service packages (both Data and Context) to be more explicit, so they show up nicely in the React tree

Screenshot 2019-07-09 18 06 58

See below for discussion of top-level provider name

@amcgee
Copy link
Member Author

amcgee commented Jun 18, 2019

@HendrikThePendric thanks for the review!

I think I agree that CurriedProviders could be improved, it's probably a premature optimization. Maybe it's best to just deeply nest the providers for now? It will only be done once (in the exported Provider) and isn't super deep yet.

@amcgee amcgee closed this Jun 18, 2019
@amcgee
Copy link
Member Author

amcgee commented Jun 18, 2019

Accidentally closed sorry!

@amcgee amcgee reopened this Jun 18, 2019
@HendrikThePendric
Copy link
Contributor

Maybe it's best to just deeply nest the providers for now?

Yes I would be in favour of that.

package.json Outdated
@@ -9,17 +9,20 @@
"services/*"
],
"devDependencies": {
"@dhis2/cli-style": "^3.0.1",
"@dhis2/cli-style": "~3.0.0",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE I had to change this to a ~ range (so <3.1.0) because eslint was introduced in cli-style@3.1.0 and doesn't play nice with Typescript. It would be nice to support Typescript with our ESLint config

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working on supporting external ESLint plugins in: dhis2/cli-style#72

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can upgrade to 4.x of cli-style and get support for extended ESLint configs.

@amcgee
Copy link
Member Author

amcgee commented Jul 9, 2019

@HendrikThePendric at long last I have now explicitly nested providers and gotten rid of the problematic <CurriedProviders> component

@amcgee
Copy link
Member Author

amcgee commented Jul 9, 2019

Question @varl @HendrikThePendric et al -

What should the top-level "runtime provider" be called?

I originally had it called just Provider (import { Provider } from '@dhis2/app-runtime') but this isn't very descriptive when viewed in React dev tools (see screenshot above). I've changed it now to DHIS2RuntimeProvider, but maybe that's too verbose? Just RuntimeProvider?

@varl
Copy link
Contributor

varl commented Jul 10, 2019

I've changed it now to DHIS2RuntimeProvider, but maybe that's too verbose? Just RuntimeProvider?

I prefer RuntimeProvider of those options.

Another alternative is ServicesProvider; maybe a combo, RuntimeServicesProvider.

Either way we can drop DHIS2.

edit: my vote goes to RuntimeProvider.

@varl
Copy link
Contributor

varl commented Jul 10, 2019

This looks nice and clear now, introducing a breaking change at this point to clean up the namespace is better to do sooner than later.

Though I wonder if we will eventually end up in a place where re-export all providers individually so they can be tree-shaken out? that will never work when we deeply nest them, nor if we dynamically generate the provider tree at runtime. Only way to avoid the overhead would be if the app declares its own provider tree with the ones that it needs.

Hm, sounds like a future problem. 🤔 Defer.

@amcgee
Copy link
Member Author

amcgee commented Jul 10, 2019

I've changed it now to DHIS2RuntimeProvider, but maybe that's too verbose? Just RuntimeProvider?

I prefer RuntimeProvider of those options.

Another alternative is ServicesProvider; maybe a combo, RuntimeServicesProvider.

Either way we can drop DHIS2.

edit: my vote goes to RuntimeProvider.

@varl yeah I like RuntimeProvider too. Normally I'm also against duplicate namespacing, but in this case maybe it's worth it to prepend DHIS2 so that it's obvious what this thing is in the React tree? Otherwise RuntimeProvider could come from literally anywhere.

We could possibly declare the component with the namespace (DHIS2RuntimeProvider or D2RuntimeProvider) and export it as just RuntimeProvider so that usage is import { RuntimeProvider } from '@dhis2/app-runtime' but it shows up in dev tools with the namespace? That could also be confusing though

Not sure I'm sold one way or the other, just some more thoughts

@amcgee
Copy link
Member Author

amcgee commented Jul 10, 2019

Though I wonder if we will eventually end up in a place where re-export all providers individually so they can be tree-shaken out? that will never work when we deeply nest them, nor if we dynamically generate the provider tree at runtime. Only way to avoid the overhead would be if the app declares its own provider tree with the ones that it needs.

In AppShell world all of these providers are "provided" by the shell, so an App should actually never need them. If apps start breaking out of the Shell and becoming standalone again then maybe separate exports with treeshaking make sense, but I still think they'd want all of them. In any case if we're flopping back to fully independent apps we've got other problems ;-)

@amcgee amcgee marked this pull request as ready for review July 10, 2019 09:28
@varl
Copy link
Contributor

varl commented Jul 10, 2019

@varl yeah I like RuntimeProvider too. Normally I'm also against duplicate namespacing, but in this case maybe it's worth it to prepend DHIS2 so that it's obvious what this thing is in the React tree? Otherwise RuntimeProvider could come from literally anywhere.

That's a valid concern to me, DHIS2 is more explicit than even D2. There can be no question about where that comes from.

@amcgee
Copy link
Member Author

amcgee commented Jul 10, 2019

That's a valid concern to me, DHIS2 is more explicit than even D2. There can be no question about where that comes from.

So DHIS2RuntimeProvider @varl? If so thoughts on the "simplified" import usage mentioned above?

@varl
Copy link
Contributor

varl commented Jul 10, 2019

So DHIS2RuntimeProvider @varl? If so thoughts on the "simplified" import usage mentioned above?

Just as a data point: there are currently 34 hits on all of GitHub in JavaScript for "RuntimeProvider": https://github.com/search?l=JavaScript&q=RuntimeProvider&type=Code

Is the simplified import really necessary? If the name bugs someone they could always do:

import { DHIS2RuntimeProvider as Provider } from '@dhis2/app-runtime`

Then again on the flip-side, if they have multiple RuntimeProvider's they could also do the reverse:

import { RuntimeProvider as DHIS2RuntimeProvider } from '@dhis2/app-runtime`

And we could have a shorter name in our library. 🤔

I prefer being consistent though and going for one or the other.

@amcgee
Copy link
Member Author

amcgee commented Aug 8, 2019

Following a Slack discussion last month, I've set the exported (in code) name to simply Provider but set the displayName of the component to DHIS2RuntimeProvider, which can also change at a later time. This gives informative react-dev-tool output while keeping the API clean

@amcgee amcgee changed the title feat: BREAKING CHANGE expose application config as separate context feat: expose application config as separate context Aug 8, 2019
@amcgee
Copy link
Member Author

amcgee commented Aug 8, 2019

I re-exported DataProvider (but not ConfigProvider), so this is no longer a breaking change and can still be used as-is outside the App Shell. We can make that break later if we want.

@amcgee amcgee merged commit c9aa123 into master Aug 8, 2019
@amcgee amcgee deleted the feat/app-context branch August 8, 2019 11:36
dhis2-bot pushed a commit that referenced this pull request Aug 8, 2019
# [1.4.0](v1.3.0...v1.4.0) (2019-08-08)

### Features

* expose application config as separate context ([#13](#13)) ([c9aa123](c9aa123))
@dhis2-bot
Copy link
Contributor

🎉 This PR is included in version 1.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants