DEV Community

Eka
Eka

Posted on

Get asynchronous data in JungleJS, the new Svelte JAMstack library

JungleJS is a new static site generator that uses Svelte and GraphQL. It also has a handy routing feature akin to NextJS and Sapper, where you can have src/routes/[slug].svelte and query for data based on the slug. I made this JungleJS starter site with Storybook and Tailwind CSS so you can get started using it more quickly.

GitHub logo ekafyi / junglejs-storybook-tailwind

Starter site for JungleJS + Storybook + TailwindCSS

At the time of writing, the official docs and template describe two data sources: JSON (whether imported and parsed from local files or written in the JS code) and Markdown files. All well and good if you only need those data sources. But many websites today also get their data from external sources by sending a request to an external API, which is asynchronous in nature.

This is not possible with the current template, so I asked on their Github repo: Is it possible to fetch data asynchronously in JungleJS?

Is it possible to pass data to dataSources asynchronously? #10

Trying JungleJS for the first time now, good work!

I wonder if it's possible to query data from an external source (eg. fetch from external API) then pass it to dataSources items?

The problem is, it has to be done asynchronously. Is it possible at all to return exports in jungle.config.js asynchronously? Or is there any other way to achieve this?

Thanks!

They responded that they aimed to have this functionality as a user-facing plugin in the future, and kindly gave the code to run JungleJS asynchronously in the meantime.

To save you all the copy-pasting and server-restarting 😉, I added a simple example and published it to my starter site under the branch with-async-data.

If you use the Netlify Deploy button or the Github template feature, you’ll get the master branch by default. You can run git checkout with-async-data to move to the async branch.

How I made this example

First I modified app.js to run asynchronously as advised by @ConProgramming, the creator, in the issue’s answer above. I did the same with build.js. (Not in the original answer but this is also necessary.)

Next I modified jungle.config.js, which previously exported an object, into an asynchronous function as per the answer. Then I added a simple fetch example with the following steps:

  • Run npm i -D node-fetch (install and save the node-fetch package as dev dependency). You can use eg. axios instead of fetch if you want.
  • Fetch data from the free OpenLibrary API. You can replace it with any API you want; simply change the SAMPLE_FETCH_URL value.
    • Don’t forget to add the necessary credentials or headers in your request as required by the API.
  • Pass the returned data to the dataSources in the same format as the existing data source objects example.
// jungle.config.js

// ... other stuff

const fetch = require("node-fetch");

const SAMPLE_FETCH_URL = "https://some-external-api/endpoint";

module.exports = async () => {
  const myResponse = await fetch(SAMPLE_FETCH_URL);
  const myArray = Object.values(await myResponse.json());

  return {
    // .. clientInputOptions etc
    dataSources: [
      {
        format: "json",
        name: "book", // data name as a singleton noun
        items: myArray, // our data as an array
      },
      // ... other data sources
    ],
  };
};

Then the data is processed into the GraphQL layer and available to query from our frontend. As I use the name book in jungle.config.js dataSources, I use the plural format books to get a list of books via GraphQL query.

<script>
  const QUERY = `
    query {
      books {
        authors {
          name
        }
        cover {
          medium
        }
        title
        url
      }
    }
  `;
  const QUERYRES = {};
  console.log(QUERYRES.books);
</script>

The data is available as QUERYRES.books and can be used as we normally would in any Svelte application. This is the simplified version:

{#each QUERYRES.books as {authors, cover, subtitle, title, url}}
  <article>
    <img src={cover.medium} alt="" width="180" height="270"/>
    <h3>{`${title}${subtitle ? `: ${subtitle}` : ''}`}</h3>
    <div>{joinAuthorNames(authors)}</div>
  </article>
{/each}

To build for production, run npm run build. The build is in the jungle/build directory, ready to upload/drop to any static site hosting you want. I use Netlify, where I can drag and drop the folder and have my Jungle site live in a few seconds. ✨

My impressions of JungleJS

🙂 Like

I love Jungle’s approach to SSG. Powered by Svelte, it creates a lean, no-frills, modern JAMstack site with no redundant hydration or run-time tasks. It’s idea for websites where we don’t need complex client-side features and would like more control to add progressive enhancements as we see fit.

  • Effortlessly good SEO: You can “View Page Source” on the page and see our books data rendered as regular HTML, ready for search engines to crawl.
  • Effortlessly good Lighthouse score: As shown below, it literally loads the HTML, 2 CSS files, 1 bundled JS file, and the images. That’s it.

screenshot of demo site with DevTools Network tab open showing what assets are loaded

This is simply a quick demo. For production, the images should ideally be lazy-loaded, the 2 CSS files combined and/or lazy-loaded, and the JS file deferred for better performance.

🙁 Dislike

Not reallly a “dislike” per se, but given this library is very new, the development experience is still not ideal. For starter there is no live reload, so you have to restart the server to see any change. Also, using GraphQL beyond simple data like in this example may be tricky.

Gatsby, for example, has an integrated GraphQL viewer where we can check our query. They also provide a way to anticipate missing data that would otherwise break the GraphQL query (for example, querying for the optional subtitle field would break if none of the books have a subtitle).

Until then, feel free to try the starter and hope JungleJS grows into a more mature library. 😃🤞


Bonus Track

Top comments (0)