Pack Hydrogen Demo - A simple example storefront powered by Pack + Hydrogen

image

Demo | Pack Platform

About

About Pack:

Build and manage your Custom Storefront with Pack, a Hydrogen-based Digital Experience Platform

Welcome to Pack, your ultimate solution for creating exceptional storefronts that captivate your audience and drive results. Discover how Pack redefines the way you approach content management, design, and performance to unleash the full potential of your brand.

Meet the Hydrogen-Pack Starter:

Introducing Hydrogen-Pack Starter, a customized Hydrogen starter that showcases how Pack can power your custom Shopify storefronts. With Pack, you can seamlessly connect to Shopify, leverage prebuilt React components + third party integrations, and design engaging shopping experiences.

Features

Explore the capabilities that make Pack stand out:

  • Unified Experience Platform: Manage components and content schema effortlessly all within Pack without the need of an additional CMS or page builder.
  • Live Previewing: See changes in real-time to ensure a pixel-perfect storefront.
  • Local Development Workflow: Streamline development for faster iteration.
  • Shopify CDN-Ready: Ensure optimal performance and flexibility.
  • Typescript and Tailwind-Ready: Tailor your storefront with preferred frameworks.
  • Oxygen Integration: Seamlessly integrate with your preferred hosting.
  • Third-Party Integration: Easily add custom snippets or build your own integrations.

Our Approach

At Pack, we believe in simplicity and empowerment:

  • Data Source Clarity: Pack syncs Shopify product and collection data solely for reference in the Customizer, eliminating stale information.
  • Pack Customizer Flexibility: Leverage Metaobjects and seamlessly integrate Shopify product data, metafields, metaobjects, or Pack Content to create compelling and easy to manage experiences.
  • Standard Structure: Our demo store follows the familiar Shopify page structure, including products, collections, pages, blogs and articles

What's included

  • Remix
  • Hydrogen
  • Oxygen
  • Shopify CLI
  • ESLint
  • Prettier
  • GraphQL generator
  • TypeScript and JavaScript flavors

Getting started

Requirements

  • Node.js version 16.14.0 or higher

Environment Variables

Before you can run your application locally, you will need to create an .env file at the root of your project with your shop's domain and Storefront API token. You can copy the necessary values from the Pack Storfront by going to Settings -> Developer, then Copy All under the Storefront Variables section. See the example below:

SESSION_SECRET="XXX"
PUBLIC_STOREFRONT_API_TOKEN="XXX"
PUBLIC_STORE_DOMAIN="XXX"
PACK_PUBLIC_TOKEN="XXX"
PACK_SECRET_TOKEN="XXX"

Building for production

This command will simulate the same deployment job that Shopify Oxygen will use when deploying your live site.

npm run build

Building for local development

This command will start a server locally on your machine at http://localhost:3000.

npm run dev

Pack Customizer Content

You can access the data in the Pack Customizer by using the pack object that lives in the Hydrogen context. See the following example:

export async function loader({params, context, request}: LoaderArgs) {
  const {handle} = params;
  const storeDomain = context.storefront.getShopifyDomain();

  const searchParams = new URL(request.url).searchParams;
  const selectedOptions: any = [];

  // set selected options from the query string
  searchParams.forEach((value, name) => {
    selectedOptions.push({name, value});
  });

  const {data} = await context.pack.query(PRODUCT_PAGE_QUERY, {
    variables: {handle},
  });

  const {product} = await context.storefront.query(PRODUCT_QUERY, {
    variables: {
      handle,
      selectedOptions,
    },
  });

  ...
}

The data object will contain all the Pack Section Setting content provided by CMS Authors in the Customizer. This data will be define per each Section's Setting schema. While the product object will contain any Shopify speficic data provided by the Storefront API.

See https://docs.packdigital.com/for-developers/section-api/schema.

Caching

Pack is leveraging the same Caching Strategy available with the Hydrogen framework. For an example of this, check out the @pack/client

export function createPackClient(options: CreatePackClientOptions): Pack {
  const {apiUrl, cache, waitUntil, preview, contentEnvironment} = options;
  const previewEnabled = !!preview?.session.get('enabled');
  const previewEnvironment = preview?.session.get('environment');

  return {
    preview,
    isPreviewModeEnabled: () => previewEnabled,
    async query<T = any>(
      query: string,
      {variables, cache: strategy = CacheLong()}: QueryOptions = {},
    ) {
      const queryHash = await hashQuery(query, variables);
      const withCache = createWithCache<QueryResponse<T>>({
        cache,
        waitUntil,
      });

      // The preview environment takes precedence over the content environment
      // provided when creating the client
      const environment =
        previewEnvironment || contentEnvironment || PRODUCTION_ENVIRONMENT;
      const fetchOptions = {
        apiUrl,
        query,
        variables,
        token: options.token,
        previewEnabled,
        contentEnvironment: environment,
      };

      // Preview mode always bypasses the cache
      if (previewEnabled) return packFetch<T>(fetchOptions);

      return withCache(queryHash, strategy, () => packFetch<T>(fetchOptions));
    },
  };
}

Data Layer

The Pack StarterKit will submit pageView and addToCart (coming soon) to Shopify Analytics via the Hydrogen hook. See the following article for more details: https://shopify.dev/docs/api/hydrogen/2023-07/utilities/sendshopifyanalytics

For example on how events are submitted view the products route (app/routes/products.$handle.tsx):

export async function loader({params, context, request}: LoaderArgs) {
  ...

   if (!data.productPage) {
    throw new Response(null, {status: 404});
  }
  // optionally set a default variant, so you always have an "orderable" product selected
  const selectedVariant =
    product.selectedVariant ?? product?.variants?.nodes[0];

  const productAnalytics: ShopifyAnalyticsProduct = {
    productGid: product.id,
    variantGid: selectedVariant.id,
    name: product.title,
    variantName: selectedVariant.title,
    brand: product.vendor,
    price: selectedVariant.price.amount,
  };
  const analytics = {
    pageType: AnalyticsPageType.product,
    resourceId: product.id,
    products: [productAnalytics],
    totalValue: parseFloat(selectedVariant.price.amount),
  };

  return defer({
    product,
    productPage: data.productPage,
    selectedVariant,
    storeDomain,
    analytics,
  });
}