Skip to content

Commit

Permalink
[sitecore-jss-react] Fetch Data for FEaaS Components as part of Compo…
Browse files Browse the repository at this point in the history
…nent SSR/SSG (#1590)

* add data fetching for feaas

* refactor feaas to use SSR, add unit test

* remove unwanted comments

* update yarn.lock

* refactor test

* update yarn.lock

* remove extra test case

* refactor test case
  • Loading branch information
addy-pathania authored Aug 18, 2023
1 parent 9b2c5bb commit a981585
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Check the BYOC documentation for more info. ([#1568](https://github.com/Sitecore
* `[sitecore-jss-react]` Built-in MissingComponent component can now accept "errorOverride" text in props - to be displayed in the yellow frame as a custom error message. ([#1568](https://github.com/Sitecore/jss/pull/1568))
* `[sitecore-jss-nextjs]` Support for public URL resolution in Netlify ([#1585](https://github.com/Sitecore/jss/pull/1585))
* `[templates/nextjs]` `[sitecore-jss-nextjs]` Better error handling for component-level data fetching ([#1586](https://github.com/Sitecore/jss/pull/1586))
* `[sitecore-jss-react]` Fetch Data for FEaaS Components as part of Component SSR/SSG ([#1586](https://github.com/Sitecore/jss/pull/1590))

### 🧹 Chores

Expand Down
24 changes: 24 additions & 0 deletions packages/sitecore-jss-react/src/components/FEaaSComponent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ describe('<FEaaSComponent />', () => {
...requiredParams,
ComponentDataOverride: '{ "foo": "bar", "baz": 1 }',
},
fetchedData: undefined,
};
const wrapper = shallow(<FEaaSComponent {...props} />);
expect(wrapper).to.have.length(1);
Expand Down Expand Up @@ -166,5 +167,28 @@ describe('<FEaaSComponent />', () => {
`data="${props.params?.ComponentDataOverride!.replace(/"/g, '&quot;').replace(/\s/g, '')}"`
);
});

it('should send prefetched data', () => {
const fetchedData = {
foo: 'bar',
baz: 42,
};

const props: FEaaSComponentProps = {
params: {
...requiredParams,
ComponentDataOverride: '{ "foo": "test", "baz": 22 }',
},
fetchedData,
};

const wrapper = shallow(<FEaaSComponent {...props} />);

expect(wrapper).to.have.length(1);
const expectedData = JSON.stringify(fetchedData)
.replace(/"/g, '&quot;')
.replace(/\s/g, '');
expect(wrapper.html()).to.contain(`data="${expectedData}"`);
});
});
});
91 changes: 70 additions & 21 deletions packages/sitecore-jss-react/src/components/FEaaSComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ type FEaaSComponentServerProps = {
* Default revision to be fetched. Should be 'staged' for editing/preview. Can be overriden by params.ComponentRevision
*/
revisionFallback?: RevisionType;
/**
* Fetched data from server component props for server rendering, based on rendering params.
*/
fetchedData?: FEAAS.DataScopes;
};

/**
Expand Down Expand Up @@ -73,25 +77,27 @@ export const FEaaSComponent = (props: FEaaSComponentProps): JSX.Element => {
}

let data: { [key: string]: unknown } = null;
if (props.params?.ComponentDataOverride) {
// Use override data if provided
try {
data = JSON.parse(props.params.ComponentDataOverride);
} catch (e) {
data = null;
if (props.fetchedData === null || props.fetchedData === undefined) {
if (props.params?.ComponentDataOverride) {
// Use override data if provided
try {
data = JSON.parse(props.params.ComponentDataOverride);
} catch (e) {
data = null;
}
} else if (props.fields) {
// Otherwise use datasource data (provided in fields)
data = getDataFromFields(props.fields);
}
} else if (props.fields) {
// Otherwise use datasource data (provided in fields)
data = getDataFromFields(props.fields);
}

// FEaaS control would still be hydrated by client
// we pass all the props as a workaround to avoid hydration error, until we convert all JSS components to server side
// this also allows component to fall back to full client-side rendering when template or src is empty
return (
<FEAAS.Component
data={data}
template={props.template || ''}
data={props.fetchedData || data}
template={props.template}
cdn={props.params?.ComponentHostName}
library={props.params?.LibraryId}
version={props.params?.ComponentVersion}
Expand All @@ -117,22 +123,65 @@ export async function fetchFEaaSComponentServerProps(
const revisionFallback =
pageState && pageState !== LayoutServicePageState.Normal ? 'staged' : 'published';
const src = endpointOverride || composeComponentEndpoint(params, revisionFallback);
let template = '';
let fetchedData: FEAAS.DataScopes = null;
const fetchDataOptions: FEAAS.DataOptions = params.ComponentDataOverride
? JSON.parse(params.ComponentDataOverride)
: {};

try {
const { template } = await FEAAS.fetchComponent(src);
return {
revisionFallback,
template,
};
template = await fetchComponentTemplate(src, params, revisionFallback);

fetchedData = await fetchData(fetchDataOptions);
} catch (e) {
console.error(e);
}

return {
fetchedData,
revisionFallback,
template,
};
}

/**
* @param {string} src component endpoint
* @param {FEaaSComponentParams} params rendering parameters for FEAAS component
* @param {RevisionType} revisionFallback fallback revision to fetch if revision is absent in params
*/
async function fetchComponentTemplate(
src: string,
params: FEaaSComponentParams,
revisionFallback: string
): Promise<string> {
try {
const { template } = await FEAAS.fetchComponent(src);
return template;
} catch (error) {
console.error(
`Fetch FEAAS component from ${src} failed. Ensure the component revision "${params.ComponentRevision ||
revisionFallback}" is present`
);
console.error(e);
// leave revision fallback in so we can re-try with client-side rendering
return {
revisionFallback,
};
throw error;
}
}

/**
* Fetches component data based on the provided data options.
* This function asynchronously fetches data using the FEAAS.DataSettings.fetch method.
*
* @param {FEAAS.DataOptions} dataOptions - Options to customize data fetching.
* @returns {Promise<FEAAS.DataScopes>} A promise that resolves with the fetched data,
* or rejects with an error if data fetching encounters an issue.
* @throws {Error} If an error occurs during data fetching, it is propagated as an error.
*/
async function fetchData(dataOptions: FEAAS.DataOptions): Promise<FEAAS.DataScopes> {
try {
const fetchedData = await FEAAS.DataSettings.fetch(dataOptions || {});
return fetchedData;
} catch (error) {
console.error('Fetch FEAAS component data settings failed');
throw error;
}
}

Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5905,11 +5905,11 @@ __metadata:
linkType: hard

"@sitecore-feaas/clientside@npm:^0.3.0":
version: 0.3.0
resolution: "@sitecore-feaas/clientside@npm:0.3.0"
version: 0.3.10
resolution: "@sitecore-feaas/clientside@npm:0.3.10"
peerDependencies:
react-dom: ">=16.8.0"
checksum: cf1309e68b92f544ac7569cd444b211f153a8433bb7c42c8f74e5453cf58e164a95a1c59d4f78f06ae8980c5b4c25f09bf081880ab160b9dcb8b477a5c8b22d3
checksum: b60391c33fa446b0fad164bc76babfc8cf2e7c892a741703df45d4acb74c6efd5aa2640650b85571d2d9d3072c02cf6653c3042cade6932365d214dc34402825
languageName: node
linkType: hard

Expand Down

0 comments on commit a981585

Please sign in to comment.