kolibri
kolibri copied to clipboard
Separate frontend core API into 'public' and 'internally shared'
Currently, all core shared components are loaded onto the core API object, which leads to a large, bloated object that we load on every single page of Kolibri.
In conversation with @indirectlylit, we posited that the purposes of the core API would be better served by a two tier structure:
-
The public, core API. This would be available to external plugins, and accessable on the
kolibriGlobal
object on thewindow
object. (this would be a subset of what is currently exposed in this way). These would be available in thekolibri
core package, under the same file paths as used for import, but for plugin builds, they would map to the kolibriGlobal object at runtime. -
A shared, internal, library. This would be available at build time for use in Kolibri. The intention of this is to allow us to more easily share components across different internal plugins, without having to overload the core API. These would be put into the
kolibri-common
package, which will not be published, nor supported for external usage.
Lastly - we will continue to use KDS as a place for public, shared components and functionality.
Current single purpose modules that need to be imported independently of the core API (kolibri_module
, kolibri_app
, content_renderer_module
, and plugin_data
) will be migrated to separate packages that are published to NPM.
The proposed mapping of the current API to this new format would be as follows (null indicates it would be removed):
kolibri_module: 'kolibri-module',
kolibri_app: 'kolibri-app',
content_renderer_module: 'kolibri-viewer',
plugin_data: 'kolibri-plugin-data',
'kolibri.client': 'kolibri/client',
'kolibri.heartbeat': 'kolibri/heartbeat',
'kolibri.lib.logging': 'kolibri/logging',
'kolibri.lib.vue': 'vue',
'kolibri.lib.vuex': 'vuex',
'kolibri.lib.vueCompositionApi': '@vue/composition-api',
'kolibri.lib.apiResource': 'kolibri/apiResource',
'kolibri.coreVue.vuex.constants': 'kolibri/constants',
'kolibri.coreVue.vuex.getters': null,
'kolibri.coreVue.vuex.actions': null,
'kolibri.coreVue.vuex.store': null,
'kolibri.coreVue.vuex.mappers': null, // Remove use of remaining mapper
'kolibri.coreVue.components.ScrollingHeader': null,
'kolibri.coreVue.components.Backdrop': 'kolibri-common/components/Backdrop',
'kolibri.coreVue.components.CoachContentLabel': 'kolibri-common/components/labels/CoachContentLabel',
'kolibri.coreVue.components.DownloadButton': 'kolibri-common/components/DownloadButton',
'kolibri.coreVue.components.ProgressBar': null, // Not used
'kolibri.coreVue.components.ContentIcon': 'kolibri-common/components/labels/ContentIcon',
'kolibri.coreVue.components.ProgressIcon': 'kolibri-common/components/labels/ProgressIcon',
'kolibri.coreVue.components.PermissionsIcon': 'kolibri-common/components/labels/PermissionsIcon',
'kolibri.coreVue.components.AppBar': null, // Only used in AppBarPage
'kolibri.coreVue.components.AppBarPage': 'kolibri/components/pages/AppBarPage',
'kolibri.coreVue.components.ImmersivePage': 'kolibri/components/pages/ImmersivePage',
'kolibri.coreVue.components.SideNav': null, // Only used in AppBarPage
'kolibri.coreVue.components.Navbar': null, // Only used in HorizontalNavBarWithOverflowMenu
'kolibri.coreVue.components.NavbarLink': null, // Only used in HorizontalNavBarWithOverflowMenu
'kolibri.coreVue.components.HorizontalNavBarWithOverflowMenu': null, // Should be migrated to AppBarPage, and populated by registered nav items
'kolibri.coreVue.components.LanguageSwitcherModal': 'kolibri-common/components/language-switcher/LanguageSwitcherModal',
'kolibri.coreVue.components.LanguageSwitcherList': 'kolibri/components/language-switcher/LanguageSwitcherList',
'kolibri.coreVue.components.ElapsedTime': 'kolibri-common/components/ElapsedTime',
'kolibri.coreVue.components.PointsIcon': 'kolibri-common/components/labels/PointsIcon',
'kolibri.coreVue.components.TotalPoints': null, // Only used in SideNav
'kolibri.coreVue.components.AuthMessage': 'kolibri/components/AuthMessage',
'kolibri.coreVue.components.FilterTextbox': 'kolibri/components/FilterTextbox',
'kolibri.coreVue.components.CoreSnackbar': null, // Only used in GlobalSnackbar
'kolibri.coreVue.components.CoreMenu': 'kolibri-common/components/CoreMenu',
'kolibri.coreVue.components.CoreMenuDivider': 'kolibri-common/components/CoreMenu/CoreMenuDivider',
'kolibri.coreVue.components.CoreMenuOption': 'kolibri-common/components/CoreMenu/CoreMenuOption',
'kolibri.coreVue.components.CoreTable': 'kolibri/components/CoreTable',
'kolibri.coreVue.components.UserTable': 'kolibri-common/components/UserTable',
'kolibri.coreVue.components.CoreInfoIcon': 'kolibri-common/components/labels/CoreInfoIcon',
'kolibri.coreVue.components.InteractionList': 'kolibri-common/components/quizzes/InteractionList',
'kolibri.coreVue.components.ExamReport': 'kolibri-common/components/quizzes/QuizReport',
'kolibri.coreVue.components.SlotTruncator': 'kolibri-common/components/SlotTruncator',
'kolibri.coreVue.components.TextTruncatorCss': 'kolibri-common/components/TextTruncatorCss',
'kolibri.coreVue.components.TimeDuration': 'kolibri-common/components/TimeDuration',
'kolibri.coreVue.components.MultiPaneLayout': 'kolibri-common/components/MultiPaneLayout',
'kolibri.coreVue.components.CoreFullscreen': 'kolibri-common/components/CoreFullscreen',
'kolibri.coreVue.components.CoreLogo': 'kolibri/components/CoreLogo',
'kolibri.coreVue.components.UiAlert': 'kolibri-design-system/lib/keen/UiAlert',
'kolibri.coreVue.components.UiIconButton': 'kolibri-design-system/lib/keen/UiIconButton',
'kolibri.coreVue.components.UiToolbar': 'kolibri-common/components/keen/UiToolbar.vue',
'kolibri.coreVue.components.PrivacyInfoModal': 'kolibri-common/components/PrivacyInfoModal',
'kolibri.coreVue.components.UserTypeDisplay': 'kolibri-common/components/UserTypeDisplay',
'kolibri.coreVue.components.Draggable': 'kolibri-common/components/sortable/Draggable',
'kolibri.coreVue.components.DragHandle': 'kolibri-common/components/sortable/DragHandle',
'kolibri.coreVue.components.DragContainer': 'kolibri-common/components/sortable/DragContainer',
'kolibri.coreVue.components.DragSortWidget': 'kolibri-common/components/sortable/DragSortWidget',
'kolibri.coreVue.components.FocusTrap': 'kolibri-common/components/FocusTrap',
'kolibri.coreVue.components.BottomAppBar': 'kolibri/components/BottomAppBar',
'kolibri.coreVue.components.BaseToolbar': 'kolibri-common/components/BaseToolbar',
'kolibri.coreVue.components.GenderSelect': 'kolibri-common/components/userAccounts/GenderSelect',
'kolibri.coreVue.components.GenderDisplayText': 'kolibri-common/components/userAccounts/GenderDisplayText',
'kolibri.coreVue.components.BirthYearSelect': 'kolibri-common/components/userAccounts/BirthYearSelect',
'kolibri.coreVue.components.FullNameTextbox': 'kolibri-common/components/userAccounts/FullNameTextbox',
'kolibri.coreVue.components.UsernameTextbox': 'kolibri-common/components/userAccounts/UsernameTextbox',
'kolibri.coreVue.components.PasswordTextbox': 'kolibri-common/components/userAccounts/PasswordTextbox',
'kolibri.coreVue.components.BirthYearDisplayText': 'kolibri-common/components/userAccounts/BirthYearDisplayText',
'kolibri.coreVue.components.PaginatedListContainer': 'kolibri-common/components/PaginatedListContainer',
'kolibri.coreVue.components.PrivacyLinkAndModal': 'kolibri-common/components/userAccounts/PrivacyLinkAndModal.vue',
'kolibri.coreVue.components.LearnOnlyDeviceNotice': 'kolibri-common/components/LearnOnlyDeviceNotice',
'kolibri.coreVue.components.SuggestedTime': 'kolibri-common/components/SuggestedTime',
'kolibri.coreVue.components.PageRoot': null, // Is an incredibly simple boiler plate that should be copied into the places it is used.
'kolibri.coreVue.components.MasteryModel': 'kolibri-common/components/labels/MasteryModel',
'kolibri.coreVue.components.NotificationsRoot': 'kolibri/components/pages/NotificationsRoot',
'kolibri.coreVue.components.KolibriLoadingSnippet': 'kolibri-common/components/KolibriLoadingSnippet',
'kolibri.coreVue.componentSets.sync': 'kolibri-common/components/syncComponentSet', // Migrate to use of individual components and composables
'kolibri.coreVue.router': 'kolibri/router',
'kolibri.coreVue.mixins.responsiveWindowMixin': null,
'kolibri.coreVue.mixins.responsiveElementMixin': null,
'kolibri.coreVue.mixins.commonCoreStrings': 'kolibri/uiText/commonCoreStrings', // Break up into use case specific translator objects
'kolibri.coreVue.mixins.commonTaskStrings': 'kolibri-common/uiText/tasks',
'kolibri.coreVue.mixins.commonSyncElements': 'kolibri-common/mixins/commonSyncElements',
'kolibri.coreVue.mixins.translatedUserKinds': 'kolibri-common/uiText/userKinds',
'kolibri.coreVue.composables.useKResponsiveWindow': 'kolibri-design-system/lib/useKResponsiveWindow',
'kolibri.coreVue.composables.useKShow': 'kolibri-design-system/lib/composables/useKShow',
'kolibri.coreVue.composables.useMinimumKolibriVersion': 'kolibri/composables/useMinimumKolibriVersion',
'kolibri.coreVue.composables.useSnackbar': 'kolibri/composables/useSnackbar',
'kolibri.coreVue.composables.useUser': 'kolibri/composables/useUser',
'kolibri.coreVue.composables.useUserSyncStatus': 'kolibri-common/composables/useUserSyncStatus',
'kolibri.resources': 'kolibri-common/api-resources', // Migrate to individual resource files to give import errors - put in kolibri-common to indicate these are internal APIs - the TaskResource alone will be put into `kolibri/api-resources`
'kolibri.themeConfig': 'kolibri/styles/themeConfig',
'kolibri.urls': 'kolibri/urls',
'kolibri.utils.appCapabilities': 'kolibri/utils/appCapabilities',
'kolibri.utils.browserInfo': 'kolibri/utils/browserInfo',
'kolibri.utils.bytesForHumans': 'kolibri/uiText/bytesForHumans',
'kolibri.utils.CatchErrors': 'kolibri/utils/CatchErrors',
'kolibri.utils.clientFactory': 'kolibri/utils/baseClient',
'kolibri.utils.contentNode': null, // Get rid of the use of this completely
'kolibri.utils.coreBannerContent': 'kolibri-common/utils/coreBannerContent',
'kolibri.utils.exams': 'kolibri-common/quizzes/utils',
'kolibri.utils.filterUsersByNames': 'kolibri-common/utils/filterUsersByNames',
'kolibri.utils.i18n': 'kolibri/utils/i18n',
'kolibri.utils.licenseTranslations': 'kolibri/uiText/licenses',
'kolibri.utils.loginComponents': 'kolibri-common/utils/loginComponents',
'kolibri.utils.navComponents': 'kolibri/utils/navComponents',
'kolibri.utils.redirectBrowser': 'kolibri/utils/redirectBrowser',
'kolibri.utils.samePageCheckGenerator': 'kolibri-common/utils/samePageCheckGenerator',
'kolibri.utils.serverClock': 'kolibri/utils/serverClock',
'kolibri.utils.shuffled': 'kolibri-common/utils/shuffled',
'kolibri.utils.sortLanguages': null, // Move into i18n module
'kolibri.utils.syncTaskUtils': 'kolibri-common/utils/syncTaskUtils', // Break this up, migrate constants to constants
'kolibri.utils.UserType': 'kolibri-common/utils/userType',
'kolibri.utils.validators': 'kolibri/utils/validators',
'kolibri.utils.coreStrings': 'kolibri/uiText/commonCoreStrings', // See above about breaking this up into more discrete uiText translators
'kolibri.utils.objectSpecs': 'kolibri/utils/objectSpecs'
This spec would also be used to create a new migration script to do the updating of import paths automatically, which could then be used by plugins for an easy migration path (but would throw a warning of anything not exposed by kolibri
is used).
### Prerequisites
- [ ] https://github.com/learningequality/kolibri/issues/11724
- [ ] https://github.com/learningequality/kolibri/issues/11725
- [ ] https://github.com/learningequality/kolibri/issues/11723
- [ ] https://github.com/learningequality/kolibri/issues/11729
- [ ] https://github.com/learningequality/kolibri/issues/11731
- [ ] https://github.com/learningequality/kolibri/issues/11561
- [ ] https://github.com/learningequality/kolibri/issues/12558
- [ ] https://github.com/learningequality/kolibri/issues/12582
- [ ] https://github.com/learningequality/kolibri/issues/12599
- [ ] https://github.com/learningequality/kolibri/issues/12601
- [ ] https://github.com/learningequality/kolibri/issues/12603
- [ ] https://github.com/learningequality/kolibri/issues/12557
- [ ] https://github.com/learningequality/kolibri/issues/12625
- [ ] https://github.com/learningequality/kolibri/pull/12698
- [ ] https://github.com/learningequality/kolibri/pull/12699
- [ ] https://github.com/learningequality/kolibri/pull/12701
- [ ] https://github.com/learningequality/kolibri/pull/12700
### Tasks
- [x] Create migration script that reads file imports in source code and maps them to the updated import paths
- [x] Show a warning to a user if a mapped import maps to null - provide explanatory text for these cases to allow for remediation
- [x] Migrate the independent packages into their own packages in the kolibri packages directory
- [x] Create kolibri package and migrate all shared modules there - setting exports explicitly in the package.json
- [x] Migrate all common modules to kolibri-common
- [x] Remove all core aliases and update core externals to map to a spec object defined on the new kolibri package
- [ ] https://github.com/learningequality/kolibri-sentry-plugin/issues/5