Skip to content

Latest commit

 

History

History
379 lines (275 loc) · 13.8 KB

CHANGELOG.md

File metadata and controls

379 lines (275 loc) · 13.8 KB

@shopify/hydrogen

2023.4.0

Major Changes

  • Releases 2023-04 (#754) by @lordofthecactus

  • Updates Hydrogen to Storefront 2023-04 API release.

  • Updates types from CartLineConnection to BaseCartLineConnection.

  • Deprecates CartLinePrice from @shopify/hydrogen-react use Money instead:

    - import {CartLinePrice} from '@shopify/hydrogen-react';
    + import {Money} from '@shopify/hydrogen-react';
    - <CartLinePrice line={line} />
    + <Money data={line.priceV2} />

    Check the docs for using Money 💵.

  • Adds a new Image component, replacing the existing one. While your existing implementation won't break, props widths and loaderOptions are now deprecated disregarded, with a new aspectRatio prop added. (#787) by @benjaminsehl

    Migrating to the new Image

    The new Image component is responsive by default, and requires less configuration to ensure the right image size is being rendered on all screen sizes.

    Before

    <Image
      data={image}
      widths={[400, 800, 1200]}
      width="100px"
      sizes="90vw"
      loaderOptions={{
        scale: 2,
        crop: 'left',
      }}
    />

    After

    <Image data={image} sizes="90vw" crop="left" aspectRatio="3/2" />

    Note that widths and loaderOptions have now been deprecated, declaring width is no longer necessary, and we’ve added an aspectRatio prop:

    • widths is now calculated automatically based on a new srcSetOptions prop (see below for details).
    • loaderOptions has been removed in favour of declaring crop and src as props. width and height should only be set as props if rendering a fixed image size, with width otherwise defaulting to 100%, and the loader calculating each dynamically.
    • aspectRatio is calculated automatically using data.width and data.height (if available) — but if you want to present an image with an aspect ratio other than what was uploaded, you can set using the format Int/Int (e.g. 3/2, see MDN docs for more info, note that you must use the fraction style of declaring aspect ratio, decimals are not supported); if you've set an aspectRatio, we will default the crop to be crop: center (in the example above we've specified this to use left instead).

    Examples

    Basic Usage

    <Image data={data} />

    This would use all default props, which if exhaustively declared would be the same as typing:

    <Image
      data={data}
      crop="center"
      decoding="async"
      loading="lazy"
      width="100%"
      sizes="100vw"
      srcSetOptions={{
        interval: 15,
        startingWidth: 200,
        incrementSize: 200,
        placeholderWidth: 100,
      }}
    />

    An alternative way to write this without using data would be to use the src, alt, and aspectRatio props. For example:

    <Image
      src={data.url}
      alt={data.altText}
      aspectRatio={`${data.width}/${data.height}`}
    />

    Assuming data had the following shape:

    {
      "url": "https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg",
      "altText": "alt text",
      "width": "4000",
      "height": "4000"
    }

    All three above examples would result in the following HTML:

    <img
      srcset="https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=300&height=300&crop=center 300w, … *13 additional sizes* … https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=3000&height=3000&crop=center 3000w"
      src="https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=100&height=100&crop=center"
      alt="alt text"
      sizes="100vw"
      loading="lazy"
      decoding="async"
      width="100px"
      height="100px"
      style="aspect-ratio: 4000 / 4000;"
    />

    Fixed-size Images

    When using images that are meant to be a fixed size, like showing a preview image of a product in the cart, instead of using aspectRatio, you'll instead declare width and height manually with fixed values. For example:

    <Image data={data} width={80} height={80} />

    Instead of generating 15 images for a broad range of screen sizes, Image will instead only generate 3, for various screen pixel densities (1x, 2x, and 3x). The above example would result in the following HTML:

    <img
      srcset="
        https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=80&height=80&crop=center   1x,
        https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=160&height=160&crop=center 2x,
        https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=240&height=240&crop=center 3x
      "
      src="https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=80&height=80"
      alt="alt text"
      loading="lazy"
      width="80px"
      height="80px"
      style="aspect-ratio: 80 / 80;"
    />

    If you don't want to have a fixed aspect ratio, and instead respect whatever is returned from your query, the following syntax can also be used:

    <Image data={data} width="5rem" />

    Which would result in the same HTML as above, however the generated URLs inside the src and srcset attributes would not have height or crop parameters appended to them, and the generated aspect-ratio in style would be 4000 / 4000 (if using the same data values as our original example).

    Custom Loaders

    If your image isn't coming from the Storefront API, but you still want to take advantage of the Image component, you can pass a custom loader prop, provided the CDN you're working with supports URL-based transformations.

    The loader is a function which expects a params argument of the following type:

    type LoaderParams = {
      /** The base URL of the image */
      src?: ImageType['url'];
      /** The URL param that controls width */
      width?: number;
      /** The URL param that controls height */
      height?: number;
      /** The URL param that controls the cropping region */
      crop?: Crop;
    };

    Here is an example of using Image with a custom loader function:

    const customLoader = ({src, width, height, crop}) => {
      return `${src}?w=${width}&h=${height}&gravity=${crop}`;
    };
    
    export default function CustomImage(props) {
      <Image loader={customLoader} {...props} />;
    }
    
    // In Use:
    
    <CustomImage data={customCDNImageData} />;

    If your CDN happens to support the same semantics as Shopify (URL params of width, height, and crop) — the default loader will work a non-Shopify src attribute.

    An example output might look like: https://mycdn.com/image.jpeg?width=100&height=100&crop=center

    Additional changes

    • Added the srcSetOptions prop used to create the image URLs used in srcset. It’s an object with the following keys and defaults:

      srcSetOptions = {
        intervals: 15, // The number of sizes to generate
        startingWidth: 200, // The smalles image size
        incrementSize: 200, // The increment by to increase for each size, in pixesl
        placeholderWidth: 100, // The size used for placeholder fallback images
      };
    • Added an export for IMAGE_FRAGMENT, which can be imported from Hydrogen and used in any Storefront API query, which will fetch the required fields needed by the component.

    • Added an export for shopifyLoader for using Storefront API responses in conjunction with alternative frameworks that already have their own Image component, like Next.js

Patch Changes

2023.1.7

Patch Changes

  • Bump internal Remix dependencies to 1.15.0. (#728) by @wizardlyhel

    Recommendations to follow:

    • Upgrade all the Remix packages in your app to 1.15.0.
    • Enable Remix v2 future flags at your earliest convenience following the official guide.
  • Add an experimental createWithCache_unstable utility, which creates a function similar to useQuery from Hydrogen v1. Use this utility to query third-party APIs and apply custom cache options. (#600) by @frandiox

    To setup the utility, update your server.ts:

    import {
      createStorefrontClient,
      createWithCache_unstable,
      CacheLong,
    } from '@shopify/hydrogen';
    
    // ...
    
      const cache = await caches.open('hydrogen');
      const withCache = createWithCache_unstable({cache, waitUntil});
    
      // Create custom utilities to query third-party APIs:
      const fetchMyCMS = (query) => {
        // Prefix the cache key and make it unique based on arguments.
        return withCache(['my-cms', query], CacheLong(), () => {
          const cmsData = await (await fetch('my-cms.com/api', {
            method: 'POST',
            body: query
          })).json();
    
          const nextPage = (await fetch('my-cms.com/api', {
            method: 'POST',
            body: cmsData1.nextPageQuery,
          })).json();
    
          return {...cmsData, nextPage}
        });
      };
    
      const handleRequest = createRequestHandler({
        build: remixBuild,
        mode: process.env.NODE_ENV,
        getLoadContext: () => ({
          session,
          waitUntil,
          storefront,
          env,
          fetchMyCMS,
        }),
      });

    Note: The utility is unstable and subject to change before stabalizing in the 2023.04 release.

  • Updated dependencies [85ae63a, 5e26503]:

2023.1.6

Patch Changes

  • Add new loader API for setting seo tags within route module (#591) by @cartogram

  • ShopPayButton component now can receive a storeDomain. The component now does not require ShopifyProvider. (#645) by @lordofthecactus

    1. Update Remix to 1.14.0 (#599) by @blittle

    2. Add Cache-Control defaults to all the demo store routes

  • Added robots option to SEO config that allows users granular control over the robots meta tag. This can be set on both a global and per-page basis using the handle.seo property. (#572) by @cartogram

    Example:

    export handle = {
      seo: {
        robots: {
          noIndex: false,
          noFollow: false,
        }
      }
    }
  • Fix active cart session event in Live View (#614) by @wizardlyhel

    Introducing getStorefrontHeaders that collects the required Shopify headers for making a Storefront API call.

    • Make cart constants available as exports from @shopify/hydrogen-react
    • Deprecating buyerIp and requestGroupId props from createStorefrontClient from @shopify/hydrogen
    • Deprecating getBuyerIp function from @shopify/remix-oxygen
    + import {getStorefrontHeaders} from '@shopify/remix-oxygen';
    import {createStorefrontClient, storefrontRedirect} from '@shopify/hydrogen';
    
    export default {
      async fetch(
        request: Request,
        env: Env,
        executionContext: ExecutionContext,
      ): Promise<Response> {
    
        const {storefront} = createStorefrontClient({
          cache,
          waitUntil,
    -     buyerIp: getBuyerIp(request),
          i18n: {language: 'EN', country: 'US'},
          publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN,
          privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN,
          storeDomain: `https://${env.PUBLIC_STORE_DOMAIN}`,
          storefrontApiVersion: env.PUBLIC_STOREFRONT_API_VERSION || '2023-01',
          storefrontId: env.PUBLIC_STOREFRONT_ID,
    -     requestGroupId: request.headers.get('request-id'),
    +     storefrontHeaders: getStorefrontHeaders(request),
        });
  • Updated dependencies [c78f441, 7fca5d5]:

2023.1.5

Patch Changes

2023.1.4

Patch Changes

  • Fix template imports to only reference @shopify/hydrogen, not @shopify/hydrogen-react (#523) by @blittle

2023.1.3

Patch Changes

  • Send Hydrogen version in Storefront API requests. (#471) by @frandiox

  • Fix default Storefront type in LoaderArgs. (#496) by @frandiox

2023.1.2

Patch Changes

  • Add license files and readmes for all packages (#463) by @blittle

2023.1.1

Patch Changes

  • Initial release