#Dynamic import issue

4 messages · Page 1 of 1 (latest)

dapper glade
#

I have a posts section in my site, with an index page with posts ordered by date, and a section with a more structured page structure containing information on a D&D setting. I want to be able to put a post both in the content collection used by the posts (so it shows up in the post list), and in the page structure (eg at specific path foo/setting/places/bar), without copypasting the files.
My initial idea was adding a 'ref' field to the post's frontmatter with the path to the static page written in it, which if set would make the renderer ignore the post's content and instead load the content of the page at foo/setting/places/bar via glob to use it, but I get

Invalid glob import syntax: Could only use literals

when doing so:

export async function renderTypedPost<T extends DefaultFrontmatter>(post: CollectionEntry<keyof AnyEntryMap>) {
    const { Content, remarkPluginFrontmatter } = await render(post);
    
    const data = remarkPluginFrontmatter as T;

    if (data.ref) {
        const refPath = `@/pages/${data.ref}.*`.replace("//", "/");

        const [refFile] = Object.values(import.meta.glob(refPath, { eager: true }));
        console.log(refFile);
    }
    
    return { post, data, Content };
}

any other way to accomplish this?

wide scarabBOT
#

Hi @dapper glade. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

The issue you're encountering is related to the use of import.meta.glob() in Astro. As mentioned in the Astro documentation, import.meta.glob() only supports static string literals and does not allow dynamic variables or string interpolation.

To accomplish what you're trying to do, you have a few options:

  1. Use a larger glob pattern and filter the results:

Instead of trying to use a dynamic path, you can import a larger set of files that includes all the files you need, then filter them based on your criteria. Here's an example from the Astro documentation:

const posts = Object.values(import.meta.glob("../pages/blog/*.md", { eager: true }));
const myFeaturedPost = posts.find(post => post.file.includes(pathToMyFeaturedPost));

In your case, you could do something like this:

if (data.ref) {
    const allPages = import.meta.glob('@/pages/**/*.*', { eager: true });
    const refFile = Object.values(allPages).find(file => file.file.includes(data.ref));
    console.log(refFile);
}
  1. Use Content Collections:

If you're not already using them, Content Collections provide a more powerful way to manage and query your content. You could create a collection that includes both your posts and your D&D setting pages, and use the collection API to query and render the content.

  1. Use getCollection():
#

If you're already using Content Collections, you can use the getCollection() function to fetch your content instead of import.meta.glob(). This provides a more flexible way to query your content. Here's an example from the Astro documentation:

import { getCollection } from 'astro:content';

const allPosts = await getCollection('blog');

You could then filter this collection based on your ref field or any other criteria.

These approaches should allow you to accomplish your goal of having posts appear in both the post list and in a specific page structure without duplicating files. The exact implementation will depend on how you've structured your content and collections.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: