shopifysveltejsonpsveltekit

How can I do JSONP requests from Sveltekit?


We are running a Shopify store, and have come to a point where we need more flexibility content wise. My solution to this is to have content delivered via a custom CMS to a subdomain. One issue I have is getting cart content from the primary domain on Shopify to the Sveltekit solution on the subdomain (I need to show the cart items count in the header, and also a list of the items in the cart in a sidebar).

Unfortunately just fetching the cart.json gives a CORS error. I have found a solution using JSONP:

function getCartData(data){
  /* do something with the data. In this example we are just loggin it */
  console.log(data)
}

var script = document.createElement('script');
script.src = 'https://jasons-experiments.myshopify.com/cart.json?callback=getCartData'
document.getElementsByTagName('head')[0].appendChild(script);

from this site: https://freakdesign.com.au/blogs/news/get-cart-contents-via-jsonp.

I am really stumped on how to do something like this from Sveltekit. Is this even possible?


Solution

  • Finally figured it out. In a blogpost from Logrocket, they try to explain the workings of JSONP. Probably succeeds as well, perhaps I just need to read it again. Anyway, I exctracted the function in their example and created a component in Svelte called getCartData.js:

    let jsonpID = 0;
    
    function jsonp(timeout = 7500) {
      const url = 'https://shopdomain.net/cart.json';
      const head = document.querySelector('head');
      jsonpID += 1;
    
      return new Promise((resolve, reject) => {
        let script = document.createElement('script');
        const callbackName = `jsonpCallback${jsonpID}`;
    
        script.src = encodeURI(`${url}?callback=${callbackName}`);
        script.async = true;
    
        const timeoutId = window.setTimeout(() => {
          cleanUp();
    
          return reject(new Error('Timeout'));
        }, timeout);
    
        window[callbackName] = data => {
          cleanUp();
    
          return resolve(data);
        };
    
        script.addEventListener('error', error => {
          cleanUp();
    
          return reject(error);
        });
    
        function cleanUp() {
          window[callbackName] = undefined;
          head.removeChild(script);
          window.clearTimeout(timeoutId);
          script = null;
        }
    
    
        head.appendChild(script);
      });
    }
    
    export default jsonp
    

    And in my header component, I just awaited the result:

    import jsonp from '$lib/helpers/getCartData';
    import { onMount } from 'svelte';
    
    let cartData = jsonp();
    
    onMount(async () => {
        console.log(await cartData);
    })