Skip to content

Commit 3e4e481

Browse files
committed
Enable named export for async loading.
1 parent 39ff8d7 commit 3e4e481

File tree

12 files changed

+107
-16
lines changed

12 files changed

+107
-16
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,25 @@ const RemotelyLoadedComponent = () => {
543543
544544
```
545545
546+
***importName***
547+
548+
The `importName` prop is a string that is used to reference the module. It is a name of the exported component from the module. Should be used if other than `default` export is required.
549+
550+
```jsx
551+
// Remote module definition
552+
export const NamedComponent = () => {
553+
return (
554+
<div>
555+
<h2>Named component</h2>
556+
</div>
557+
)
558+
}
559+
560+
// Consumer
561+
<ScalprumComponent {...props} importName="NamedComponent">
562+
```
563+
One module can have multiple exports.
564+
546565
***fallback***
547566
548567
Similar to [React.Suspense](https://beta.reactjs.org/reference/react/Suspense). This component will be loaded before the module is ready.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
describe('SDK module loading', () => {
2+
it('should show data from prefetch', () => {
3+
cy.visit('http://localhost:8123/sdk');
4+
5+
// check if the component using named export is rendered
6+
cy.get('#named-component').should('exist');
7+
});
8+
});

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@scalprum/core",
3-
"version": "0.5.4",
3+
"version": "0.6.0",
44
"description": "Includes core functions for scalprum scaffolding.",
55
"main": "dist/cjs/index.js",
66
"module": "dist/esm/index.js",

packages/core/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export interface AppsConfig<T extends {} = {}> {
1414
}
1515

1616
export type PrefetchFunction<T = any> = (ScalprumApi: Record<string, any> | undefined) => Promise<T>;
17-
export type ExposedScalprumModule<T = any, P = any> = { default: T; prefetch?: PrefetchFunction<P> };
17+
export type ExposedScalprumModule<T = any, P = any> = { [importName: string]: T } & { prefetch?: PrefetchFunction<P> };
1818
export type ScalprumModule<T = any, P = any> = {
1919
cachedModule?: ExposedScalprumModule<T, P>;
2020
prefetchPromise?: ReturnType<PrefetchFunction>;

packages/react-core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@scalprum/react-core",
3-
"version": "0.5.4",
3+
"version": "0.6.0",
44
"description": "React binding for @scalprum/core package.",
55
"main": "dist/cjs/index.js",
66
"module": "dist/esm/index.js",
@@ -27,7 +27,7 @@
2727
},
2828
"dependencies": {
2929
"@openshift/dynamic-plugin-sdk": "^4.0.0",
30-
"@scalprum/core": "^0.5.4",
30+
"@scalprum/core": "^0.6.0",
3131
"lodash": "^4.17.0"
3232
},
3333
"peerDependencies": {

packages/react-core/src/__snapshots__/scalprum-component.test.tsx.snap

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`<ScalprumComponent /> should render component with importName prop from cache 1`] = `
4+
<div>
5+
<div
6+
data-testid="named-component"
7+
>
8+
named export Component
9+
</div>
10+
</div>
11+
`;
12+
313
exports[`<ScalprumComponent /> should render error component 1`] = `
414
<div>
515
<h1>

packages/react-core/src/async-loader.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { ExposedScalprumModule, getCachedModule, getScalprum, PrefetchFunction }
33

44
export async function loadComponent<P = {}>(
55
scope: string,
6-
module: string
6+
module: string,
7+
importName = 'default'
78
): Promise<{ prefetch?: PrefetchFunction; component: React.ComponentType<P> }> {
89
{
910
const { pluginStore } = getScalprum();
@@ -15,7 +16,7 @@ export async function loadComponent<P = {}>(
1516
}
1617
return {
1718
prefetch: mod.prefetch,
18-
component: mod.default,
19+
component: mod[importName],
1920
};
2021
}
2122
}

packages/react-core/src/scalprum-component.test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ describe('<ScalprumComponent />', () => {
3838
name: 'errorRepairSuccess',
3939
manifestLocation: '/errorRepairSuccess,js',
4040
},
41+
testApp: {
42+
name: 'testApp',
43+
manifestLocation: '/testApp.js',
44+
},
4145
};
4246

4347
const mockInitScalpumConfigManifest: AppsConfig = {
@@ -344,4 +348,28 @@ describe('<ScalprumComponent />', () => {
344348

345349
expect(container).toMatchSnapshot();
346350
});
351+
352+
it('should render component with importName prop from cache', async () => {
353+
processManifestSpy.mockImplementation(() => Promise.resolve());
354+
const namedModule = {
355+
__esModule: true,
356+
NamedExport: () => <div data-testid="named-component">named export Component</div>,
357+
};
358+
ScalprumCore.initialize({ appsConfig: mockInitScalprumConfig });
359+
ScalprumCore.getScalprum().exposedModules[`namedModule#./test`] = namedModule;
360+
await ScalprumCore.getScalprum().pluginStore.loadPlugin(testManifest);
361+
362+
const props: ScalprumComponentProps = {
363+
scope: 'namedModule',
364+
module: './test',
365+
importName: 'NamedExport',
366+
};
367+
let container;
368+
await act(async () => {
369+
container = render(<ScalprumComponent {...props} />).container;
370+
});
371+
expect(loadComponentSpy).not.toHaveBeenCalled();
372+
expect(container).toMatchSnapshot();
373+
expect(screen.getAllByTestId('named-component')).toHaveLength(1);
374+
});
347375
});

packages/react-core/src/scalprum-component.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import DefaultErrorComponent from './default-error-component';
1515
import { PrefetchProvider } from './prefetch-context';
1616
import { useScalprum } from './use-scalprum';
1717

18-
// eslint-disable-next-line @typescript-eslint/ban-types
1918
export type ScalprumComponentProps<API extends Record<string, any> = {}, Props extends Record<string, any> = {}> = Props & {
2019
fallback?: NonNullable<React.ReactNode> | null;
2120
api?: API;
2221
scope: string;
2322
module: string;
23+
importName?: string;
2424
ErrorComponent?: React.ReactElement;
2525
LoadingComponent?: React.ComponentType;
2626
innerRef?: React.Ref<unknown>;
@@ -36,6 +36,7 @@ async function setComponentFromModule(
3636
scope: string,
3737
module: string,
3838
isMounted: boolean,
39+
importName: string,
3940
setComponent: React.Dispatch<
4041
React.SetStateAction<
4142
| React.ComponentType<{
@@ -45,7 +46,7 @@ async function setComponentFromModule(
4546
>
4647
>
4748
): Promise<PrefetchFunction | undefined> {
48-
const { prefetch, component } = await loadComponent(scope, module);
49+
const { prefetch, component } = await loadComponent(scope, module, importName);
4950
isMounted && setComponent(() => component);
5051
return prefetch;
5152
}
@@ -58,6 +59,7 @@ const LoadModule: React.ComponentType<LoadModuleProps> = ({
5859
processor,
5960
innerRef,
6061
skipCache = false,
62+
importName = 'default',
6163
...props
6264
}) => {
6365
const { manifestLocation } = getAppData(scope);
@@ -103,7 +105,7 @@ const LoadModule: React.ComponentType<LoadModuleProps> = ({
103105
if (manifestLocation) {
104106
const processPromise = processManifest(manifestLocation, scope, module, processor)
105107
.then(() => {
106-
pref = setComponentFromModule(scope, module, isMounted, setComponent);
108+
pref = setComponentFromModule(scope, module, isMounted, importName, setComponent);
107109
pref.then((result) => {
108110
if (result) {
109111
const prefetch = getPendingPrefetch(prefetchID) || result(scalprumApi);
@@ -120,7 +122,7 @@ const LoadModule: React.ComponentType<LoadModuleProps> = ({
120122
}
121123
} else {
122124
try {
123-
isMounted && setComponent(() => cachedModule.default);
125+
isMounted && setComponent(() => cachedModule[importName]);
124126

125127
pref = cachedModule.prefetch;
126128
if (pref) {
@@ -186,7 +188,7 @@ class BaseScalprumComponent extends React.Component<ScalprumComponentProps, Base
186188
return !isEqual(nextProps, this.props) || !isEqual(nextState, this.state);
187189
}
188190

189-
// TODO: Use ErrorWithCause once the type is avaiable
191+
// TODO: Use ErrorWithCause once the type is available
190192
componentDidCatch(error: any, errorInfo: React.ErrorInfo) {
191193
if (this.selfRepairAttempt === true) {
192194
console.error('Scalprum encountered an error!', error?.cause || error.message, error);

0 commit comments

Comments
 (0)