@openmrs/esm-routes 7.0.0 → 7.0.1-pre.3256

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
- [0] Successfully compiled: 9 files with swc (130.35ms)
1
+ [0] Successfully compiled: 9 files with swc (116.2ms)
2
2
  [0] swc --strip-leading-paths src -d dist exited with code 0
3
3
  [1] tsc --project tsconfig.build.json exited with code 0
@@ -1,6 +1,6 @@
1
1
  import { attach, registerExtension, registerModal, registerWorkspace, registerWorkspaceGroup } from "@openmrs/esm-extensions";
2
- import { getLoader } from "./app.js";
3
2
  import { registerFeatureFlag } from "@openmrs/esm-feature-flags";
3
+ import { loadLifeCycles } from "./load-lifecycles.js";
4
4
  /**
5
5
  * This function registers an extension definition with the framework and will
6
6
  * attach the extension to any configured slots.
@@ -22,35 +22,22 @@ a 'slot' property. Only the 'slots' property will be honored.`);
22
22
  const slots = extension.slots ? extension.slots : extension.slot ? [
23
23
  extension.slot
24
24
  ] : [];
25
- if (!extension.component && !extension.load) {
25
+ if (!extension.component) {
26
26
  console.error(`The extension ${name} from ${appName} is missing a 'component' entry and thus cannot be registered.
27
27
  To fix this, ensure that you define a 'component' field inside the extension definition.`, extension);
28
28
  return;
29
29
  }
30
- let loader = undefined;
31
- if (extension.component) {
32
- loader = getLoader(appName, extension.component);
33
- } else if (extension.load) {
34
- if (typeof extension.load !== 'function') {
35
- console.error(`The extension ${name} from ${appName} declares a 'load' property that is not a function. This is not
36
- supported, so the extension will not be loaded.`);
37
- return;
38
- }
39
- loader = extension.load;
40
- }
41
- if (loader) {
42
- registerExtension({
43
- name,
44
- load: loader,
45
- meta: extension.meta || {},
46
- order: extension.order,
47
- moduleName: appName,
48
- privileges: extension.privileges,
49
- online: extension.online ?? true,
50
- offline: extension.offline ?? false,
51
- featureFlag: extension.featureFlag
52
- });
53
- }
30
+ registerExtension({
31
+ name,
32
+ load: ()=>loadLifeCycles(appName, extension.component),
33
+ meta: extension.meta || {},
34
+ order: extension.order,
35
+ moduleName: appName,
36
+ privileges: extension.privileges,
37
+ online: extension.online ?? true,
38
+ offline: extension.offline ?? false,
39
+ featureFlag: extension.featureFlag
40
+ });
54
41
  for (const slot of slots){
55
42
  attach(slot, name);
56
43
  }
@@ -68,29 +55,16 @@ registered. To fix this, ensure that you define the "name" field inside the
68
55
  modal definition.`, modal);
69
56
  return;
70
57
  }
71
- if (!modal.component && !modal.load) {
58
+ if (!modal.component) {
72
59
  console.error(`The modal ${name} from ${appName} is missing a 'component' entry and thus cannot be registered.
73
60
  To fix this, ensure that you define a 'component' field inside the modal definition.`, modal);
74
61
  return;
75
62
  }
76
- let loader = undefined;
77
- if (modal.component) {
78
- loader = getLoader(appName, modal.component);
79
- } else if (modal.load) {
80
- if (typeof modal.load !== 'function') {
81
- console.error(`The modal ${name} from ${appName} declares a 'load' property that is not a function. This is not
82
- supported, so the modal will not be loaded.`);
83
- return;
84
- }
85
- loader = modal.load;
86
- }
87
- if (loader) {
88
- registerModal({
89
- name,
90
- load: loader,
91
- moduleName: appName
92
- });
93
- }
63
+ registerModal({
64
+ name,
65
+ moduleName: appName,
66
+ load: ()=>loadLifeCycles(appName, modal.component)
67
+ });
94
68
  }
95
69
  /**
96
70
  * This function registers a workspace definition with the framework so that it can be launched.
@@ -110,36 +84,24 @@ To fix this, ensure that you define the "name" field inside the workspace defini
110
84
  To fix this, ensure that you define the "title" field inside the workspace definition.`, workspace);
111
85
  return;
112
86
  }
113
- if (!workspace.component && !workspace.load) {
87
+ if (!workspace.component) {
114
88
  console.error(`The workspace ${name} from ${appName} is missing a 'component' entry and thus cannot be registered.
115
89
  To fix this, ensure that you define a 'component' field inside the workspace definition.`, workspace);
116
90
  return;
117
91
  }
118
- let loader = undefined;
119
- if (workspace.component) {
120
- loader = getLoader(appName, workspace.component);
121
- } else if (workspace.load) {
122
- if (typeof workspace.load !== 'function') {
123
- console.error(`The workspace ${name} from ${appName} declares a 'load' property that is not a function. This is not
124
- supported, so the workspace will not be loaded.`);
125
- return;
126
- }
127
- loader = workspace.load;
128
- }
129
- if (loader) {
130
- registerWorkspace({
131
- name,
132
- title,
133
- load: loader,
134
- moduleName: appName,
135
- type: workspace.type,
136
- canHide: workspace.canHide,
137
- canMaximize: workspace.canMaximize,
138
- width: workspace.width,
139
- preferredWindowSize: workspace.preferredWindowSize,
140
- groups: workspace.groups
141
- });
142
- }
92
+ registerWorkspace({
93
+ name,
94
+ title,
95
+ component: workspace.component,
96
+ moduleName: appName,
97
+ type: workspace.type,
98
+ canHide: workspace.canHide,
99
+ canMaximize: workspace.canMaximize,
100
+ width: workspace.width,
101
+ preferredWindowSize: workspace.preferredWindowSize,
102
+ groups: workspace.groups,
103
+ load: ()=>loadLifeCycles(appName, workspace.component)
104
+ });
143
105
  for (const group of workspace.groups || []){
144
106
  registerWorkspaceGroup({
145
107
  name: group,
@@ -1,3 +1 @@
1
- import { type LifeCycles } from 'single-spa';
2
- export declare const emptyLifecycle: LifeCycles<never>;
3
1
  export declare function routeRegex(regex: RegExp, location: Location): boolean;
@@ -1,14 +1,3 @@
1
- export const emptyLifecycle = {
2
- bootstrap () {
3
- return Promise.resolve();
4
- },
5
- mount () {
6
- return Promise.resolve();
7
- },
8
- unmount () {
9
- return Promise.resolve();
10
- }
11
- };
12
1
  export function routeRegex(regex, location) {
13
2
  const result = regex.test(location.pathname.replace(window.getOpenmrsSpaBase(), ''));
14
3
  return result;
@@ -1,3 +1,3 @@
1
- export { initializeApp } from './app';
2
1
  export { registerApp, finishRegisteringAllApps } from './pages';
3
2
  export { tryRegisterExtension } from './components';
3
+ export * from './load-lifecycles';
@@ -1,3 +1,3 @@
1
- export { initializeApp } from "./app.js";
2
1
  export { registerApp, finishRegisteringAllApps } from "./pages.js";
3
2
  export { tryRegisterExtension } from "./components.js";
3
+ export * from "./load-lifecycles.js";
@@ -0,0 +1,18 @@
1
+ import { type LifeCycles } from 'single-spa';
2
+ /**
3
+ * This function loads a single-spa Lifecycles from the given app. The Lifecycles should be
4
+ * created using `getAsyncLifecycle()` or `getSyncLifecycle()` and exported in the app's
5
+ * index.ts file.
6
+ * The function is lazy and ensures that the appropriate module is loaded,
7
+ * that the module's `startupApp()` is called before the component is loaded. It
8
+ * then calls the component function, which should return either a single-spa
9
+ * {@link LifeCycles} object or a {@link Promise} that will resolve to such an object.
10
+ *
11
+ * @param routesAppName The app name of the routes.json file defining the component to load
12
+ *
13
+ * @param fullComponentName The name of the component to load. Note that this can optionally
14
+ * include the appName to load the component from (in the format `${appName}#${componentName}`),
15
+ * or omitted to implicitly use routesAppName
16
+ *
17
+ */
18
+ export declare function loadLifeCycles(routesAppName: string, fullComponentName: string): Promise<LifeCycles>;
@@ -1,6 +1,5 @@
1
1
  import { importDynamic } from "@openmrs/esm-dynamic-loading";
2
2
  import { registerModuleLoad } from "@openmrs/esm-config";
3
- import { emptyLifecycle } from "./helpers.js";
4
3
  /**
5
4
  * @internal
6
5
  *
@@ -9,44 +8,50 @@ import { emptyLifecycle } from "./helpers.js";
9
8
  * Values are promises to support asynchronous loading of the same app multiple times
10
9
  */ const initializedApps = new Map();
11
10
  /**
12
- * This function creates a loader function suitable for use in either a single-spa
13
- * application or parcel.
14
- *
15
- * The returned function is lazy and ensures that the appropriate module is loaded,
11
+ * This function loads a single-spa Lifecycles from the given app. The Lifecycles should be
12
+ * created using `getAsyncLifecycle()` or `getSyncLifecycle()` and exported in the app's
13
+ * index.ts file.
14
+ * The function is lazy and ensures that the appropriate module is loaded,
16
15
  * that the module's `startupApp()` is called before the component is loaded. It
17
16
  * then calls the component function, which should return either a single-spa
18
17
  * {@link LifeCycles} object or a {@link Promise} that will resolve to such an object.
19
18
  *
20
- * React-based pages or extensions should generally use the framework's
21
- * `getAsyncLifecycle()` or `getSyncLifecycle()` functions.
22
- *
23
19
  * @param routesAppName The app name of the routes.json file defining the component to load
24
20
  *
25
21
  * @param fullComponentName The name of the component to load. Note that this can optionally
26
22
  * include the appName to load the component from (in the format `${appName}#${componentName}`),
27
23
  * or omitted to implicitly use routesAppName
28
24
  *
29
- */ export function getLoader(routesAppName, fullComponentName) {
30
- return async ()=>{
31
- const poundIndex = fullComponentName.indexOf('#');
32
- const isNamespaced = poundIndex >= 0;
33
- const appName = isNamespaced ? fullComponentName.substring(0, poundIndex) : routesAppName;
34
- const componentName = isNamespaced ? fullComponentName.substring(poundIndex + 1) : fullComponentName;
35
- const module = await importDynamic(appName);
36
- if (module && Object.hasOwn(module, componentName) && typeof module[componentName] === 'function') {
37
- return initializeApp(appName, module).then(()=>module[componentName]());
25
+ */ export async function loadLifeCycles(routesAppName, fullComponentName) {
26
+ const poundIndex = fullComponentName.indexOf('#');
27
+ const isNamespaced = poundIndex >= 0;
28
+ const appName = isNamespaced ? fullComponentName.substring(0, poundIndex) : routesAppName;
29
+ const componentName = isNamespaced ? fullComponentName.substring(poundIndex + 1) : fullComponentName;
30
+ const module = await importDynamic(appName);
31
+ if (module && Object.hasOwn(module, componentName) && typeof module[componentName] === 'function') {
32
+ return initializeApp(appName, module).then(()=>module[componentName]());
33
+ } else {
34
+ if (!module) {
35
+ console.warn(`Unknown app ${appName} for ${fullComponentName} defined in ${routesAppName}'s routes.json`);
36
+ } else if (module && Object.hasOwn(module, componentName)) {
37
+ console.warn(`The export ${fullComponentName}, defined in ${routesAppName}'s routes.json, is not a function`);
38
38
  } else {
39
- if (!module) {
40
- console.warn(`Unknown app ${appName} for ${fullComponentName} defined in ${routesAppName}'s routes.json`);
41
- } else if (module && Object.hasOwn(module, componentName)) {
42
- console.warn(`The export ${fullComponentName}, defined in ${routesAppName}'s routes.json, is not a function`);
43
- } else {
44
- console.warn(`${appName} does not define a component called "${componentName}", referenced in ${routesAppName}'s routes.json. This cannot be loaded.`);
45
- }
39
+ console.warn(`${appName} does not define a component called "${componentName}", referenced in ${routesAppName}'s routes.json. This cannot be loaded.`);
46
40
  }
47
- return emptyLifecycle;
48
- };
41
+ }
42
+ return emptyLifecycle;
49
43
  }
44
+ const emptyLifecycle = {
45
+ bootstrap () {
46
+ return Promise.resolve();
47
+ },
48
+ mount () {
49
+ return Promise.resolve();
50
+ },
51
+ unmount () {
52
+ return Promise.resolve();
53
+ }
54
+ };
50
55
  /**
51
56
  * This function can be used to manually initialize an application without waiting for the
52
57
  * framework to load it. This can sometimes be helpful if the framework doesn't load code
@@ -60,7 +65,7 @@ import { emptyLifecycle } from "./helpers.js";
60
65
  * @param module The loaded code module, if available; if this parameter is omitted, this
61
66
  * function will load it.
62
67
  * @returns a Promise which completes once the app has been loaded and initialized
63
- */ export async function initializeApp(appName, module) {
68
+ */ async function initializeApp(appName, module) {
64
69
  if (!(appName in initializedApps)) {
65
70
  let _module = module ?? await importDynamic(appName);
66
71
  await (initializedApps[appName] = new Promise((resolve, reject)=>{
@@ -2,8 +2,8 @@ import { pathToActiveWhen, registerApplication } from "single-spa";
2
2
  import { registerModuleWithConfigSystem } from "@openmrs/esm-config";
3
3
  import { getFeatureFlag } from "@openmrs/esm-feature-flags";
4
4
  import { routeRegex } from "./helpers.js";
5
- import { getLoader } from "./app.js";
6
5
  import { tryRegisterExtension, tryRegisterFeatureFlag, tryRegisterModal, tryRegisterWorkspace, tryRegisterWorkspaceGroup } from "./components.js";
6
+ import { loadLifeCycles } from "./load-lifecycles.js";
7
7
  // this is the global holder of all pages registered in the app
8
8
  const pages = [];
9
9
  /**
@@ -174,6 +174,6 @@ To fix this, ensure that you define the "component" field inside the page defini
174
174
  return;
175
175
  }
176
176
  const activityFn = wrapPageActivityFn(getActivityFn(route), page);
177
- const loader = getLoader(page.appName, page.component);
177
+ const loader = ()=>loadLifeCycles(page.appName, page.component);
178
178
  registerApplication(appName, loader, activityFn);
179
179
  }
package/dist/public.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from './constants';
2
2
  export * from './routes';
3
- export { initializeApp } from './loaders';
package/dist/public.js CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from "./constants.js";
2
2
  export * from "./routes.js";
3
- export { initializeApp } from "./loaders/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-routes",
3
- "version": "7.0.0",
3
+ "version": "7.0.1-pre.3256",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Utilities for working with the routes registry",
6
6
  "type": "module",
@@ -54,12 +54,12 @@
54
54
  "single-spa": "6.x"
55
55
  },
56
56
  "devDependencies": {
57
- "@openmrs/esm-config": "7.0.0",
58
- "@openmrs/esm-dynamic-loading": "7.0.0",
59
- "@openmrs/esm-extensions": "7.0.0",
60
- "@openmrs/esm-feature-flags": "7.0.0",
61
- "@openmrs/esm-globals": "7.0.0",
62
- "@openmrs/esm-utils": "7.0.0",
57
+ "@openmrs/esm-config": "7.0.1-pre.3256",
58
+ "@openmrs/esm-dynamic-loading": "7.0.1-pre.3256",
59
+ "@openmrs/esm-extensions": "7.0.1-pre.3256",
60
+ "@openmrs/esm-feature-flags": "7.0.1-pre.3256",
61
+ "@openmrs/esm-globals": "7.0.1-pre.3256",
62
+ "@openmrs/esm-utils": "7.0.1-pre.3256",
63
63
  "@swc/cli": "^0.7.7",
64
64
  "@swc/core": "^1.11.29",
65
65
  "concurrently": "^9.1.2",
@@ -69,5 +69,6 @@
69
69
  "single-spa": "^6.0.3",
70
70
  "vitest": "^3.1.4",
71
71
  "vitest-fetch-mock": "^0.4.5"
72
- }
72
+ },
73
+ "stableVersion": "7.0.0"
73
74
  }
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  attach,
3
- type ExtensionRegistration,
4
3
  registerExtension,
5
4
  registerModal,
6
5
  registerWorkspace,
@@ -13,8 +12,8 @@ import {
13
12
  type WorkspaceDefinition,
14
13
  type WorkspaceGroupDefinition,
15
14
  } from '@openmrs/esm-globals';
16
- import { getLoader } from './app';
17
15
  import { registerFeatureFlag } from '@openmrs/esm-feature-flags';
16
+ import { loadLifeCycles } from './load-lifecycles';
18
17
 
19
18
  /**
20
19
  * This function registers an extension definition with the framework and will
@@ -43,7 +42,7 @@ a 'slot' property. Only the 'slots' property will be honored.`,
43
42
  }
44
43
  const slots = extension.slots ? extension.slots : extension.slot ? [extension.slot] : [];
45
44
 
46
- if (!extension.component && !extension.load) {
45
+ if (!extension.component) {
47
46
  console.error(
48
47
  `The extension ${name} from ${appName} is missing a 'component' entry and thus cannot be registered.
49
48
  To fix this, ensure that you define a 'component' field inside the extension definition.`,
@@ -52,33 +51,17 @@ To fix this, ensure that you define a 'component' field inside the extension def
52
51
  return;
53
52
  }
54
53
 
55
- let loader: ExtensionRegistration['load'] | undefined = undefined;
56
- if (extension.component) {
57
- loader = getLoader(appName, extension.component);
58
- } else if (extension.load) {
59
- if (typeof extension.load !== 'function') {
60
- console.error(
61
- `The extension ${name} from ${appName} declares a 'load' property that is not a function. This is not
62
- supported, so the extension will not be loaded.`,
63
- );
64
- return;
65
- }
66
- loader = extension.load;
67
- }
68
-
69
- if (loader) {
70
- registerExtension({
71
- name,
72
- load: loader,
73
- meta: extension.meta || {},
74
- order: extension.order,
75
- moduleName: appName,
76
- privileges: extension.privileges,
77
- online: extension.online ?? true,
78
- offline: extension.offline ?? false,
79
- featureFlag: extension.featureFlag,
80
- });
81
- }
54
+ registerExtension({
55
+ name,
56
+ load: () => loadLifeCycles(appName, extension.component),
57
+ meta: extension.meta || {},
58
+ order: extension.order,
59
+ moduleName: appName,
60
+ privileges: extension.privileges,
61
+ online: extension.online ?? true,
62
+ offline: extension.offline ?? false,
63
+ featureFlag: extension.featureFlag,
64
+ });
82
65
 
83
66
  for (const slot of slots) {
84
67
  attach(slot, name);
@@ -103,7 +86,7 @@ modal definition.`,
103
86
  return;
104
87
  }
105
88
 
106
- if (!modal.component && !modal.load) {
89
+ if (!modal.component) {
107
90
  console.error(
108
91
  `The modal ${name} from ${appName} is missing a 'component' entry and thus cannot be registered.
109
92
  To fix this, ensure that you define a 'component' field inside the modal definition.`,
@@ -112,27 +95,11 @@ To fix this, ensure that you define a 'component' field inside the modal definit
112
95
  return;
113
96
  }
114
97
 
115
- let loader: ExtensionRegistration['load'] | undefined = undefined;
116
- if (modal.component) {
117
- loader = getLoader(appName, modal.component);
118
- } else if (modal.load) {
119
- if (typeof modal.load !== 'function') {
120
- console.error(
121
- `The modal ${name} from ${appName} declares a 'load' property that is not a function. This is not
122
- supported, so the modal will not be loaded.`,
123
- );
124
- return;
125
- }
126
- loader = modal.load;
127
- }
128
-
129
- if (loader) {
130
- registerModal({
131
- name,
132
- load: loader,
133
- moduleName: appName,
134
- });
135
- }
98
+ registerModal({
99
+ name,
100
+ moduleName: appName,
101
+ load: () => loadLifeCycles(appName, modal.component),
102
+ });
136
103
  }
137
104
 
138
105
  /**
@@ -162,7 +129,7 @@ To fix this, ensure that you define the "title" field inside the workspace defin
162
129
  return;
163
130
  }
164
131
 
165
- if (!workspace.component && !workspace.load) {
132
+ if (!workspace.component) {
166
133
  console.error(
167
134
  `The workspace ${name} from ${appName} is missing a 'component' entry and thus cannot be registered.
168
135
  To fix this, ensure that you define a 'component' field inside the workspace definition.`,
@@ -171,34 +138,19 @@ To fix this, ensure that you define a 'component' field inside the workspace def
171
138
  return;
172
139
  }
173
140
 
174
- let loader: ExtensionRegistration['load'] | undefined = undefined;
175
- if (workspace.component) {
176
- loader = getLoader(appName, workspace.component);
177
- } else if (workspace.load) {
178
- if (typeof workspace.load !== 'function') {
179
- console.error(
180
- `The workspace ${name} from ${appName} declares a 'load' property that is not a function. This is not
181
- supported, so the workspace will not be loaded.`,
182
- );
183
- return;
184
- }
185
- loader = workspace.load;
186
- }
187
-
188
- if (loader) {
189
- registerWorkspace({
190
- name,
191
- title,
192
- load: loader,
193
- moduleName: appName,
194
- type: workspace.type,
195
- canHide: workspace.canHide,
196
- canMaximize: workspace.canMaximize,
197
- width: workspace.width,
198
- preferredWindowSize: workspace.preferredWindowSize,
199
- groups: workspace.groups,
200
- });
201
- }
141
+ registerWorkspace({
142
+ name,
143
+ title,
144
+ component: workspace.component,
145
+ moduleName: appName,
146
+ type: workspace.type,
147
+ canHide: workspace.canHide,
148
+ canMaximize: workspace.canMaximize,
149
+ width: workspace.width,
150
+ preferredWindowSize: workspace.preferredWindowSize,
151
+ groups: workspace.groups,
152
+ load: () => loadLifeCycles(appName, workspace.component),
153
+ });
202
154
 
203
155
  for (const group of workspace.groups || []) {
204
156
  registerWorkspaceGroup({
@@ -1,17 +1,3 @@
1
- import { type LifeCycles } from 'single-spa';
2
-
3
- export const emptyLifecycle: LifeCycles<never> = {
4
- bootstrap() {
5
- return Promise.resolve();
6
- },
7
- mount() {
8
- return Promise.resolve();
9
- },
10
- unmount() {
11
- return Promise.resolve();
12
- },
13
- };
14
-
15
1
  export function routeRegex(regex: RegExp, location: Location) {
16
2
  const result = regex.test(location.pathname.replace(window.getOpenmrsSpaBase(), ''));
17
3
  return result;
@@ -1,3 +1,3 @@
1
- export { initializeApp } from './app';
2
1
  export { registerApp, finishRegisteringAllApps } from './pages';
3
2
  export { tryRegisterExtension } from './components';
3
+ export * from './load-lifecycles';
@@ -1,7 +1,6 @@
1
1
  import { importDynamic } from '@openmrs/esm-dynamic-loading';
2
- import { registerModuleLoad } from '@openmrs/esm-config';
3
2
  import { type LifeCycles } from 'single-spa';
4
- import { emptyLifecycle } from './helpers';
3
+ import { registerModuleLoad } from '@openmrs/esm-config';
5
4
 
6
5
  // Couldn't figure out how to express this as an interface
7
6
  type Module = Omit<Record<string, () => LifeCycles | Promise<LifeCycles>>, 'startupApp'> & {
@@ -18,17 +17,14 @@ type Module = Omit<Record<string, () => LifeCycles | Promise<LifeCycles>>, 'star
18
17
  const initializedApps = new Map<string, Promise<unknown>>();
19
18
 
20
19
  /**
21
- * This function creates a loader function suitable for use in either a single-spa
22
- * application or parcel.
23
- *
24
- * The returned function is lazy and ensures that the appropriate module is loaded,
20
+ * This function loads a single-spa Lifecycles from the given app. The Lifecycles should be
21
+ * created using `getAsyncLifecycle()` or `getSyncLifecycle()` and exported in the app's
22
+ * index.ts file.
23
+ * The function is lazy and ensures that the appropriate module is loaded,
25
24
  * that the module's `startupApp()` is called before the component is loaded. It
26
25
  * then calls the component function, which should return either a single-spa
27
26
  * {@link LifeCycles} object or a {@link Promise} that will resolve to such an object.
28
27
  *
29
- * React-based pages or extensions should generally use the framework's
30
- * `getAsyncLifecycle()` or `getSyncLifecycle()` functions.
31
- *
32
28
  * @param routesAppName The app name of the routes.json file defining the component to load
33
29
  *
34
30
  * @param fullComponentName The name of the component to load. Note that this can optionally
@@ -36,33 +32,43 @@ const initializedApps = new Map<string, Promise<unknown>>();
36
32
  * or omitted to implicitly use routesAppName
37
33
  *
38
34
  */
39
- export function getLoader(routesAppName: string, fullComponentName: string): () => Promise<LifeCycles> {
40
- return async () => {
41
- const poundIndex = fullComponentName.indexOf('#');
42
- const isNamespaced = poundIndex >= 0;
43
- const appName = isNamespaced ? fullComponentName.substring(0, poundIndex) : routesAppName;
44
- const componentName = isNamespaced ? fullComponentName.substring(poundIndex + 1) : fullComponentName;
35
+ export async function loadLifeCycles(routesAppName: string, fullComponentName: string): Promise<LifeCycles> {
36
+ const poundIndex = fullComponentName.indexOf('#');
37
+ const isNamespaced = poundIndex >= 0;
38
+ const appName = isNamespaced ? fullComponentName.substring(0, poundIndex) : routesAppName;
39
+ const componentName = isNamespaced ? fullComponentName.substring(poundIndex + 1) : fullComponentName;
45
40
 
46
- const module = await importDynamic<Module>(appName);
41
+ const module = await importDynamic<Module>(appName);
47
42
 
48
- if (module && Object.hasOwn(module, componentName) && typeof module[componentName] === 'function') {
49
- return initializeApp(appName, module).then(() => module[componentName]());
43
+ if (module && Object.hasOwn(module, componentName) && typeof module[componentName] === 'function') {
44
+ return initializeApp(appName, module).then(() => module[componentName]());
45
+ } else {
46
+ if (!module) {
47
+ console.warn(`Unknown app ${appName} for ${fullComponentName} defined in ${routesAppName}'s routes.json`);
48
+ } else if (module && Object.hasOwn(module, componentName)) {
49
+ console.warn(`The export ${fullComponentName}, defined in ${routesAppName}'s routes.json, is not a function`);
50
50
  } else {
51
- if (!module) {
52
- console.warn(`Unknown app ${appName} for ${fullComponentName} defined in ${routesAppName}'s routes.json`);
53
- } else if (module && Object.hasOwn(module, componentName)) {
54
- console.warn(`The export ${fullComponentName}, defined in ${routesAppName}'s routes.json, is not a function`);
55
- } else {
56
- console.warn(
57
- `${appName} does not define a component called "${componentName}", referenced in ${routesAppName}'s routes.json. This cannot be loaded.`,
58
- );
59
- }
51
+ console.warn(
52
+ `${appName} does not define a component called "${componentName}", referenced in ${routesAppName}'s routes.json. This cannot be loaded.`,
53
+ );
60
54
  }
55
+ }
61
56
 
62
- return emptyLifecycle;
63
- };
57
+ return emptyLifecycle;
64
58
  }
65
59
 
60
+ const emptyLifecycle: LifeCycles<never> = {
61
+ bootstrap() {
62
+ return Promise.resolve();
63
+ },
64
+ mount() {
65
+ return Promise.resolve();
66
+ },
67
+ unmount() {
68
+ return Promise.resolve();
69
+ },
70
+ };
71
+
66
72
  /**
67
73
  * This function can be used to manually initialize an application without waiting for the
68
74
  * framework to load it. This can sometimes be helpful if the framework doesn't load code
@@ -77,7 +83,7 @@ export function getLoader(routesAppName: string, fullComponentName: string): ()
77
83
  * function will load it.
78
84
  * @returns a Promise which completes once the app has been loaded and initialized
79
85
  */
80
- export async function initializeApp(appName: string, module?: Module) {
86
+ async function initializeApp(appName: string, module?: Module) {
81
87
  if (!(appName in initializedApps)) {
82
88
  let _module: Module = module ?? (await importDynamic<Module>(appName));
83
89
 
@@ -12,7 +12,6 @@ import {
12
12
  } from '@openmrs/esm-globals';
13
13
  import { getFeatureFlag } from '@openmrs/esm-feature-flags';
14
14
  import { routeRegex } from './helpers';
15
- import { getLoader } from './app';
16
15
  import {
17
16
  tryRegisterExtension,
18
17
  tryRegisterFeatureFlag,
@@ -20,6 +19,7 @@ import {
20
19
  tryRegisterWorkspace,
21
20
  tryRegisterWorkspaceGroup,
22
21
  } from './components';
22
+ import { loadLifeCycles } from './load-lifecycles';
23
23
 
24
24
  // this is the global holder of all pages registered in the app
25
25
  const pages: Array<RegisteredPageDefinition> = [];
@@ -257,6 +257,6 @@ To fix this, ensure that you define the "component" field inside the page defini
257
257
  }
258
258
 
259
259
  const activityFn = wrapPageActivityFn(getActivityFn(route), page);
260
- const loader = getLoader(page.appName, page.component);
260
+ const loader = () => loadLifeCycles(page.appName, page.component);
261
261
  registerApplication(appName, loader, activityFn);
262
262
  }
package/src/public.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from './constants';
2
2
  export * from './routes';
3
- export { initializeApp } from './loaders';
@@ -1,40 +0,0 @@
1
- import { type LifeCycles } from 'single-spa';
2
- type Module = Omit<Record<string, () => LifeCycles | Promise<LifeCycles>>, 'startupApp'> & {
3
- startupApp?: () => unknown;
4
- };
5
- /**
6
- * This function creates a loader function suitable for use in either a single-spa
7
- * application or parcel.
8
- *
9
- * The returned function is lazy and ensures that the appropriate module is loaded,
10
- * that the module's `startupApp()` is called before the component is loaded. It
11
- * then calls the component function, which should return either a single-spa
12
- * {@link LifeCycles} object or a {@link Promise} that will resolve to such an object.
13
- *
14
- * React-based pages or extensions should generally use the framework's
15
- * `getAsyncLifecycle()` or `getSyncLifecycle()` functions.
16
- *
17
- * @param routesAppName The app name of the routes.json file defining the component to load
18
- *
19
- * @param fullComponentName The name of the component to load. Note that this can optionally
20
- * include the appName to load the component from (in the format `${appName}#${componentName}`),
21
- * or omitted to implicitly use routesAppName
22
- *
23
- */
24
- export declare function getLoader(routesAppName: string, fullComponentName: string): () => Promise<LifeCycles>;
25
- /**
26
- * This function can be used to manually initialize an application without waiting for the
27
- * framework to load it. This can sometimes be helpful if the framework doesn't load code
28
- * at the point you think is appropriate.
29
- *
30
- * This will ensure that the module is available and that it's `startupApp()` function (if
31
- * any) will be called. Note that these are only guaranteed to be complete once the Promise
32
- * returned from the function completes.
33
- *
34
- * @param appName The name of the app to initialize
35
- * @param module The loaded code module, if available; if this parameter is omitted, this
36
- * function will load it.
37
- * @returns a Promise which completes once the app has been loaded and initialized
38
- */
39
- export declare function initializeApp(appName: string, module?: Module): Promise<void>;
40
- export {};