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

AngularLoader: Support 'settingsFactory' callbacks in angular modules. #18731

Merged
merged 1 commit into from
Oct 13, 2020

Conversation

colemanw
Copy link
Member

@colemanw colemanw commented Oct 10, 2020

Overview

This allows Angular modules with complex/expensive data to provide it with a callback, which will only be invoked if the module is actively loaded on the page.

Docs updated at https://lab.civicrm.org/documentation/docs/dev/-/merge_requests/862

Before

Angular modules can declare settings which are calculated on every AngularLoader->load() and then discarded if the module isn't needed on the current page. This can get expensive.

After

Angular modules can declare settingsFactory which is only invoked when a module is needed on the current page.

Comments

Currently (and I was a bit surprised by this) the full list of Angular modules is not cached anywhere. So hook_civicrm_angularModules runs on every page, and each module's settings is loaded every time. That's a good thing from the POV of permissions (if say a module's settings are different for different users) but it's terrible for performance.

Switching modules to use settingsFactory can save cycles in the short-term, and be even better in the long-term when we get around to caching the list of modules, as only the name of the callback will be cached, not the array of settings. This will also keep the per-user settings a possibility even with global caching of the modules.

@civibot civibot bot added the master label Oct 10, 2020
@civibot
Copy link

civibot bot commented Oct 10, 2020

(Standard links)

@totten
Copy link
Member

totten commented Oct 10, 2020

This is a good idea. The test looks sensible (though I added a suggestion above for more assertions).

Currently (and I was a bit surprised by this) the full list of Angular modules is not cached anywhere. So hook_civicrm_angularModules runs on every page, and each module's settings is loaded every time. That's a good thing from the POV of permissions (if say a module's settings are different for different users) but it's terrible for performance.

Switching modules to use settingsFactory can save cycles in the short-term, and be even better in the long-term when we get around to caching the list of modules, as only the name of the callback will be cached, not the array of settings. This will also keep the per-user settings a possibility even with global caching of the modules.

Yup, in a world where modules are loaded conditionally (e.g. conditioned on the server-route; e.g. conditioned onfindActiveModules() and resolveDependencies()), putting all settings in the metadata is not ideal. It makes much more sense for the metadata to have a callback (settingsFactory).

From a DX POV, it's nice for the module metadata to be always-fresh/live. But then again...

  • afforms module list is cached. (Though, IMHO, this works out for a different reason -- afform docs are usually created/deleted via API, so we can affirmatively clear the cache when needed. Regular modules don't have that.)
  • For an overall Angular module cache, we could probably use a setting for developers to enable/disable it (e.g. probably assetCache but maybe debug_enabled).

In any case, regardless of when/how/if caching is added to the module list, we should probably phase-out the use of $angularModules['...']['settings'] and favor settingsFactory...

@colemanw
Copy link
Member Author

Thanks @totten. I updated the test with half of your suggestion. Resources->getSettings() doesn't actually fetch all settings, only the ones loaded via a factory.

@colemanw colemanw force-pushed the angularSettingsFactory branch 2 times, most recently from c4ade9a to dbb704f Compare October 11, 2020 15:44
@colemanw
Copy link
Member Author

@totten actually nevermind the settings do all come back, I just needed to fix the logic. So now I've implemented your full suggestion to improve the test.

This allows Angular modules with complex/expensive data to provide it with a callback,
which will only be invoked if the module is actively loaded on the page.

Normally, module settings are calculated on every page request, even if they are not needed.
@totten
Copy link
Member

totten commented Oct 13, 2020

@colemanw Glad to hear all settings come back.

I did some r-run by writing+testing a patch that relies on this -- #18749 (update crmMailing). This worked in my testing. One possible snag to note -- CRM_Mailing_Info::getAngularModules() calls addPermissions(). This function also populates settings-data that's only needed conditionally, but I don't think a settingsFactory could handle it.

TBH, I sort of feel that the angularModules should be more like a Bundle or Collection (eg building on CollectionTrait / CollectionAdderTrait), but I don't have a clear enough thought on how transition it. (The tricky bits are that (1) angular modules have dependencies, which aren't in the bundle model (2) angular modules existing contract is presented as a different array/data-structure.) So I think it's OK to punt that for a bit.

Marking this "merge ready". @colemanw , if the example (#18749) is OK, and if you're OK punting the other bits, then let's merge.

@totten totten added the merge ready PR will be merged after a few days if there are no objections label Oct 13, 2020
@colemanw colemanw merged commit af8662f into civicrm:master Oct 13, 2020
@colemanw colemanw deleted the angularSettingsFactory branch October 13, 2020 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has-test master merge ready PR will be merged after a few days if there are no objections
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants