Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useAsyncData example for static generation #81

Closed
ckald opened this issue Oct 20, 2022 · 22 comments
Closed

useAsyncData example for static generation #81

ckald opened this issue Oct 20, 2022 · 22 comments
Labels
question Further information is requested

Comments

@ckald
Copy link

ckald commented Oct 20, 2022

How one would use directus API to generate a completely static site using Nuxt3? Simple html/js files that do not trigger backend requests.

I'm trying to implement the following:

export const asyncDirectusItems = async (key, config, transform) => {
  const { getItems } = useDirectusItems();
  const { data } = await useAsyncData(key, async () => await getItems(config), {transform});
  return data;
};

export const asyncDirectusItemById = async (collection, id, transform) => {
  const { getItemById } = useDirectusItems();
  const key = `${collection}#${id}`;
  const { data } = await useAsyncData(key, async () => await getItemById({ collection, id }), {transform});
  return data;
};

But recent Nuxt 3 RC's (9 and 12) either fail to generate directly accessible SSR pages or mix their markup with the front page. Also I'm having trouble to prevent Directus API calls (which are unnecessary for a completely static website).

<script setup>
const categories = await asyncDirectusItems('blog_categories', {
  collection: "Blog",
  params: {
    fields: "category",
    groupBy: "category"
  }
});

const posts = await asyncDirectusItems('published_blogs', {
  collection: "Blog",
  params: {
    filter: {
      status: "published"
    }
  }
});
</script>
```html
@ckald ckald added the question Further information is requested label Oct 20, 2022
@mklueh
Copy link
Contributor

mklueh commented Jan 1, 2023

Hello, have you found a solution yet?

@Intevel
Copy link
Owner

Intevel commented Jan 1, 2023

I think if you just use your composables in set ssr to false in Nuxt Configuration it will be fine. SSR false does not prerender all routes

@mklueh
Copy link
Contributor

mklueh commented Jan 2, 2023

@Intevel not sure if I understand it correctly, but would just using composables really change anything?

I currently have ssr: false and run nuxt generate and I've tried it with this composable with no effect:

export default async function () {
  const {getItems} = useDirectusItems();

  interface Article {
    id?: string | number;
    title: string;
    content: string;
    status: string;
  }

  const posts = await getItems<Article>({
    collection: "blog"
  });

  return {
    posts
  }
}

@Intevel
Copy link
Owner

Intevel commented Jan 2, 2023

Do you want the content from the API to be in the static HTML or do you want the static page to fetch the data on load?

@mklueh
Copy link
Contributor

mklueh commented Jan 2, 2023

@Intevel I want the content to be in the static HTML

@Intevel
Copy link
Owner

Intevel commented Jan 2, 2023

Then you remove the ssr property, and just call nuxi generate. This will pretender the routes

@mklueh
Copy link
Contributor

mklueh commented Jan 2, 2023

@Intevel I don't think there is a third state of the ssr property. It's true by default https://nuxt.com/docs/api/configuration/nuxt-config/#ssr

I've tried it with no success and I still see requests in the browser to directus

@Intevel
Copy link
Owner

Intevel commented Jan 2, 2023

Can you show me you're nuxi generate output?

@mklueh
Copy link
Contributor

mklueh commented Jan 2, 2023

 WARN  Using experimental payload extraction for full-static output. You can opt-out by setting experimental.payloadExtraction to false.
 WARN  Generated an empty chunk: "index"
ℹ Client built in 21415ms
ℹ Building server...
 WARN  Generated an empty chunk: "index"
✔ Server built in 15164ms
✔ Generated public .output/public
ℹ Initializing prerenderer
ℹ Prerendering 10 initial routes with crawler
  ├─ /async-data (51ms) 
  ├─ /blog (6ms)
  ├─ /fetch (5ms)
  ├─ / (5ms) 
  ├─ /lazy-async-data (6ms)
  ├─ /lazy-fetch (7ms)
  ├─ /api/_content/cache.1672699140405.json (24ms) 
  ├─ /index.html (5ms)
  ├─ /200.html (5ms) 
  ├─ /404.html (5ms)
close hook called

@Intevel
Copy link
Owner

Intevel commented Jan 2, 2023

Okay @mklueh I will try something tomorrow and let you know then.

@mklueh
Copy link
Contributor

mklueh commented Jan 2, 2023

@Intevel thanks

I'd guess one could use something like this

const posts = await useAsyncData('posts', () => {
  return getItems<Article>({
    collection: "blog"
  })
})

But so far I had no success

Edit: I've found this package https://www.npmjs.com/package/nuxt-full-static indicating that maybe it's not working out of the box, but on the other hand how is it working with normal REST calls to the backend then?

@Intevel
Copy link
Owner

Intevel commented Jan 3, 2023

Yes but nuxt-full-static was just a PoC, before Nuxt 3 has static support. I guess.

@mklueh
Copy link
Contributor

mklueh commented Jan 3, 2023

@Intevel yes. But I don't understand it. What is the difference between rendering a static site from a REST API directly vs rendering using the Directus SDK that uses a REST API?

@Intevel
Copy link
Owner

Intevel commented Jan 3, 2023

The way you explain it there is no difference, but you want the content to be directly in the code.

@mklueh
Copy link
Contributor

mklueh commented Jan 3, 2023

@Intevel Yes, and I think https:/nuxt/content works also that way if I'm not mistaken.

I've seen this docs now https://nitro.unjs.io/config/#prerender and maybe the issue is related, because my /blog page has no link from / and the crawler does not pick it up that way. Need to investigate a bit later.

@mklueh
Copy link
Contributor

mklueh commented Jan 3, 2023

@Intevel linking to the blog page did not change anything. Do you have any other ideas ?

@mklueh
Copy link
Contributor

mklueh commented Jan 3, 2023

@Intevel ok got it now after trying a bit more!

I've tested it again with ssr: true and useAsyncData and this seems to work

nuxt.config.ts

/**
   * build:
   *   ssr: true  -> pre-rendered trough server / function
   *   ssr: false -> generate index.html + CSR JS bundles (*)
   * generate:
   *   ssr: true  -> pre-rendered during build
   *   ssr: false -> generate index.html + CSR JS bundles (*)
   *   
   * (*) both should behave identically imo
   *   
   */
  ssr: true,
  nitro: {
    preset: "netlify",
    prerender: {
      routes: [
        '/blog'
      ]
    }
  },

blog.vue

const {getItems} = useDirectusItems();

interface Article {
  id?: string | number;
  title: string;
  content: string;
  status: string;
}

const {data, pending, error, refresh} = await useAsyncData('posts', () => {
  console.log("async called!")
  return getItems<Article>({
    collection: "blog"
  })
})


const posts = data.value;

@Intevel Intevel closed this as completed Jan 3, 2023
@Intevel
Copy link
Owner

Intevel commented Jan 3, 2023

@mklueh Do you think you can make a Pull Request to document this?

@mklueh
Copy link
Contributor

mklueh commented Jan 3, 2023

@Intevel I can do that tomorrow likely

@mklueh
Copy link
Contributor

mklueh commented Jan 5, 2023

@Intevel do you have any preference on where it should be added to the docs? I'm leaning towards "Setup" or "Options", rather than creating a new "Rendering" sub-page

@mklueh
Copy link
Contributor

mklueh commented Jan 5, 2023

I've added it to the options.md page and created a pull request #96

@miket2marcom
Copy link

Hi,

I'm looking for some help in achieving the same thing - getting Directus content 'inlined' into the static site upon build.

I'm using composables to query the API and I'm having some trouble implementing useAsyncContent in this context.

Here is a typical composable as it is, which currently works (I'm cutting out the fields here to make it easier to read):

import { Header } from '~/types/Header.d'
export const useHeader = (menuDepth = 1) => {
  const { getItems } = useDirectusItems()

  const fields = [
    ...
  ]

  const getHeaderLayout = async (codeId: string) => {
    const filters = {
      code_id: {
        _eq: `${codeId}`
      }
    }
    return await getItems<Header>({
      collection: 'header',
      params: { fields, filter: filters }
    })
  }

  return {
    getHeaderLayout
  }
}

And here it is with my attempt to use useAsyncData:

import { Header } from '~/types/Header.d'
export const useHeader = (menuDepth = 1) => {
  const { getItems } = useDirectusItems()

  const fields = [
    ...
  ]

  const getHeaderLayout = async (codeId: string) => {
    const filters = {
      code_id: {
        _eq: `${codeId}`
      }
    }
    const { data, pending, error, refresh } = await useAsyncData('header', () => {
      return getItems<Header>({
        collection: 'header',
        params: { fields, filter: filters }
      })
    })
  }

  return {
    getHeaderLayout
  }
}

But the above gives me 500/'undefined' errors.

For what it's worth, here is how I use the composable on pages:

import { useHeader } from '~/composables/data/useHeader'

const { getHeaderLayout } = useHeader()
const headerpayload = await getHeaderLayout('header')

Any help here would be greatly appreciated.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants