Hydrogen is a React-based framework for building dynamic, Shopify-powered custom storefronts.

Last update: Jun 19, 2022

Hydrogen logo

πŸ“š Docs | πŸ—£ Discord | πŸ’¬ Discussions | πŸ“ Changelog

Hydrogen is a React-based framework for building dynamic, Shopify-powered custom storefronts.

Spin up a Hydrogen app in your browser with our playground or set up your local environment with the instructions below ⬇️

Getting Started

Requirements:

  • yarn or npm
  • Node.js version 14.0 or higher

Installation:

# Using `yarn`
yarn create hydrogen-app

# Using `npm`
npm init [email protected]

# Using `npx`
npx create-hydrogen-app

Running locally:

  1. Start a development server
# Using `yarn`
yarn install
yarn dev

# Using `npm`
npm i --legacy-peer-deps
npm run dev
  1. Visit the development environment running at http://localhost:3000.

Learn more about getting started with Hydrogen.

Contributing to Hydrogen

Read our contributing guide

Other handy links

🎁 Give us the gift of feedback.

πŸ“ Check out Hydrogen examples on Github.

🀩 Learn more about Hydrogen.

πŸ‘·β€β™€οΈ Add npm packages to your project:

GitHub

https://github.com/Shopify/hydrogen
Comments
  • 1. Implement better environment variables management for Hydrogen

    https://shopify.dev/beta/hydrogen/framework/secrets

    • If a dev wants to provide a secret, they have to use VITE_ and reference with import.meta.env
    • However, Vite warns that this explicitly makes the secret public (ends up in a public build)
    • This is not good, and we should provide another solution

    This issue is interesting, and perhaps there will be movement in this area: https://github.com/vitejs/vite/issues/3176#issuecomment-827773555

    Reviewed by jplhomer at 2021-09-22 20:25
  • 2. Introduce `hydrogen.config.js`

    Description

    Closes #1035 Closes #1023

    I'm trying to implement a hydrogen.config.js following what was mentioned in #948 (except Plugin API), but also considering other issues and use-cases we need to support. There are some opinions in this approach that I'm happy to discuss or change if anyone has suggestions.

    Still need to add a lot of docs here.

    Issues covered here:

    • [x] #948
    • [x] #1035
    • [x] #1023
    • [x] Duplicated and inconsistent config for API Routes + File Page Routes.
    • [x] Extra step of passing shopifyConfig to ShopifyProvider as props when it's already known.
    • [x] Extra step of passing routes to FileRoutes as props when it's already known.
    • [x] Try to find dirPrefix in routes automatically.
    • [x] ~~Dynamic hydrogenConfig to support async redirects and routes.~~
    • [x] Pass hydrogenConfig to renderHydrogen automatically.

    Not covered here (will be done in other PRs):

    • Move some Vite plugin options to Hydrogen config.
    • Move Logger and other in-app options to Hydrogen config.
    • Move client-entry options to Hydrogen config.
    • Design a Hydrogen Plugin system (some exploration in #910 and #1103)

    All of these examples can be mixed:

    export default {
      routes: import.meta.globEager('./src/routes/...'),
      shopify: {...},
    }
    
    export default {
      routes: {
        files: import.meta.globEager('./src/routes/...'),
        dirPrefix: '...',
        basePath: '...',
      },
      shopify:  async (url, request) => {
         if (url.pathname === '...') {
            await fetch(...);
            return {...}
         }
    
         return {...}
      }
    }
    

    The location of this file can be modified by passing configPath option to the Hydrogen plugin in vite.config.js. The default value is <root>/hydrogen.config.[jt]s. This config is now passed automatically to renderHydrogen, although it can still be overwritten in its second parameter just like before.

    ~~It is possible to have a function as the default export. This would be called before the rendering starts, thus blocking streaming. This is useful to fetch things like redirects (need to be done before suspense to send 3xx status). The custom property will be passed later to server components.~~ This has been removed for now since a plugin system might be a better fit for this kind of functionality.

    We have the shopify property (note: renamed from shopifyConfig since this is already a config file). This can be a function to fetch Storefront info asynchronously. This function runs within suspense boundaries (inside ShopifyProvider, which doesn't need props anymore).

    Note that the user is responsible for caching in-memory anything in these functions (using outer scope variables, etc).

    Apart from that, the routes property can now have extra configuration which was only available in the <FileRoutes> component before. This config now affects API routes as well as the mentioned component (unless overwritten with component props).

    The configs are always loaded using Vite so that import.meta.env syntax and .env files are available in this file.

    Additional context

    I'm not totally sure about allowing a function as the default export. Perhaps redirects could be implemented in a plugin system or as a core feature, and I'm not sure if anything else needs to be fetched asynchronously before rendering. Feedback is welcome particularly here.


    Before submitting the PR, please make sure you do the following:

    • [x] Read the Contributing Guidelines
    • [x] Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123)
    • [x] Update docs in this repository according to your change
    • [x] Run yarn changeset add if this PR cause a version bump based on Keep a Changelog and adheres to Semantic Versioning
    Reviewed by frandiox at 2022-04-11 13:52
  • 3. Session and Cookie abstraction for Hydrogen!

    Early implementation of session/cookie abstraction for Hydrogen. Additionally the cookie isn't signed at the moment. Resolves #982

    This is how it works:

    1. Configure sessions: (this assumes the config consolidation will land)
    import {CookieSessionStorage} from '@shopify/hydrogen';
    
    function App() {...}
    
    export default renderHydrogen(App, {
      routes,
      shopifyConfig,
      session: CookieSessionStorage('__session', {
          httpOnly: true,
          secure: true,
          sameSite: 'Strict',
          path:"/",
          expires: new Date(new Date.getTime() + (1000 * 60 * 60 * 24 * 30)), // 30 days
          domain: "shopify.dev",
          maxAge: 60*60*24*30,
      }),
    });
    
    1. Async API for API Routes:
    export async function api(request, {queryShop, session}) {
      if (request.method === 'POST') {
        await session.set("someKey", "someValue"); 
        return "session set";
      } else if (request.method === 'DELETE') {
        await session.destroy();
        return "session destroyed";
      }
      
      const {someKey} = await session.get();
      return "session: " + someKey;
    }
    
    1. Sync API for React Components
    import {useSession} from '@shopify/hydrogen';
    
    export default function MyComponent() {
      const [session, setSession, destroySession] = useSession();
      set('someKey', 'someValue');
      return <div>{session.someKey}</div>
    }
    
    1. How to write your own adapter? (see CookieSessionStorage for how it is implemented for cookies)
    export const CustomSessionStorage = function(name, options) {
      return function() {
        return {
          async get(request, id) {
            // pull the session from wherever you want, like redis, memcached, etc
          },
          async set(request, data) {
            // save the session data wherever you want
            // the only requirement is to return a cookie string which will be used to "Set-Cookie"
            // so although your session might be stored somewhere fancy, still return how you 
            // the session key is stored in the cookie
          },
          async destroy(request) {
            // remove the session
            // return a cleared out cookie value
          }
        }
      }
    }
    
    Reviewed by blittle at 2022-04-05 19:48
  • 4. Support `onClick` prop, `ref` on `BuyNowButton`

    I think starting off with at least doing something like

    -const handleBuyNow = useCallback(() => {
    +const handleBuyNow = useCallback((evt) => {
    +   if(props.onClick) {
    +    const clickShouldContinue = props.onClick(evt)
    +    // it's probably easier to just look for defaultPrevented rather than require devs to explicitly return false
    +    if(clickShouldContinue === false || evt.defaultPrevented) return
    +   }
        setLoading(true);
        createInstantCheckout({
          lines: [
            {
              quantity: quantity ?? 1,
              merchandiseId: variantId,
              attributes,
            },
          ],
        });
      }, [setLoading, createInstantCheckout, quantity, variantId, attributes]);
    

    In the BuyNow button would be a start.

    Also forwarding the ref as well, using forwardRef

    Thoughts?


    Discussed in https://github.com/Shopify/hydrogen/discussions/708

    Originally posted by joshbuckley182 February 18, 2022 It would be good if we can supply our own onClick prop to be executed before (potentially async and blocking) the default behavior. Another option would be to be able to create a ref to the button, so we can trigger a click event after performing some other task.

    Use case:

    I need to track click events on a BuyNowButton. What I’m finding though, is the page navigation happens before the event has been sent to the tracking server. This seems like something other users of Hydrogen might also want to do too. (Note: Right now I’m capturing the click in a parent element to trigger the tracking call).

    I see a few options here:

    1. Create our own TrackableBuyNowButton with a similar implementation to the Hydrogen one. Pro: Easy, Con: Need to ensure we stay in-sync with the Hydrogen one
    2. Have an optional onBeforeRedirect (or similar) prop on the BuyNowButton which would be executed and resolved before performing the redirect.
    3. Add ref forwarding to the BuyNowButton so we can trigger a click after the tracking call has completed.

    Another option would be to track the event using the beacon api, but that’s not compatible with all types of tracking.

    Reviewed by frehner at 2022-02-18 18:22
  • 5. [BUG] EISDIR: illegal operation on a directory, read on run app with fresh install app

    Describe the bug EISDIR: illegal operation on a directory, read on run app

    To Reproduce Install app using Yarn and run app then show error on local server with fresh app with default app configuration EISDIR: illegal operation on a directory, read

    Screenshots

    download

    • Hydrogen version : "0.6.4",
    • Node version : v14.18.0
    • Device details Windows 10
    Reviewed by aaronmitash at 2021-11-19 11:51
  • 6. Update React experimental version

    Description

    This PR upgrades to Hydrogen to the latest version of React experimental. This includes the latest changes to the Fizz streaming SSR API. It also includes server context, which has an impact on our pseudo server-only-context utilities.

    We need to add these Suspense boundaries to prevent this hydration error:

    Uncaught Error: This Suspense boundary received an update before it finished hydrating. This caused the boundary to switch to client rendering. The usual way to fix this is to wrap the original update in startTransition.
    

    I'm tracking this issue in #920 so we can resolve it later.


    Before submitting the PR, please make sure you do the following:

    • [ ] Run yarn changeset add to update the changelog, if needed
    • [ ] Read the Contributing Guidelines
    • [ ] Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123)
    • [ ] Update docs in this repository for your change, if needed
    Reviewed by frandiox at 2022-02-25 14:44
  • 7. feat: Add useLoadScript custom hook

    Also handle errors thrown from loadScript better

    Description

    Provides a useScriptLoader hook to cover the common use case for loadScript. [Should I rename it to useLoadScript?]

    Also, the previous implementation wasn't correctly handling the thrown error, so this custom hook handles that and surfaces it to the dev.

    Additional context

    Questions:

    • Currently I'm not exposing this custom hook to the end developer. Should I? Or should I keep it internal-only for now?
    • I didn't focus on improvements to the underlying loadScript function. However, if desired, I could try to add the ability for a basic version of incremental fallback reattempts, or allowing the dev to force a reattempt, etc. Thoughts?

    Is this even worth doing? I don't mind if we don't think this is valuable.

    If we do want to keep it, then I will finish things up such as adding tests, a readme (if necessary? If it's internal only does it need one?), etc.


    Before submitting the PR, please make sure you do the following:

    • [x] Add your change under the Unreleased heading in the package's CHANGELOG.md
    • [x] Read the Contributing Guidelines
    • [x] Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123)
    • [x] Update docs in this repository for your change, if needed
    Reviewed by frehner at 2022-01-18 20:54
  • 8. Deprecate generate-docs package and add script to copy docs for Shopify.dev

    Description

    This PR removes the generate-docs package and adds a simple script to copy the files over from the new docs directory. I included a light config so that @mcvinci can have some more control over the output, but given this is just an interim solution, we still want to keep this simple.

    Additional context

    More context and history was collected in this google doc.

    Also related to https://github.com/Shopify/hydrogen/pull/1079

    Before submitting the PR, please make sure you do the following:

    • [x] Read the Contributing Guidelines
    • [x] Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123)
    • [x] Update docs in this repository according to your change
    • [ ] Run yarn changeset add if this PR cause a version bump based on Keep a Changelog and adheres to Semantic Versioning
    Reviewed by cartogram at 2022-04-15 18:55
  • 9. Hydrogen should throw when both `noStore` and `maxAge` values are set

    Right now, it's possible for a developer to set this combination of values in both full-page and sub-request caches:

    response.cache({
      maxAge: 10,
      staleWhileRevalidate: 30,
      noStore: true
    });
    

    This is not a valid combination, as no-store prevents any caching whatsoever.

    Hydrogen should throw an error when this combination of values is set.

    Is this an API smell? Is there a better way to set noStore instead to prevent this confusion?

    Reviewed by jplhomer at 2022-01-06 14:53
  • 10. [BUG] Vite dev server hangs on initial page load

    Describe the bug Vite's dev server seems to hang when running a fresh project. It seems to happen on the first page load, where the initial SSR response is returned, the client loads, and then Vite detects new dependencies so it starts a reload.

    The page never fully seems to reload. Requests are hanging in the Network tab (see screenshot).

    We also sometimes see errors related to headers being sent during streaming & the standard "Can't use Switch outside Router" which is usually a red herring #64

    To Reproduce Steps to reproduce the behaviour:

    1. Create a new Hydrogen project, or run in the monorepo with the latest Vite dev server & starter template
    2. Start the dev server
    3. Observe the behavior

    Expected behaviour The dev server should start up and be snappy. Any dependency refreshes should happen instantly.

    Screenshots

    Screen Shot 2021-11-07 at 8 14 47 AM Screen Shot 2021-11-07 at 8 12 01 AM Screen Shot 2021-11-07 at 8 12 08 AM

    Additional context Add any other context about the problem here. eg.

    • Hydrogen version: 0.6.0
    • Node version: v16
    • Vite version: 2.6.13
    Reviewed by jplhomer at 2021-11-07 14:17
  • 11. Optionally prefetch `` on hover

    Next.js and Remix do this, and so can we.

    This will require some re-plumbing to generate a <link rel="preload" /> with the RSC URL and stick it in the head.

    This should be opt-in as a prop on <Link>.

    We could also build a slightly different behavior using IntersectionObserver, and start prefetching links when the <Link> scrolls into view.

    I don't know which is the best answer, and which defaults to use πŸ‘

    Reviewed by jplhomer at 2022-03-03 15:14
  • 12. [BUG] create-hydrogen: command not found

    When trying to start up a hydrogen template. I get a

    sh: line 1: create-hydrogen: command not found error message.

    It happens with npm, npx, and yarn. I tried on another computer, with node 18.3 installed, and it worked fine no problem. So i went back to my other PC, updated node to the latest version 18.4, and am still getting the same issue.

    Both PCs are running the same operating system and versions of node > 16.5.

    Why is this happening?

    Reviewed by EricPezzulo at 2022-06-24 15:23
  • 13. [BUG] `fetchSync` cached responses do not return a valid `response` object

    Describe the bug This is my fault.

    It was my intention to build fetchSync similarly to react-fetch (which is going away with the migration to async/await server components) so that you could grab the response object to inspect headers, status, etc:

    const response = fetchSync('https://shopify.dev');
    
    response.headers.get('some-header');
    
    const data = response.json();
    

    There are two problems:

    Bad return value

    I screwed up the return value here:

    https://github.com/Shopify/hydrogen/blob/76c50da27a02fb16ed734a29f99cf1eb9a6cb8e3/packages/hydrogen/src/foundation/fetchSync/server/fetchSync.ts#L43-L47

    It really ought to be:

    response.json = () => parseJSON(data);
    response.text = () => data;
    
    return response;
    

    I think we should fix this. We can add some warnings, and even an embedded response object which logs an error or something, to help backwards compat. But I would be surprised if this is being used very often, and we should fix it sooner rather than later to match our original intent of the API.

    See: https://github.com/facebook/react/blob/main/packages/react-fetch/src/ReactFetchNode.js#L16-L30

    Reviving cached responses

    When we fetchSync the first time, a valid response is returned from useQuery.

    However, for subsequent cached responses, the response object is a silly {size: 0, status: ''} (or something).

    This is because the response is being serialized to JSON in the cache, and we're not properly reviving the response instance when returning a cache hit.

    Instead, we should create a bespoke response JSON format that contains relevant info like status, array of headers, etc, and then "revive" the object using new Response when returning from fetchSync.

    Reviewed by jplhomer at 2022-06-24 12:14
  • 14. [BUG] Incompatible Node versions in Hydrogen and CLI

    We have engines set to Node 14 in Hydrogen itself, but mini-oxygen requires 16.7. This error is thrown when building with Node 14 (this is from Vercel build logs):

    error @shopify/[email protected]: The engine "node" is incompatible with this module. Expected version ">16.7.0". Got "14.19.0"
    

    mini-oxygen is a dependency of the new CLI and it's installed even if we are only targeting Node environments.

    Reviewed by frandiox at 2022-06-24 09:41
  • 15. Add back demo-store e2e tests

    Description

    We accidentally removed e2e tests on demo store. Couple updates to these test:

    • Fully type scripted
    • Check for not null instead of text value
    • null fix on PerformanceMetrics component

    Before submitting the PR, please make sure you do the following:

    • [ ] Read the Contributing Guidelines
    • [ ] Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123)
    • [ ] Update docs in this repository according to your change
    • [ ] Run yarn changeset add if this PR cause a version bump based on Keep a Changelog and adheres to Semantic Versioning
    Reviewed by wizardlyhel at 2022-06-22 21:38
  • 16. [BUG] demo-store-js isn't a valid template when running yarn create @shopify/hydrogen --template demo-store

    Describe the bug When following the documentation here I'm getting some bold text in the terminal that tells me that demo-store-js isn't a valid template when running yarn create @shopify/hydrogen --template demo-store

    To Reproduce In terminal run yarn create @shopify/hydrogen --template demo-store Add your relevant project name and you should get a read out like the below text

    Scaffolding Hydrogen app in /Users/jaylarson/git/project-name...
    ? demo-store-js isn't a valid template. Please choose from below: … 
    ❯ hydrogen
    

    Expected behaviour I expect to load the demo store template that includes the updated folder/component structure that can be viewed here: https://github.com/Shopify/hydrogen/tree/v1.x-2022-07/templates/demo-store/src

    Reviewed by tomorrowagency-jay at 2022-06-22 19:32
  • 17. Improve demo store's product description page performance with 3D models

    Having a 3D model in the products description page decreases performance

    As suggested by @wizardlyhel and @juanpprieto we could use a facade and delay loading until user interaction

    Reviewed by lordofthecactus at 2022-06-22 18:40
A frontend Framework for building B2B applications running in the browser on top of REST/GraphQL APIs, using ES6, React and Material Design
A frontend Framework for building B2B applications running in the browser on top of REST/GraphQL APIs, using ES6, React and Material Design

react-admin A frontend Framework for building data-driven applications running in the browser on top of REST/GraphQL APIs, using ES6, React and Materi

Jun 26, 2022
web3-react🧰 A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps

?? A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps

Jun 24, 2022
🧰 A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps

?? A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps

Jun 23, 2022
A web framework for building virtual reality experiences (VR Web)
A web framework for building virtual reality experiences (VR Web)

Virtual Reality Made Simple: A-Frame handles the 3D and WebVR boilerplate required to get running across platforms including mobile, desktop, Vive, and Rift

Mar 18, 2022
A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps

A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps

Nov 1, 2021
A data-driven, functional, and reactive framework for building Modern Web Apps in JavaScript.
A data-driven, functional, and reactive framework for building Modern Web Apps in JavaScript.

A data-driven, functional, and reactive framework for building Modern Web Apps in JavaScript. It leverages React, inspired by re-frame.

Mar 2, 2022
Create beautfiful custom applications using 100ms' React SDK.
Create beautfiful custom applications using 100ms' React SDK.

Create beautfiful custom applications using 100ms' React SDK.

Jun 17, 2022
πŸ›‘οΈ βš›οΈ A simple, scalable, and powerful architecture for building production ready React applications.

??️ βš›οΈ A simple, scalable, and powerful architecture for building production ready React applications.

Jun 21, 2022
A declarative, efficient, and flexible JavaScript library for building user interfaces.

React Β· React is a JavaScript library for building user interfaces. Declarative: React makes it painless to create interactive UIs. Design simple view

Jun 20, 2022
Datapod for React - a framework which extends create-react-app to enables you to quickly build data-driven sites
Datapod for React - a framework which extends create-react-app to enables you to quickly build data-driven sites

This is a framework which extends create-react-app to enables you to quickly build data-driven sites. This code is generated from the Datapod-for-React Core application.

Mar 19, 2022
The React Framework

Next.js Getting Started Visit https://nextjs.org/learn to get started with Next.js. Documentation Visit https://nextjs.org/docs to view the full docum

Jun 19, 2022
The Full-stack Framework for React and other in Deno.

The Full-stack Framework for React and other in Deno.

Jun 17, 2022
⚑️The Fullstack React Framework β€” built on Next.js
⚑️The Fullstack React Framework β€” built on Next.js

⚑️The Fullstack React Framework β€” built on Next.js

Jun 16, 2022
A most advanced ssr framework support React/Vue2/Vue3 on Earth that implemented serverless-side render specification.
A most advanced ssr framework support React/Vue2/Vue3 on Earth that implemented serverless-side render specification.

A most advanced ssr framework support React/Vue2/Vue3 on Earth that implemented serverless-side render specification.

Jun 18, 2022
⚑️The Fullstack React Framework β€” built on Next.js β€” Inspired by Ruby on Rails
⚑️The Fullstack React Framework β€” built on Next.js β€” Inspired by Ruby on Rails

⚑️The Fullstack React Framework β€” built on Next.js β€” Inspired by Ruby on Rails

Oct 12, 2021
🌟 DataFormsJS 🌟 A minimal JavaScript Framework, standalone React and Web Components, and JSX Compiler for rapid development of high quality websites and single page applications.
🌟 DataFormsJS 🌟 A minimal JavaScript Framework, standalone React and Web Components, and JSX Compiler for rapid development of high quality websites and single page applications.

?? DataFormsJS ?? A minimal JavaScript Framework, standalone React and Web Components, and JSX Compiler for rapid development of high quality websites and single page applications.

Jun 13, 2022
Web App using react framework

waldo.vision This is the website for waldo-anticheat :D Libraries used: React React-router React-router-hash-link React-helmet TODO: improve this list

Nov 12, 2021
Declarative data-fetching and caching framework for REST APIs with React
Declarative data-fetching and caching framework for REST APIs with React

Declarative data-fetching and caching framework for REST APIs with React

Jun 12, 2022
A utility-first CSS-in-JS framework built for React πŸ’…πŸ‘©β€πŸŽ€βš‘οΈ
A utility-first CSS-in-JS framework built for React πŸ’…πŸ‘©β€πŸŽ€βš‘οΈ

A utility-first CSS-in-JS framework built for React. npm install @xstyled/styled-components styled-components Docs See the documentation at xstyled.de

Jun 21, 2022