Scaling Sitecore JSS images

Created: 22 May 2019, last update: 6 Dec 2019

Scaling Sitecore JSS images (GraphQL)

Sitecore can scale images out of the box, but also use a hash in the url, media protection. This ensures that the server only spends resources and disk space on valid image scaling requests. How can we use scaling with JSS if you know the sizes you can do it on the Sitecore site see JSS Customizing Layout Service Rendering Output but what if you want do it at the frontend?

Image scaling with JSSMedia handler
JSS has its own mediahandeler, default prefixed with -/jssmedia instead of -/media
In the web.config you have:

<add name="Sitecore.JavaScriptServices.Media.MediaRequestHandler" verb="*" path="sitecorejss_media.ashx" type="Sitecore.JavaScriptServices.Media.MediaRequestHandler, Sitecore.JavaScriptServices.Media" />

In the React sample app from “jss create <your-app-name> <app-template-name>” there is this in the config.

<javaScriptServices>
...
<!--
IMAGE RESIZING WHITELIST
Using Sitecore server-side media resizing (i.e. the `imageParams` or `srcSet` props on the `<Image/>` helper component)
could expose your Sitecore server to a denial-of-service attack by rescaling an image with many arbitrary dimensions.
In JSS resizing param sets that are unknown are rejected by a whitelist.
Sets of image sizing parameters that are used in app components must be whitelisted here.
If a param set is not whitelisted, the image will be returned _without resizing_.
To determine the image parameters being used, look at the query string on the `src` of the rendered image, i.e. '/img.jpg?mw=100&h=72' -> mw=100,h=72
Note: the parameter sets defined here are comma-delimited (,) instead of &-delimited like the query string. Multiple sets are endline-delimited.
--><allowedMediaParams>
<!-- XML element name is arbitary, useful for organizing and patching -->
<styleguide-image-sample>
mw=100,mh=50
</styleguide-image-sample>
<styleguide-image-sample-adaptive>
mw=300
mw=100
</styleguide-image-sample-adaptive>
</allowedMediaParams>
</javaScriptServices>

You can create your own allowedMediaParams. This works when you use the JSS mediahandler. The JSS JSON from the layout service and the Sitecore LinkManager does not create this link with /-/jssmedia. You need to replace it yourself.  

In the server.bundle.js there is this piece of code:

 /** * Receives a Sitecore media URL and replaces `/~/media` or `/-/media` with `/~/jssmedia` or `/-/jssmedia`, respectively.
 * This replacement allows the JSS media handler to be used for JSS app assets.
 * Also, any provided `params` are used as the querystring parameters for the media URL.
 */
exports.updateImageUrl = function (url, params) {
    // polyfill node `global` in browser to workaround https://github.com/unshiftio/url-parse/issues/150
    if (typeof window !== 'undefined' && !window.global) {
        window.global = {};
    }
    var parsed = URL(url, {}, true);
    parsed.set('query', params || parsed.query);
    var match = mediaUrlPrefixRegex.exec(parsed.pathname);
    if (match && match.length > 1) {
        // regex will provide us with /-/ or /~/ type
        parsed.set('pathname', parsed.pathname.replace(mediaUrlPrefixRegex, "/" + match[1] + "/jssmedia/"));
    }
    return parsed.toString();
};

The media protection is optional in Sitecore it is introduced in Sitecore 7.5. you can disable it, or disable it just for one website (not recommended) with a config patch like this:

 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <mediaLibrary>
      <requestProtection>
        <ignoreSites>
          <site name="website"/>
        </ignoreSites>
      </requestProtection>
    </mediaLibrary>
  </sitecore>
</configuration>

GraphQL
With GraphQL It is possible to specify field rendering parameters with GraphQL this look like this:

query MyDemoQuery( $contextItem: String!) 
{
    contextItem: item(path: $contextItem) {
    ...on Jsspage {
           image {
            value
            editable(fieldRendererParameters: "mw=100")
            test2:editable(fieldRendererParameters: "w=150") 
            test3:editable(fieldRendererParameters: "w=100&h=100&bc=AA4422") 
            test4:editable(fieldRendererParameters: "w=2000&as=true")
            test5:editable(fieldRendererParameters: "mw=250&mh=250") 
            rendered(fieldRendererParameters: "mw=100")
          }
     }
 }
}

This generates urls with a valid hash. This also works when you replace the `/-/media` with `/-/jssmedia` For a list of possible parameters, see this list <sc:image> Enhancements from the Sitecore 5.3 documentation ;)

Image optimizer
Sitecore Dianoga works with JSS https://github.com/kamsar/Dianoga