When using the JSS Integrated Mode on a project, I've seen that the conversion of the JSON to HTML takes time. This depends on how big the JSON response is.
What I did
I had to extend the GetJsLayoutRenderer
in order to be able to change the instantiation of the class JsLayoutRenderer
.
Major Point
The main drawback with this is that if you have dynamic queries such as personalization, it will not take effect. This is because it has already cached the HTML Rendering. I am still working on this part and I am using JAMStack to perform the queries.
Implementation
Below is the code snippet I'ved used.
The extended GetJsLayoutRenderer
using Sitecore.Abstractions;
using Sitecore.JavaScriptServices.Configuration;
using Sitecore.JavaScriptServices.ViewEngine.Presentation;
using Sitecore.JavaScriptServices.ViewEngine.Presentation.Pipelines.MvcGetRenderer;
using Sitecore.LayoutService.Configuration;
using Sitecore.LayoutService.ItemRendering;
using Sitecore.LayoutService.Serialization;
using Sitecore.Mvc.Pipelines.Response.GetRenderer;
namespace Experimental.Foundation.Pipelines.Renderer
{
public class GetJsLayoutRendererExtension : GetJsLayoutRenderer
{
public GetJsLayoutRendererExtension(ILayoutService layoutService, ISerializerService serializerService, IConfiguration layoutServiceConfiguration, IConfigurationResolver appConfigurationResolver, IJssRendererConfiguration jssRendererConfiguration, BaseCorePipelineManager pipelineManager) : base(layoutService, serializerService, layoutServiceConfiguration, appConfigurationResolver, jssRendererConfiguration, pipelineManager)
{
}
protected override Sitecore.Mvc.Presentation.Renderer GetRenderer(GetRendererArgs args)
{
AppConfiguration appConfig = this.ResolveAppConfiguration(args.Rendering.Item);
if (appConfig == null)
{
return new JssAppNotFoundStandardValuesRenderer();
}
NamedConfiguration layoutServiceNamedConfig = this.ResolveNamedConfiguration(appConfig);
return new JsLayoutRendererExtension(args.Rendering, appConfig, layoutServiceNamedConfig, this.LayoutService, this.SerializerService, this.JssRendererConfig);
}
}
}
The extended class of JsLayoutRenderer
using System.IO;
using Experimental.Foundation.Utilities.Helpers;
using Newtonsoft.Json;
using Sitecore.Data.Items;
using Sitecore.JavaScriptServices.Configuration;
using Sitecore.JavaScriptServices.ViewEngine.Presentation;
using Sitecore.JavaScriptServices.ViewEngine.RenderingEngine;
using Sitecore.LayoutService.Configuration;
using Sitecore.LayoutService.ItemRendering;
using Sitecore.LayoutService.Serialization;
using Sitecore.Mvc.Presentation;
namespace Experimental.Foundation.Pipelines.Renderer
{
public class JsLayoutRendererExtension : JsLayoutRenderer
{
public JsLayoutRendererExtension(Rendering rendering, AppConfiguration appConfig, NamedConfiguration layoutServiceNamedConfig, ILayoutService layoutService, ISerializerService serializerService, IJssRendererConfiguration jssRendererConfiguration) : base(rendering, appConfig, layoutServiceNamedConfig, layoutService, serializerService, jssRendererConfiguration)
{
}
protected override object[] ResolveFunctionArgs()
{
string requestPath = GetRequestPath();
Item itemToRender = GetItemToRender();
RenderedItem rendered = RenderItem(itemToRender, LayoutServiceNamedConfiguration);
dynamic viewBag = GetViewBag(GetViewBagPipelineArgs(itemToRender));
string text = SerializerService.Serialize(rendered, LayoutServiceNamedConfiguration.SerializationConfiguration);
object obj = JsonConvert.SerializeObject(viewBag, LayoutServiceNamedConfiguration.SerializationConfiguration.JsonSerializerSettings);
var cacheKey = $"{rendered.ItemId}-{rendered.ItemLanguage}";
return new []
{
requestPath,
text,
obj,
cacheKey
};
}
protected override void PerformRender(TextWriter writer, IRenderEngine renderEngine, string moduleName, string functionName, object[] functionArgs)
{
var cacheKey = functionArgs[3] as string;
// Apply/Read cache here
var renderResult = CacheHelper<RenderResult>.GetOrCreateCache(cacheKey,
() => renderEngine.Invoke<RenderResult>(moduleName, functionName, functionArgs));
if (!string.IsNullOrWhiteSpace(renderResult.Redirect))
{
if (!renderResult.Status.HasValue || renderResult.Status == 302)
{
JssRendererConfiguration.HttpContext.Response.Redirect(renderResult.Redirect);
}
else
{
JssRendererConfiguration.HttpContext.Response.RedirectPermanent(renderResult.Redirect);
}
}
if (renderResult.Status.HasValue)
{
JssRendererConfiguration.HttpContext.Response.StatusCode = renderResult.Status.Value;
}
writer.Write(renderResult.Html);
}
}
}
Finally, you would need to patch the existing GetJsLayoutRenderer
as shown below
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:search="http://www.sitecore.net/xmlconfig/search/">
<sitecore>
<pipelines>
<mvc.getRenderer>
<processor type="Experimental.Foundation.Pipelines.Renderer.GetJsLayoutRendererExtension, Experimental.Foundation.Pipelines" patch:instead="*[@type='Sitecore.JavaScriptServices.ViewEngine.Presentation.Pipelines.MvcGetRenderer.GetJsLayoutRenderer, Sitecore.JavaScriptServices.ViewEngine']" resolve="true">
<layoutServiceConfigurationName>jss</layoutServiceConfigurationName>
</processor>
</mvc.getRenderer>
</pipelines>
</sitecore>
</configuration>
More information can be found at my blog post
Sitecore JSS Integrated Mode Cache