Skip to content

Commit

Permalink
Create createHydrogenContext that combine createStorefrontClient,…
Browse files Browse the repository at this point in the history
…`createCustomerAccountClient` and `createCartHandler` (#2333)

* Create ShopifyEnv and use it for all the env.d.ts

* add createStorefrontClient method and calls createStorefrontClient

* add customerAccount and cart to createShopifyHandler

* update types to determined the cart type correctly based on options

* use shopify handler in skeleton & custom cart method example

* refactor for client options to be in its own key

* move all non client specific options into top level

* renamed a bunch of options to get rid of duplicate prefix

* update type using TUseCustomerAccountAPI

* move useCustomerAccountAPI to be nested under customerAccount option

* change key to useStorefrontAPI

* fix cart type

* move getStorefrontHeaders to @Shopify/hydrogen

* add changeset

* remove extra types

* use createShopifyHandler in all of the server.ts files

* fix test

* change test

* update context type using ShopifyContext export

* renamed all shopify prefix to hydrogen prefix

* ensure createHydrogenContext is compatible with Request and CrossRuntimeRequest

* update changelogs

* fix i18n replacer with the new type

* undo the move of getStorefrontHeaders and just have the method locally within createHydrogenContext

* return env, waitUntil, session from createHydrogenContext

* change useStorefrontAPI to useLegacy

* always require session and always return customerAccount object

* add docs type

* add docs for createHydrogenContext

* update examples

* fix type

* move create context to a seperate file and export type from there for AppLoadContext

* fix header according to comment

* move type definition from context to env.d.ts

* modify i18n replacer method to modify the new context file

* Update packages/hydrogen/src/createHydrogenContext.ts

Co-authored-by: Bret Little <bret.little@shopify.com>

* Update packages/hydrogen/src/createHydrogenContext.doc.ts

Co-authored-by: Bret Little <bret.little@shopify.com>

* Update packages/cli/assets/i18n/mock-i18n-types.ts

Co-authored-by: Bret Little <bret.little@shopify.com>

* update changelog

* update context path in i18n replacer to use joinPath

* simplify mock-i18n-type replacement

* add reasoning for HydrogenContextOverloads

* remove duplicate env.session check

* i18n strategy update

* update i18n test

---------

Co-authored-by: Bret Little <bret.little@shopify.com>
  • Loading branch information
michenly and blittle authored Aug 2, 2024
1 parent 6e5d8ea commit bf4e3d3
Show file tree
Hide file tree
Showing 56 changed files with 2,749 additions and 1,758 deletions.
112 changes: 112 additions & 0 deletions .changeset/healthy-rats-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
'skeleton': patch
---

1. Create a app/lib/context file and use `createHydrogenContext` in it.

```.ts
// in app/lib/context

import {createHydrogenContext} from '@shopify/hydrogen';

export async function createAppLoadContext(
request: Request,
env: Env,
executionContext: ExecutionContext,
) {
const hydrogenContext = createHydrogenContext({
env,
request,
cache,
waitUntil,
session,
i18n: {language: 'EN', country: 'US'},
cart: {
queryFragment: CART_QUERY_FRAGMENT,
},
// ensure to overwrite any options that is not using the default values from your server.ts
});

return {
...hydrogenContext,
// declare additional Remix loader context
};
}

```

2. Use `createAppLoadContext` method in server.ts Ensure to overwrite any options that is not using the default values in `createHydrogenContext`.

```diff
// in server.ts

- import {
- createCartHandler,
- createStorefrontClient,
- createCustomerAccountClient,
- } from '@shopify/hydrogen';
+ import {createAppLoadContext} from '~/lib/context';

export default {
async fetch(
request: Request,
env: Env,
executionContext: ExecutionContext,
): Promise<Response> {

- const {storefront} = createStorefrontClient(
- ...
- );

- const customerAccount = createCustomerAccountClient(
- ...
- );

- const cart = createCartHandler(
- ...
- );

+ const appLoadContext = await createAppLoadContext(
+ request,
+ env,
+ executionContext,
+ );

/**
* Create a Remix request handler and pass
* Hydrogen's Storefront client to the loader context.
*/
const handleRequest = createRequestHandler({
build: remixBuild,
mode: process.env.NODE_ENV,
- getLoadContext: (): AppLoadContext => ({
- session,
- storefront,
- customerAccount,
- cart,
- env,
- waitUntil,
- }),
+ getLoadContext: () => appLoadContext,
});
}
```

3. Use infer type for AppLoadContext in env.d.ts

```diff
// in env.d.ts

+ import type {createAppLoadContext} from '~/lib/context';

+ interface AppLoadContext extends Awaited<ReturnType<typeof createAppLoadContext>> {
- interface AppLoadContext {
- env: Env;
- cart: HydrogenCart;
- storefront: Storefront;
- customerAccount: CustomerAccount;
- session: AppSession;
- waitUntil: ExecutionContext['waitUntil'];
}

```
5 changes: 5 additions & 0 deletions .changeset/light-boxes-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Create `createHydrogenContext` that combined `createStorefrontClient`, `createCustomerAccountClient` and `createCartHandler`.
5 changes: 5 additions & 0 deletions .changeset/quiet-falcons-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/create-hydrogen': patch
---

starter template updated
24 changes: 24 additions & 0 deletions .changeset/rich-falcons-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
'skeleton': patch
---

Use type `HydrogenEnv` for all the env.d.ts

```diff
// in env.d.ts

+ import type {HydrogenEnv} from '@shopify/hydrogen';

+ interface Env extends HydrogenEnv {}
- interface Env {
- SESSION_SECRET: string;
- PUBLIC_STOREFRONT_API_TOKEN: string;
- PRIVATE_STOREFRONT_API_TOKEN: string;
- PUBLIC_STORE_DOMAIN: string;
- PUBLIC_STOREFRONT_ID: string;
- PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID: string;
- PUBLIC_CUSTOMER_ACCOUNT_API_URL: string;
- PUBLIC_CHECKOUT_DOMAIN: string;
- }

```
40 changes: 9 additions & 31 deletions docs/shopify-dev/analytics-setup/ts/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
import '@total-typescript/ts-reset';

import type {
Storefront,
CustomerAccount,
HydrogenCart,
HydrogenContext,
HydrogenSessionData,
HydrogenEnv,
} from '@shopify/hydrogen';
import type {AppSession} from '~/lib/session';

Expand All @@ -19,38 +18,17 @@ declare global {
*/
const process: {env: {NODE_ENV: 'production' | 'development'}};

/**
* Declare expected Env parameter in fetch handler.
*/
interface Env {
SESSION_SECRET: string;
PUBLIC_STOREFRONT_API_TOKEN: string;
PRIVATE_STOREFRONT_API_TOKEN: string;
PUBLIC_STORE_DOMAIN: string;
PUBLIC_STOREFRONT_ID: string;
PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID: string;
PUBLIC_CUSTOMER_ACCOUNT_API_URL: string;
// [START envtype]
PUBLIC_CHECKOUT_DOMAIN: string;
// [END envtype]
interface Env extends HydrogenEnv {
// declare additional Env parameter use in the fetch handler and Remix loader context here
}
}

declare module '@shopify/remix-oxygen' {
/**
* Declare local additions to the Remix loader context.
*/
interface AppLoadContext {
env: Env;
cart: HydrogenCart;
storefront: Storefront;
customerAccount: CustomerAccount;
session: AppSession;
waitUntil: ExecutionContext['waitUntil'];
interface AppLoadContext extends HydrogenContext<AppSession> {
// declare additional Remix loader context here
}

/**
* Declare local additions to the Remix session data.
*/
interface SessionData extends HydrogenSessionData {}
interface SessionData extends HydrogenSessionData {
// declare local additions to the Remix session data here
}
}
50 changes: 50 additions & 0 deletions examples/b2b/app/lib/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {createHydrogenContext} from '@shopify/hydrogen';
import {AppSession} from '~/lib/session';
import {CART_QUERY_FRAGMENT} from '~/lib/fragments';

/**
* The context implementation is separate from server.ts
* so that type can be extracted for AppLoadContext
* */
export async function createAppLoadContext(
request: Request,
env: Env,
executionContext: ExecutionContext,
) {
/**
* Open a cache instance in the worker and a custom session instance.
*/
if (!env?.SESSION_SECRET) {
throw new Error('SESSION_SECRET environment variable is not set');
}

const waitUntil = executionContext.waitUntil.bind(executionContext);
const [cache, session] = await Promise.all([
caches.open('hydrogen'),
AppSession.init(request, [env.SESSION_SECRET]),
]);

const hydrogenContext = createHydrogenContext({
env,
request,
cache,
waitUntil,
session,
i18n: {language: 'EN', country: 'US'},
/***********************************************/
/********** EXAMPLE UPDATE STARTS ************/
customerAccount: {
unstableB2b: true,
},
/********** EXAMPLE UPDATE END ************/
/***********************************************/
cart: {
queryFragment: CART_QUERY_FRAGMENT,
},
});

return {
...hydrogenContext,
// declare additional Remix loader context
};
}
54 changes: 0 additions & 54 deletions examples/b2b/app/remix.env.d.ts

This file was deleted.

Loading

0 comments on commit bf4e3d3

Please sign in to comment.