Search code examples
svelteastrojs

Dynamically Load Astro Page From Glob


I have a site with over 15,000 static pages. I am able to load them individually using a url no problem. I would like to implement a "Random" page, where I would pick a random identifier from a pre-existing search index, and then use that to load one of the pages. My rough implementation in Svelte is:

<script>
  import { onMount } from "svelte";
  import Layout from '../layouts/sign/single.astro'
  let randomNumber = 0;
  let randomFile = null;

  let endpoint =
    "SEARCH_INDEX_QUERY_THAT_RETURNS_A_COUNT";
  onMount(async function () {
    const response = await fetch(endpoint);
    const data = await response.text();

    const totalCount = parseInt(data);

    randomNumber = Math.floor(Math.random() * totalCount);

    const files = import.meta.glob("../pages/sign/*.md");

    let counter = 0;
    for (const path in files) {
      if (counter == randomNumber) {
        randomFile = await files[path]();
        console.log(randomFile);
      }
      counter++;
    }
  });
</script>

{#if randomFile}
  <randomFile/>
{:else}
<p>Loading</p>
{/if} 

The code is correctly returning a random page when being run, however, I am unsure how and if I can actually display the page. Each page does have a layout defined. I am calling this svelte component using an page that looks like:

---
import Random from "../components/Random.svelte"

---
<Random client:load/>

I have a few other complicated scenarios in mind that may also use this approach. The general idea is that all of the pages are stored statically - but these static pages could be pulled up dynamically at run time using a search query, or in this case a random search.


Solution

  • you did the hard part which is globbing with import.meta.glob and not with Astro.glob which is eager by default, so you prevented the content conversion of all files in each request. Here the solution for how to render the imported selected file

    solution

    It is possible to keep all of this code within a .astro file, and there it is possible to render your page as follows

    {randomFile &&
    <Layout>
            <randomFile.Content />
    </Layout>
    }
    

    optimization

    further more, and given the high amount of pages you have, you do not need to be counting the pages till you reach the target you can directly index it from the returned object keys as follows (I avoided variable name with keyword 'path' not to confuse with the module of the same name)

    const Post_path = Object.keys(posts)[randomNumber]