The Experience Editor in headless Sitecore using Next.js: API Routes Response Size Limited to 4MB

,

I am currently working on a headless Sitecore solution using Next.js and Experience Edge. In this post I am going to explain one particular fix we had to do, to avoid sending excessive amounts of data to the rendering engine when using the Experience Editor causing the /api/editing/render to fail.

Sitecore’s Experience Editor allows a content editor to log into Sitecore and browse the site like a regular visitor, but with the ability to add and edit content on the fly. What happens is that Sitecore replaces the normal content fields with small input fields (called editor chromes).

The “chromes” in the Sitecore Experience Editor is small frames around editable fields, that allows the content editor to update and insert text directly on the page.

If you e.g., have a content module consisting of a headline field and a rich-text body field, Sitecore will replace these with a single line input field and a WYSIWYG editor in the Experience Editor. In a non-headless MVC solution this is normally done in the Razor views, where Sitecore has a lot of html helpers methods for the Experience Editor. The chromes are only rendered if a field is actually shown on a page using one of these helper methods (e.g. Html.Sitecore().Field). This means that fields that are used for e.g. configuration is not causing chromes to be send to the browser. Also, even for rendered fields, the chromes can be disabled using the DisableWebEdit setting.

The Experience Editor in a headless approach

However, in a headless CMS, the rendering of content is done separately from the CMS, and the closed knit connection between the CMS and the rendering of e.g., Razor views does not exist.

The way Sitecore renders a page in the Experience Editor when using a headless approach, is that it makes an API call to the rendering engine’s /api/editing/render endpoint:

The rendering engine (which in Next.js is hosted on a Node.js server) then renders the HTML, inserting the editor chromes into the HTML.

In a normal view, the rendering engine API would simply receive the fields (e.g., the headline and the body) in JSON format. But when using the Experience Editor, these fields are augmented with the editor chromes, which is small HTML forms for each field which is added to the JSON. The rendering engine then embeds these forms into the rendered page. If you inspect this traffic, you will notice that the JSON with editor chromes is about 20 times larger than the normal JSON.

This turns out to be a problem for two reasons. In a classic non-headless Sitecore solution, the Razor view would dictate which fields should be rendered using chromes, but in a headless architecture, the Sitecore CMS has no way of knowing which fields are editable, and hence it does it to each and every field.

Not only does it slow the Experience Editor down, but it can also run into a limit on the /api/editing/render endpoint request and response size, which in Next.js is 4MB causing errors like:

API response for /api/editing/render exceeds 4MB.
This will cause the request to fail in a future version. 
https://nextjs.org/docs/messages/api-routes-body-size-limit

It is possible to turn off the check, but this is not recommended (https://nextjs.org/docs/messages/api-routes-response-size-limit).

The solution we ended up implementing was the ability to turn off the Experience Editor on individual fields. While not as fine grained as the MVC approach where the DisableWebEdit can be set on the rendering level, it proved enough to get the Experience Editor working fast again:

First, on the field template (/sitecore/templates/System/Templates/Template field) we added a new checkbox field called DisableChromes. But checking this field, the Sitecore developer would indicate that the field was not meant to be edited from the Experience Editor, and there where no need to send editor chromes to the rendering engine.

Next, we overrode the Sitecore.Pipelines.GetChromeData.GetFieldChromeData pipeline processor, adding the following logic to the Process Method:

public override void Process(GetChromeDataArgs args)
{
    if (!VerifyCanHandleChromeType(args))
        return;

    Field field = args.ExtractRequired("field");

    if (field.InnerItem.Fields[disableChromeFieldId]?.Value == "1")
        return;

    base.Process(args);
}

By patching in the overridden processor, we now had the capability of turning off the editor chromes for the fields we did not want to be able to edit in the Experience Editor. This reduced the size of the request to the /api/editing/render endpoint and meant we did not have to fear running in to problems with the payload restrictions when using Next.js.