-1

I'm having a performance issue, the loading speed is quite long.

I also noticed that when I first load the page, there is some plain text showing while loading before the page completely loaded and the theme appears.

Is there a way to improve this like component caching or any way possible?

  • What mode are you using? Integrated or headless mode? – Hishaam Namooya Nov 18 at 5:30
  • @HishaamNamooya Integrated – JSS Man Nov 18 at 5:41
  • The main reason for the slowness is because component caching works a bit different on JSS. The layoutservice returns a JSON of the whole page. There is a conversion which is performed to convert the JSON to HTML. This is where it is slow. You can cache that particular conversion but the impact is a all or nothing in the cache. So, if you cache that conversion, your page will be considered static. Once i am on a laptop I’ll provide more information and code snippet – Hishaam Namooya Nov 18 at 5:45
  • @HishaamNamooya I see, for the plain text showing on the loading part, I think it is because the props from layoutservice is already there but the component isn't mounted yet right? because some of the images are also showing on loading. Alright, I'll wait. Thank you so much. – JSS Man Nov 18 at 5:52
2

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.