Create a free Pack account and explore our Quick Start guide. Continue with the following guide or check out the README file in the Pack's Blueprint Theme Repository.
Requirements
- Node.js version 16.14.0 or newer
After cloning your project, begin by installing your node packages:
npm install
Environment Variables
To run your application locally, you can use Shopify's mock.shop API to simulate a Shopify storefront. You can set the PUBLIC_STORE_DOMAIN
environment variable to mock.shop
to use the mock.shop API.
SESSION_SECRET="foobar"
PUBLIC_STORE_DOMAIN="mock.shop"
PUBLIC_STOREFRONT_API_TOKEN="foobar"
You can automate pull in your Shopify environment variables directly from your Shopify Hydrogen storefront using the Hydrogen CLI. Run the command below and follow its prompts.
npx shopify hydrogen env pull
Alternatively, you can create a .env
file and manually copy these values from your Shopify Hydrogen storefront. You can find the variables by going to the Hydrogen storefront > Storefront Settings > Environments & Variables. These are the required variables needed:
SESSION_SECRET="XXX"
PUBLIC_STOREFRONT_API_TOKEN="XXX"
PUBLIC_STORE_DOMAIN="XXX"
PACK_PUBLIC_TOKEN="XXX"
PACK_SECRET_TOKEN="XXX"
PACK_STOREFRONT_ID="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}: LoaderFunctionArgs) {
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 Section Schema API.
Caching
Pack is leveraging the same Caching Strategy available with the Hydrogen framework. For an example of this, see app/lib/pack/create-pack-client.ts
NOTE: In the future, the lib/pack
library will be moved into it's own NPM package provided by Pack.
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(
query: string,
{variables, cache: strategy = CacheLong()}: QueryOptions = {},
) {
const queryHash = await hashQuery(query, variables);
const withCache = createWithCache>({
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(fetchOptions);
return withCache(queryHash, strategy, () => packFetch(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}: LoaderFunctionArgs) {
...
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,
});
}