Skip to main content

Using the Optimized ShopifyImage Component

When creating custom blocks that are added through the Appmaker dashboard and registered in your theme, loading large images can impact performance. This is particularly important for blocks that display images uploaded through the dashboard's interface. The ShopifyImage component provides an optimized solution by:

  1. Automatically resizing images before download using Shopify's image API
  2. Supporting both standard React Native Image and FastImage components
  3. Handling URL parameter management for image dimensions

Component Implementation

Create a new file ShopifyImage.tsx in your theme's components directory and add the following code:

import React, { useMemo } from 'react';
import FastImage, { FastImageProps } from 'react-native-fast-image';
import { Image } from 'react-native';

// Safety check to ensure only Shopify CDN URLs are processed
// The dashboard will always provide Shopify image URLs, this is just a failsafe
const isValidUrl = (url: string): boolean => {
try {
if (url.includes(' ')) return false;
if (!url.startsWith('http://') && !url.startsWith('https://')) return false;
return url.includes('shopify.com');
} catch {
return false;
}
};

const appendQueryParam = (url: string, param: string, value: number): string => {
if (!url || !param) return url;

if (typeof value !== 'number' || value <= 0 || !Number.isFinite(value)) {
return url;
}

try {
const hasQuery = url.includes('?');
const hasTrailingQuery = url.endsWith('?');
const hasTrailingAmp = url.endsWith('&');

if (hasQuery) {
return `${url}${hasTrailingQuery || hasTrailingAmp ? '' : '&'}${param}=${value}`;
}
return `${url}?${param}=${value}`;
} catch {
return url;
}
};

interface ShopifyImageProps extends FastImageProps {
useFastImage?: boolean;
maxWidth?: number;
maxHeight?: number;
}

const ShopifyImage: React.FC<ShopifyImageProps> = ({
useFastImage = false,
maxWidth,
maxHeight,
source,
...props
}) => {
const modifiedSource = useMemo(() => {
if (!source || typeof source === 'number') return source;

try {
const { uri } = source;

if (!uri || typeof uri !== 'string') return source;
// Safety checks - dashboard always provides Shopify URLs
if (!uri.includes('shopify.com')) return source;
if (!isValidUrl(uri)) return source;
if (!maxWidth && !maxHeight) return source;

let newUri = uri;

if (maxWidth && maxWidth > 0) {
newUri = appendQueryParam(newUri, 'width', Math.floor(maxWidth));
}

if (maxHeight && maxHeight > 0) {
newUri = appendQueryParam(newUri, 'height', Math.floor(maxHeight));
}

if (newUri === uri) return source;

return {
...source,
uri: newUri,
};
} catch (error) {
console.warn('Error modifying Shopify image URL:', error);
return source;
}
}, [source, maxWidth, maxHeight]);

const ImageComponent = useFastImage ? FastImage : Image;
return <ImageComponent source={modifiedSource} {...props} />;
};

export default ShopifyImage;

Usage in Custom Blocks

To use the ShopifyImage component in your custom blocks that are registered in the theme and configured through the Appmaker dashboard:

import { StyleSheet, View } from 'react-native'
import React from 'react'
import ShopifyImage from '../components/ShopifyImage';

type Props = {}

const DashboardImageBlock = (props: Props) => {
const { attributes } = props;

// The image URL will be provided by the dashboard when the block is configured
return (
<View>
<ShopifyImage
source={{
uri: attributes.image.url,
}}
maxWidth={300}
maxHeight={200}
useFastImage={true}
style={styles.image}
/>
</View>
);
};

export default DashboardImageBlock;

const styles = StyleSheet.create({
image: {
width: '100%',
height: 200,
},
});

Props

The ShopifyImage component accepts all standard props from React Native's Image component plus these additional props:

PropTypeDefaultDescription
useFastImagebooleanfalseWhen true, uses react-native-fast-image instead of the standard Image component
maxWidthnumberundefinedMaximum width to request from Shopify's image API
maxHeightnumberundefinedMaximum height to request from Shopify's image API

How It Works

  1. When configuring the block through the dashboard, you'll upload or select an image
  2. The dashboard provides a Shopify CDN URL as per the attribute settings from the block configuration
  3. The component includes safety checks to ensure only Shopify CDN URLs are processed
  4. If maxWidth or maxHeight are provided, it appends these parameters to the URL
  5. Shopify's CDN will return an optimized image of the requested size
  6. This reduces the download size and improves performance

Best Practices

  1. Always specify both maxWidth and maxHeight to ensure optimal image sizing
  2. Use useFastImage={true} for better performance with multiple images
  3. Set appropriate style dimensions that match your maxWidth/maxHeight to avoid layout shifts
  4. Consider the device's screen density when setting dimensions