Purpose
This guide provides an overview of Resizer v2 features and the necessary actions and configurations to start using Resizer v2 within your Arc XP organization
Purpose
This guide provides an overview of Resizer v2 features and the necessary actions and configurations to start using Resizer v2 within your Arc XP organization
Audience
Developers and technically-savvy users who have worked with Resizer v1 and want to migrate to Resizer v2
Arc XP has moved to a newer version of Resizer (v2) as part of the continuous improvement efforts of our global SaaS platform. Key changes include the following:
auth
field of the image ANS whenever you upload an image to Photo Center, and is good for all resize variations. For existing images, you can generate the token on-demand by using the Signing Service API.SEO Filename
, which, if populated, saves as slugified text and can be prepended to the Arc ID in a Resizer URL. This improves your site’s SEO performance./resizer/v2/
as the entryway into Arc XP’s new resizing solution.Before migrating to Resizer v2, consider that your site’s SEO performance might be affected and that some Resizer v1 URLs could remain on your site after migration. This section provides more details on these considerations.
Migrating to Resizer v2 impacts your SEO performance because moving from v1 to v2 requires images to be re-fetched for the first time, transformed at edge, and cached, resulting in unavoidable latency.
First hit is defined as fetching the pristine image and creating the transformed image (derivative) based on the transformation request.
The first hit of Resizer v2 is slower (more latent) than Resizer v1. However, the pros outweigh this single con that may or may not actually affect your SEO performance. Resizer v2 provides the following benefits:
After the first hit impact, subsequent and cached hits with Resizer v2 perform on par with Resizer v1 in terms of latency and output performance. We obtained the following results from testing with a beta partner:
TIME | COUNT | LATENCY (ms) | SIZE (kb) | |
---|---|---|---|---|
v1 | Feb 6 - Feb 7 | 1.31M | 75ms | 27.3kb |
v2 | Oct 4 - Oct 5 | 947k | 75.9ms | 27.8kb |
After you migrate to Resizer v2, it is possible that v1 image URLs may still exist and Google bots are still crawling them. Additionally, the migration may accidentally miss v1 image URLs. Resizer v2 is in General Availability on Production. We are adding a redirect so that v1 URLs automatically redirect to v2.
Before taking the migration steps, make sure you meet the following requirements:
You are able to run PageBuilder locally and make changes to your feature bundle.
You are familiar with content sources and either have custom content sources or are using Themes-provided content sources. See PageBuilder Content Source Documentation.
You are familiar with PageBuilder Blocks and are able to update them.
You are familiar with environment variables and how to add new variables. See PageBuilder Environment Variables Documentation.
For the following examples, we are going to assume there is no image resizing being used for your code and you are rendering the original images.
Take the steps in this section to start using Resizer v2.
Arc XP recommends doing a phased migration to Resizer v2 if you are not using out-of-the-box Arc Blocks (Themes) or if you are using fully custom blocks. This means updating one or few blocks at a time. Since the Themes 2.0 release, all Arc Blocks natively support Resizer v2. If you remained on the upgrade path for your custom blocks, there is no further action needed to migrate to Resizer v2.
A phased migration has the following pros and cons:
Pros:
Cons:
If you do wish to do a phased migration to Resizer v2 on a smaller section of your site, see Phased migration from Resizer v1 to Resizer v2 for more details.
Resizer v2 requires that you add the following environment variables to your /environment/*.json
file.
{"RESIZER_TOKEN_VERSION": 1,"SIGNING_SERVICE_DEFAULT_APP": "resizer","RESIZER_URL": "{CONTENT_BASE}/resizer/v2/"}
The RESIZER_TOKEN_VERSION
value may vary depending on your organization setup. Make a Get request to the following endpoint of the Delivery API:
{CONTENT_BASE)/v1/organization/hmac-key/resizer
The response includes the field ssm_version
. You must use this value for RESIZER_TOKEN_VERSION
.
auth
field to images’ ANSIf you added images to Photo Center before the Resizer v2 or Arc Blocks v2 releases, those images need to be inflated to include the auth
field and the resizer token in their ANS.
Arc XP offers the following methods to inflate ANS objects:
Update existing content sources to use the fetch
function (instead of resolve
).
Add the logic to the content source to call the Signing Service API when needed.
The following code block provides an example of an updated content source that uses the updated environment variables:
import axios from "axios";import {ARC_ACCESS_TOKEN,CONTENT_BASE,SIGNING_SERVICE_DEFAULT_APP,RESIZER_TOKEN_VERSION,} from "fusion:environment";const params = {id: "text",service: "text",serviceVersion: "text",};const fetch = ({id,service = SIGNING_SERVICE_DEFAULT_APP,serviceVersion = RESIZER_TOKEN_VERSION,}) =>axios({url: `${CONTENT_BASE}/signing-service/v2/sign/${service}/${serviceVersion}?value=${encodeURIComponent(id)}`,headers: {"content-type": "application/json",Authorization: `Bearer ${ARC_ACCESS_TOKEN}`,},method: "GET",}).then(({ data: content }) => content);export default {fetch,params,http: false,// 365 day ttlttl: 31536000,};
This section provides a base example of a block that does not use Resizer v2 and explains the changes that you need to make to the example code in order to use Resizer v2.
The following example uses ANS content to render an image and headline. The image comes from the Promo Items of Composer, and the headline is the Composer headline:
import React from "react";import PropTypes from "@arc-fusion/prop-types";import { useContent } from "fusion:content";
const PromoBlock = ({ customFields }) => { const content = useContent({ source: customFields?.itemContentConfig?.contentService ?? null, query: customFields?.itemContentConfig?.contentConfigValues ? { ...customFields.itemContentConfig.contentConfigValues, } : null, }) || null;
if (!customFields?.itemContentConfig || !content) return null;
return ( <article> {/* The image is using Cloudfront directly - which is not the most optimized way to display an image from Photo Center Ensure images always go through resizer - see resizer v2 document for details */} <img src={content?.promo_items?.basic?.url} alt="" /> <h2>{content?.headlines?.basic}</h2> </article> );};
PromoBlock.propTypes = { customFields: PropTypes.shape({ itemContentConfig: PropTypes.contentConfig("ans-item").tag({ group: "Configure Content", label: "Display Content Info", }), }),};
PromoBlock.label = "Promo Block";PromoBlock.icon = "paragraph-bullets";
export default PromoBlock;
To update the previous example code to use Resizer v2, take the following steps:
import { RESIZER_URL, RESIZER_TOKEN_VERSION } from "fusion:environment";
Update the rest of the block to match the following code:
const promoImage = content?.promo_items?.basic;
// Get the Image Auth Token from the `auth` object and use the// key assigned to auth key 1const imageAuth = promoImage.auth[RESIZER_TOKEN_VERSION];
// Get the _id of the Imageconst imageID = promoImage._id;
let assetId = imageID;
// Append the file extension of the image to assetId if presentif (promoImage.url.split("/").pop().split(".").length > 1) { assetId = assetId.concat(".", promoImage.url.split(".").pop());}
return ( <article> <img src={`${RESIZER_URL}/${assetId}?auth=${imageAuth}&width=300`} alt="" /> <h2>{content?.headlines?.basic}</h2> </article>);
The img src
is now using Resizer v2 path with its auth token and resizer options instead of the raw image URL.
This example calls the Content API for a single item and inflates only the promo images image (Featured Media). ANS objects can contain multiple images, and these could also need inflating:
import axios from 'axios';import { CONTENT_BASE, ARC_ACCESS_TOKEN, RESIZER_TOKEN_VERSION,} from 'fusion:environment';
// Import the signing service content sourceimport signingService from './signing-service';
const params = { _id: 'text',};
const fetch = async ({ _id: id, 'arc-site': site }, { cachedCall }) => { const contentRequest = await axios({ url: `${CONTENT_BASE}/content/v4/?_id=${id}${site ? `&website=${site}` : ''}`, headers: { 'content-type': 'application/json', Authorization: `Bearer ${ARC_ACCESS_TOKEN}`, }, method: 'GET', }).then(({ data: content }) => content);
// Inflate ANS with token promo items -> basic -> image if there is no auth if (contentRequest.promo_items.basic.type === 'image' && !contentRequest.promo_items.basic?.auth?.[RESIZER_TOKEN_VERSION]) { contentRequest.promo_items.basic.auth = contentRequest.promo_items.basic.auth || {}; const signingResponse = await cachedCall( 'image-token', signingService.fetch, // The fetch method imported from the resizer content source { query: { id: contentRequest.promo_items.basic._id }, ttl: 31536000, independent: true }, ); contentRequest.promo_items.basic.auth[RESIZER_TOKEN_VERSION] = signingResponse.hash; }
return { ...contentRequest, };};
export default { schemaName: 'ans-item', params, fetch,};
The previous code does the following:
Imports the signing service content source. The code assumes the two content sources are in the same directory within your feature bundle.
Imports the RESIZER_TOKEN_VERSION
environment variable that enables inflating an ANS object.
Uses the fetch
content source pattern with partial caching.
Uses axios
client to make the request to the content API
With the response from Content API, the code:
a. Checks if the promo_items.basic.type
is an image
If so, uses the partial caching feature to make a request to the signing service using the signing service content source.
b. Passes the image _id
to the signing service to get a signed string for the image _id
.
c. Adds the response of the signing service content source to the content API response.
d. Assigns the signing service response to an auth
object using the version number as the object key.
With the content source updated to inflate the ANS object with the auth
data, your blocks do not have to handle getting auth
tokens. Fetching auth
tokens on the server provides better performance, but makes use of caching.
To determine the Resizer URL for your Photo Center images, use these steps:
https://{org}-{default-website}-{env}.web.arc-cdn.net/resizer
.{website name}/resizer
./v2
to the base Resizer URL: {website name}/resizer/v2
.SMDVGH3HWRBMRGDZHZFNTCP6EU.jpg
{website name}/resizer/v2/SMDVGH3HWRBMRGDZHZFNTCP6EU.jpg
GET
request to the Photo API photo/api/v2/{photoId}
. Take the Auth token from the image ANS auth field (associated with the image) and paste that as a query parameter at the end of the URL. For example:{website name}/resizer/v2/SMDVGH3HWRBMRGDZHZFNTCP6EU.jpg?auth=db02a059a34fd56e1041d5513ec2745a54239c848a8b
Resizer v2 also supports external images. This section provides an example of a a block that has the ability for an editor to specify an external image through a custom field in PageBuilder Editor.
The following block outputs an image and a headline, provided that both are supplied through PageBuilder Editor. The image uses the imageURL
with no resizing.
import React from "react";import PropTypes from "@arc-fusion/prop-types";
const ManualPromo = ({ customFields }) => { const { imageURL, headline } = customFields; if (!imageURL || !headline) return null;
return ( <article> <img src={imageURL} alt="" /> <h2>{headline}</h2> </article> );};
ManualPromo.propTypes = { customFields: PropTypes.shape({ imageURL: PropTypes.string, headline: PropTypes.string, }),};ManualPromo.label = "Manual Promo Block";ManualPromo.icon = "paragraph-bullets";
export default ManualPromo;
To make the block use Resizer v2, you must update the block to call the signing service content source (see the Example with content source). You must also update the image src
to use the Resizer v2 URL, auth token, and resizer parameters. Take the following steps:
Import the RESIZER_URL
from the environment variables.
Import the useContent
hook from fusion:content
to enable content source calls within the block.
As the signing service is a content source, you can use the useContent
hook to call it as per other content sources. For this case, you must pass the imageURL
from the custom fields to the id
query param of the content source call.
Update the image src
attribute to construct the image src
as needed for Resizer v2.
As you are calling the signing service content source to get the auth
token for Resizer v2, you use content.hash
as the value for the auth
query param in the image.
The resulting code is as follows:
import React from "react";import PropTypes from "@arc-fusion/prop-types";import { RESIZER_URL } from "fusion:environment";import { useContent } from "fusion:content";
const ManualPromo = ({ customFields = {} }) => { const { imageURL, headline } = customFields; const content = useContent({ source: 'signing-service', query: imageURL ? { id: imageURL } : null, }) || null;
if (!imageURL || !headline) return null;
return ( <article> <img src={`${RESIZER_URL}/${imageURL}?auth=${content.hash}&width=300`} alt="" /> <h2>{headline}</h2> </article> );};
ManualPromo.propTypes = { customFields: PropTypes.shape({ imageURL: PropTypes.string, headline: PropTypes.string, }),};
ManualPromo.label = "Manual Promo Block";ManualPromo.icon = "paragraph-bullets";
export default ManualPromo;
To ensure you’re delivering the best experience and images possible to your end users, other optimizations exist for responsive images and, if needed, art-directed images. Arc Blocks v2 handle these optimizations natively.
To learn more about image optimizations, see:
https://clientsite.com/resizer/v2/person-with-red-ball-ABCDEFGHIJKLMNOPQRSTUVWXY.jpg?auth=40b3b900866998ec98c4a286eef727080a10ac968d5eed7bd4a6a084511db6c1&width=500&height=500&quality=80
{ "_id": "6UI63OCUJI5AW6IHRW46XWAAPU", "additional_properties": { ... }, "auth": { "1": "40b3b900866998ec98c4a286eef727080a10ac968d5eed7bd4a6a084511db6c1" }, ... "seo_filename": "person-with-red-ball", "url": "https://cloudfront-us-east-1.images.arcpublishing.com/6UI63OCUJI5AW6IHRW46XWAAPU.jpg", "type": "image"}