Shopify / buy-button-js

BuyButton.js is a highly customizable UI library for adding ecommerce functionality to any website.
http://shopify.github.io/buy-button-js/
MIT License
244 stars 114 forks source link

buy-button-js needs to be re-written to play nice with react #760

Open EliotSlevin opened 3 years ago

EliotSlevin commented 3 years ago

When the buy button was introduced in 2016, it was such a cool idea. Plug and play, practically turn any website into a store, sell your stuff anywhere that html can run. Get all sorts of nice UI, and experience out of the box for free - it's like embedding a youtube video, but instead it's a store, and you get all of Shopify's great backend tooling to actually run your business.

However, over the last 5 years a lot has changed - namely the rise of react, and other client-side rendering libs. Buy button just doesn't play nice with this libraries at all, it's written in a much more traditional JQuery library style. It doesn't render isomorphically - it doesn't play nice with SSR, making it a pain to implement with Gatsby or Next.js, any modern react website dev.

Now obviously, there's the JS Buy SDK, which works fine with react, there's even nice code samples. But implementing the SDK yourself, has a lot of challenges, building your own cart, worrying about state, all the UI styling - it's a lot of work.

In the blog post where buy-button was introduced, the goal of it was described as, "The goal of BuyButton.js is to handle the more challenging aspects of integrating ecommerce on the client-side, such as state management, event and data binding, and coordination between components." Going the JS Buy SDK route you have to worry about all this stuff.

The buy-button is so cool cause you can just slap it in, and spend your time worrying about all the other issues when you're selling stuff online. It's still a great value prop, and a great library - it just needs to be brought 5 years up to speed, and made to play nicely with react.

resistorsoftware commented 3 years ago

If you want this library to work with React, feel free to do the legwork and bring it to life as React code. No one is stopping you.

suntudo commented 3 years ago

I'm running into this same issue with BuyButton.js with Nuxt on the Vue side. I'd really like to be able to just use buybutton.js and not have to build out all the logic and cart myself with JS Buy SDK. Nor do I have the experience or time to create a PR to update the library for this use case. It would be great if Shopify could provide more resources for this library.

resistorsoftware commented 3 years ago

That is the problem when there are so many approaches to do the same thing. So many wheels have been re-invented to solve the same problem, it is hard to imagine servicing them all. I doubt Shopify cares a whit what people use, instead, they laid down the groundwork by providing the SDK in the first place. So if you want your Nuxt and Vue, best be finding some buddies, and getting at 'er. Shopify does not even keep their own libs in perfect shape, never mind what is on other people's wish lists.

pastisprologue commented 3 years ago

I am using next.js and have gotten this to work, at least in a dev setup (time will tell if I'm doing the dynamic stuff correctly):

import { useEffect } from 'react';
import ShopifyBuy from '@shopify/buy-button-js';

const shopifyClient = ShopifyBuy.buildClient({
    domain: '<your domain>',
    storefrontAccessToken: '<your token>'
});

const ui = ShopifyBuy.UI.init(shopifyClient);

export default function BuyNow({ id }) {
    useEffect(() => {
        ui.createComponent('product', {
            id,
            node: document.getElementById(`buy-now-${id}`),
        });
    });

    return <div id={`buy-now-${id}`} />;
}

Then where I use it I have to use next/dynamic, like so:

import dynamic from 'next/dynamic';

const DynamicBuyNow = dynamic(() => import('src/components/shopify/BuyNow'), {
    ssr: false
});

export const Products = (props) => {
    return (
        <>
            {props.ids.map((id) => (
                <div className="mb-8">
                    <DynamicBuyNow key={id} id={id} />
                </div>
            ))}
        </>
    );
};

I think if you're not using Next you can just use the BuyNow component directly

EliotSlevin commented 3 years ago

I actually just ended up finding a gatsby shopify starter and going from there. I tried your approach @pastisprologue (which looks great) but turns out I wasn't smart enough to get it working with gatsby, in particular the server side rendering.

seano424 commented 3 years ago

@pastisprologue How did you even import the package? If I try to download the package it gives me all kinds of errors and warnings of it being deprecated.

pastisprologue commented 3 years ago

@seano424 I'm not sure what you're asking exactly. I added it using npm like:

npm i @shopify/buy-button-js

In my package.json, the version is listed as "^2.1.7". In my package-lock.json, the version actually installed is "2.1.7".

During installation, I did get some deprecation warnings, as well as build warnings (C++, related to libsass), but the lib otherwise installed successfully without error. I am running node version 14.17.1 and npm version 6.14.13 if you think that makes any difference.

Then I imported it as shown on the second line of my first snippet:

import ShopifyBuy from '@shopify/buy-button-js';

I also get linting messages from my editor because Shopify doesn't provide a type declaration file for the library, but that is pretty common in my experience using JS libs in a TS project-- the lib still works regardless.

What versions are you running? What error(s) are you seeing?

RyanMoreau commented 2 years ago

Honestly, just use Loadable Components. Gatsby doesn't support dynamic the same way Next does and I just had this issue.

I set my BuyButton component up similarly to how @pastisprologue did in the first code snippet. Then to import the component:

import loadable from '@loadable/component' const BuyButton = loadable(() => import('../../elements/shopify/buyButton'))

After that, it's available as a typical jsx element <BuyButton />.