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

[Next.js] [BYOC] Component Builder integration endpoint #1729

Merged
merged 11 commits into from
Feb 8, 2024
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ Our versioning strategy is as follows:
* `[templates/react]` `[sitecore-jss-react]` Replace package 'deep-equal' with 'fast-deep-equal'. No functionality change only performance improvement ([#1719](https://github.com/Sitecore/jss/pull/1719)) ([#1665](https://github.com/Sitecore/jss/pull/1665))
* `[templates/nextjs-xmcloud]` `[sitecore-jss]` `[sitecore-jss-nextjs]` `[sitecore-jss-react]` Add support for loading appropriate stylesheets whenever a theme is applied to BYOC and SXA components by introducing new function getComponentLibraryStylesheetLinks, which replaces getFEAASLibraryStylesheetLinks (which has been marked as deprecated) ([#1722](https://github.com/Sitecore/jss/pull/1722))
* `[templates/nextjs-xmcloud]` `[sitecore-jss-nextjs]` Add protected endpoint which provides configuration information (the sitecore packages used by the app and all registered components) to be used to determine feature compatibility on Pages side. ([#1724](https://github.com/Sitecore/jss/pull/1724))
* `[templates/nextjs]` `[templates/nextjs-styleguide]` Modify all GraphQLRequestClient import statements so that it gets imported from the /graphql submodule ([#1728](https://github.com/Sitecore/jss/pull/1728))
* `[sitecore-jss-nextjs]` `[templates/nextjs]` [BYOC] Component Builder integration endpoint ([#1729](https://github.com/Sitecore/jss/pull/1729))

### 🐛 Bug Fixes

* `[templates/nextjs]` `[templates/nextjs-styleguide]` Modify all GraphQLRequestClient import statements so that it gets imported from the /graphql submodule ([#1728](https://github.com/Sitecore/jss/pull/1728))
* `[sitecore-jss-nextjs]` Internal link in RichText is broken when nested tags are added ([#1718](https://github.com/Sitecore/jss/pull/1718))
* `[templates/node-headless-ssr-proxy]` `[node-headless-ssr-proxy]` Add sc_site qs parameter to Layout Service requests by default ([#1660](https://github.com/Sitecore/jss/pull/1660))
* `[templates/nextjs-sxa]` Fixed Image component when there is using Banner variant which set property background-image when image is empty. ([#1689](https://github.com/Sitecore/jss/pull/1689)) ([#1692](https://github.com/Sitecore/jss/pull/1692))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
*/
const feaasPlugin = (nextConfig = {}) => {
return Object.assign({}, nextConfig, {
// Enable FEAAS Nextjs Image integration
images: {
remotePatterns: [
illiakovalenko marked this conversation as resolved.
Show resolved Hide resolved
{
protocol: 'https',
hostname: '**',
},
{
protocol: 'http',
hostname: '**',
illiakovalenko marked this conversation as resolved.
Show resolved Hide resolved
},
],
},
webpack: (config, options) => {
if (options.isServer) {
// Force use of CommonJS on the server for FEAAS SDK since JSS also uses CommonJS entrypoint to FEAAS SDK.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FEAASRenderMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/editing';

/**
* This Next.js API route is used to handle GET requests from Sitecore Component Builder.
*
* The `FEAASRenderMiddleware` will:
* 1. Enable Next.js Preview Mode
* 2. Invoke the /feaas/render page request, passing along the Preview Mode cookies.
* 3. Return the rendered page HTML to the Sitecore Component Builder:
* - If "feaasSrc" query parameter is provided, the page will render a FEAAS component.
* - The page provides all the registered FEAAS components
*/

// Bump body size limit (1mb by default) and disable response limit for Sitecore editor payloads
// See https://nextjs.org/docs/api-routes/request-helpers#custom-config
export const config = {
api: {
bodyParser: {
sizeLimit: '2mb',
},
responseLimit: false,
},
};
illiakovalenko marked this conversation as resolved.
Show resolved Hide resolved

// Wire up the FEAASRenderMiddleware handler
const handler = new FEAASRenderMiddleware().getHandler();

export default handler;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { GetServerSideProps } from 'next';
import BYOC from 'src/byoc';
import * as FEAAS from '@sitecore-feaas/clientside/react';

/**
* The FEAASRender page is responsible for:
* - Rendering the FEAAS component if the "feaasSrc" is provided.
* - Rendering all the registered components.
* - The page is rendered only if it's requested by the api route (/api/editing/feaas/render) using the preview mode.
*/
const FEAASRender = ({ feaasSrc }: { feaasSrc: string }): JSX.Element => {
return (
<>
{/** Render the component if the "feaasSrc" is provided */}
{feaasSrc && <FEAAS.Component src={feaasSrc} />}
{/** Render all the registered components */}
<BYOC />
</>
);
};

export const getServerSideProps: GetServerSideProps = async (context) => {
return {
props: {
feaasSrc: context.query.feaasSrc || null,
},
// Don't show the page if it's not requested by the api route using the preview mode
notFound: !context.preview,
};
};

export default FEAASRender;
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { STATIC_PROPS_ID, SERVER_PROPS_ID } from 'next/constants';
import { AxiosDataFetcher, debug } from '@sitecore-jss/sitecore-jss';
import { debug } from '@sitecore-jss/sitecore-jss';
import { EDITING_COMPONENT_ID, RenderingType } from '@sitecore-jss/sitecore-jss/layout';
import { parse } from 'node-html-parser';
import { EditingData } from './editing-data';
import { EditingDataService, editingDataService } from './editing-data-service';
import {
QUERY_PARAM_EDITING_SECRET,
QUERY_PARAM_PROTECTION_BYPASS_SITECORE,
QUERY_PARAM_PROTECTION_BYPASS_VERCEL,
} from './constants';
import { QUERY_PARAM_EDITING_SECRET } from './constants';
import { getJssEditingSecret } from '../utils/utils';
import { RenderMiddlewareBase, RenderMiddlewareBaseConfig } from './render-middleware';

export interface EditingRenderMiddlewareConfig {
/**
* The `AxiosDataFetcher` instance to use for API requests.
* @default new AxiosDataFetcher()
* @see AxiosDataFetcher
*/
dataFetcher?: AxiosDataFetcher;
export type EditingRenderMiddlewareConfig = RenderMiddlewareBaseConfig & {
/**
* The `EditingDataService` instance to use.
* This would typically only be necessary if you've got a custom `EditingDataService` instance (e.g. using a custom API route).
Expand All @@ -38,34 +29,23 @@ export interface EditingRenderMiddlewareConfig {
* @see resolveServerUrl
*/
resolvePageUrl?: (serverUrl: string, itemPath: string) => string;
/**
* Function used to determine the root server URL. This is used for the route/page and subsequent data API requests.
* By default, the host header is used, with https protocol on Vercel (due to serverless function architecture) and http protocol elsewhere.
* @param {NextApiRequest} req The current request.
* @default `${process.env.VERCEL ? 'https' : 'http'}://${req.headers.host}`;
* @see resolvePageUrl
*/
resolveServerUrl?: (req: NextApiRequest) => string;
}
};

/**
* Middleware / handler for use in the editing render Next.js API route (e.g. '/api/editing/render')
* which is required for Sitecore editing support.
*/
export class EditingRenderMiddleware {
export class EditingRenderMiddleware extends RenderMiddlewareBase {
private editingDataService: EditingDataService;
private dataFetcher: AxiosDataFetcher;
private resolvePageUrl: (serverUrl: string, itemPath: string) => string;
private resolveServerUrl: (req: NextApiRequest) => string;

/**
* @param {EditingRenderMiddlewareConfig} [config] Editing render middleware config
*/
constructor(config?: EditingRenderMiddlewareConfig) {
super(config);
this.editingDataService = config?.editingDataService ?? editingDataService;
this.dataFetcher = config?.dataFetcher ?? new AxiosDataFetcher({ debugger: debug.editing });
this.resolvePageUrl = config?.resolvePageUrl ?? this.defaultResolvePageUrl;
this.resolveServerUrl = config?.resolveServerUrl ?? this.defaultResolveServerUrl;
}

/**
Expand All @@ -76,28 +56,6 @@ export class EditingRenderMiddleware {
return this.handler;
}

/**
* Gets query parameters that should be passed along to subsequent requests
* @param {Object} query Object of query parameters from incoming URL
* @returns Object of approved query parameters
*/
protected getQueryParamsForPropagation = (
query: Partial<{ [key: string]: string | string[] }>
): { [key: string]: string } => {
const params: { [key: string]: string } = {};
if (query[QUERY_PARAM_PROTECTION_BYPASS_SITECORE]) {
params[QUERY_PARAM_PROTECTION_BYPASS_SITECORE] = query[
QUERY_PARAM_PROTECTION_BYPASS_SITECORE
] as string;
}
if (query[QUERY_PARAM_PROTECTION_BYPASS_VERCEL]) {
params[QUERY_PARAM_PROTECTION_BYPASS_VERCEL] = query[
QUERY_PARAM_PROTECTION_BYPASS_VERCEL
] as string;
}
return params;
};

private handler = async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {
const { method, query, body, headers } = req;

Expand Down Expand Up @@ -240,20 +198,6 @@ export class EditingRenderMiddleware {
private defaultResolvePageUrl = (serverUrl: string, itemPath: string) => {
return `${serverUrl}${itemPath}`;
};

/**
* Default server URL resolution.
* Note we use https protocol on Vercel due to serverless function architecture.
* In all other scenarios, including localhost (with or without a proxy e.g. ngrok)
* and within a nodejs container, http protocol should be used.
*
* For information about the VERCEL environment variable, see
* https://vercel.com/docs/environment-variables#system-environment-variables
* @param {NextApiRequest} req
*/
private defaultResolveServerUrl = (req: NextApiRequest) => {
return `${process.env.VERCEL ? 'https' : 'http'}://${req.headers.host}`;
};
}

/**
Expand Down
Loading