nuxt / content

The file-based CMS for your Nuxt application, powered by Markdown and Vue components.
https://content.nuxt.com
MIT License
3.08k stars 624 forks source link

<ContentList> works in "npm run dev", but not in "npm run build" #2582

Closed bryancurran closed 6 months ago

bryancurran commented 6 months ago

Environment


Reproduction

To reproduce, simply create a content directory in the root of your project and place any .md file in it.

Then under pages/blog/index.vue I have this file:

<template>
    <main>
        list
        <ContentList>
            <template #default="{ list }">
                <div v-for="article in list" :key="article._path">
                    <a :href="article._path">{{ article.title }}</a>
                </div>
            </template>
            <template #not-found>
                <div>Not found</div>
            </template>
        </ContentList>
    </main>
</template>

Describe the bug

When visiting the /blog path while running npm run dev, it correctly lists all of the files within the content/ directory.

When running npm run build followed by npm run start, the /blog path simply says "Not found".

Nothing else has changed.

Additional context

No response

Logs

No response

twatzl commented 6 months ago

I have stumbled upon a similar, if not the same issue. It cost me 2 weeks to debug, but it seems I finally got a fix.

TL;DR: contrary to the documentations ContentList ALWAYS REQUIRES path parameter to be passed in order to work in production.

This is my article list component which I generically use to generate lists of articles from a directory

<template>
  <PageTitle :title="title"></PageTitle>
  <PageContent>
    <ContentList :path="path" :query="query">
      <template v-slot="{ list }">
        <div v-for="article in list" :key="article._path">
          <Card class="article-content px-5 py-2 mb-5">
            <template #header>
              <h2>{{ article.title }}</h2>
              <div class="flex align-items-center text-sm my-3" v-if="showDate">
                <i class="pi pi-clock mr-2"/>{{ article.date }}
              </div>
            </template>
            <template #content>
              <ContentRendererMarkdown :value="article"/>
            </template>
          </Card>
        </div>
      </template>
      <template #not-found>
        <Card>
          <template #content>
            <p>Keine {{ title }} gefunden.</p>
          </template>
        </Card>
      </template>
    </ContentList>
    <slot name="additionalContent"></slot>
  </PageContent>
  <div class="h-3rem"></div>
</template>
<script setup lang="ts">

import PageTitle from '~/components/PageTitle.vue';

const props = defineProps<{
  title: string,
  showDate: boolean,
  query: QueryBuilderParams,
  path: string | undefined,
}>();
</script>

This is my content subfolder:

image

What i found out was that e.g. this query http://localhost:3000/contentApi/_content/query?_params={"sort":[{"date":-1}],"where":[{"_path":"--REGEX+/^\\/news/"}]} worked when running using nuxt dev but not when building for production and running with node. It just returned [] as a result. However once I specified a path parameter to the ContentList additionally to the query parameter it suddenly worked.

Weirdly enough when not passing any parameters in prod I got the same result from the query endpoint as in dev (some json with the articles).

For example this was one of the calls before (which did not work):

<template>
  <ArticleList title="Über uns" :query="query"></ArticleList>
</template>
<script setup lang="ts">
const query: QueryBuilderParams = {path: 'about'};
</script>

and after (which worked)

<template>
  <ArticleList title="Über uns" :path="path"></ArticleList>
</template>
<script setup lang="ts">
const path = "/about"
</script>

For my build I use the following Dockerfile:

# Stage 1 - build
FROM node:20-alpine AS builder
ARG NPM_REPO_URL
ARG NPM_TOKEN
WORKDIR /app
COPY . .
RUN echo "" >> .npmrc  \
    && printf "@boudicca:registry=https://${NPM_REPO_URL}\n" >> .npmrc \
    && printf "@museumrailwayevents:registry=https://${NPM_REPO_URL}\n" >> .npmrc \
    && printf "//${NPM_REPO_URL}:_authToken=\${NPM_TOKEN}" >> .npmrc
RUN npm install && npm run build

# Stage 2 - production
FROM node:20-alpine AS final
WORKDIR /app
COPY --from=builder /app/.output ./.output
ENV NUXT_HOST=0.0.0.0
ENV NUXT_PORT=3000
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]

I don't really know what happens. Some optimization or incompatibility or whatever, but I know that this is a huge issue, because it works perfectly fine in dev mode and then suddenly stops working in production and this makes it a huge pain to debug and find the cause.

What I know is that I did not touch the news page, however before adding the path to my ArticleList it also did not work and now suddenly it works. Even though passing undefined as a parameter.

owljackob commented 6 months ago

Could you try to update Nitro to 2.9.3?

acidjazz commented 6 months ago

Could you try to update nitro to 2.9.3?

Upgrading nitro fixed this for me

liviuzachin commented 6 months ago

For me it also happened when using useAsyncData('blog', () => queryContent('blog').find()) directly. I can confirm that upgrading nitropack@2.9.3 solved the issue. Thanks for the tip :)

bryancurran commented 6 months ago

Confirming what others have helpfully pointed out. appears to be broken in Nitro 2.9.1 - which is currently the default version installed with Nuxt 3. Upgrading Nitro to 2.9.3 resolved the issue for me so I'm closing the issue.

acidjazz commented 6 months ago

Confirming what others have helpfully pointed out. appears to be broken in Nitro 2.9.1 - which is currently the default version installed with Nuxt 3. Upgrading Nitro to 2.9.3 resolved the issue for me so I'm closing the issue.

I think we shoud re-open this and then close it once nuxt-content and/or nuxt uses nitro 2.9.3 ? I see this more of a workaround