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

Collections - generating page for MDX page fails #5703

Closed
1 task
thomasledoux1 opened this issue Dec 30, 2022 · 21 comments
Closed
1 task

Collections - generating page for MDX page fails #5703

thomasledoux1 opened this issue Dec 30, 2022 · 21 comments
Assignees
Labels
- P3: minor bug An edge case that only affects very specific usage (priority) pkg: vercel Related to Vercel adapter (scope)

Comments

@thomasledoux1
Copy link

What version of astro are you using?

1.8.0

Are you using an SSR adapter? If so, which one?

Vercel

What package manager are you using?

npm

What operating system are you using?

Mac

Describe the Bug

When using a Collection with MDX files, and rendering a page for it as described in the docs, everything works as expected during development.
When I try to build my site however, the build fails.
I get the following error during build:

file: /Users/thomas_ledoux/Documents/Projects/website-thomas-astro/src/content/blog/adding-comments-prisma-planetscale-astro-vercel-edge.mdx?astroContent=true:5:20
3: export const collection = "blog";
4: export const slug = "adding-comments-prisma-planetscale-astro-vercel-edge";
5: export const body = "\n# Adding comments to my Astro blog with PlanetScale & Prisma\n\nAfter I created my [blog platform using Astro](https://www.thomasledoux.be/blog/create-blog-astro-mdx), the next thing on my list was to make it possible for people to (anonymously) leave comments on blog posts.\nFor this I needed to add a database to my architecture.\n\n## Choice of technologies\n\nI chose [PlanetScale](https://wwww.planetscale.com) because it's serverless and MySQL, 2 of my criteria.\nTo communicate with my PlanetScale database, I chose to use [Prisma](https://www.prisma.io/), a Node.js and TypeScript ORM.\n\n## Set up Prisma\n\nI started by adding the Prisma client: `npm install prisma @prisma/client`.\nAfter this install, I added my Prisma schema to my codebase:\n\n```prisma\n// schema.prisma\n\ngenerator client {\n  provider        = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider     = \"mysql\"\n  url          = env(\"DATABASE_URL\")\n  relationMode = \"prisma\"\n}\n\nmodel Post {\n  id         Int       @id @default(autoincrement())\n  createdAt  DateTime  @default(now())\n  url        String\n  like_count Int @default(0)\n  Comment    Comment[]\n}\n\nmodel Comment {\n  id        Int      @id @default(autoincrement())\n  createdAt DateTime @default(now())\n  text      String\n  author    String\n  postId    Int\n  post      Post     @relation(fields: [postId], references: [id], onDelete: Cascade)\n}\n```\n\nThen it got a bit tricky.\nBecause I'm deploying my blog platform on Vercel's Edge network, the connections from the platform to the database can [not have a persistent connection](https://vercel.com/guides/using-databases-with-vercel#connecting-to-your-database).\nAfter some research, I found out Prisma offers a service to set up connection pooling called `Prisma Data Platform`.\nOnce I had created an account on the Data Platform, I was able to create a `Data Proxy`, which provided me with a connection string to use in my application.\nThis connection string is what I needed to put in the `DATABASE_URL` environment variable (which is used in the `prisma.schema`).\n\nTo generate the TypeScript types based on my Prisma schema, I just ran `npx prisma generate`, this will by default generate the types in the `node_modules` folder in your project locally.\n\n## Setting up PlanetScale\n\nSyncing the schema from Prisma to PlanetScale is as easy as running `npx prisma db push` in your terminal.\n\n## Creating comments\n\nTo communicate from my frontend to my API routes, I opted to use [TanStack Query](https://tanstack.com/query/v4), my favourite tool to handle client-side API calls in React.\nThe frontend code to add and list comments for a blog post looks like this (this part I wrote in React):\n\n```tsx\nimport type { Comment } from '@prisma/client';\nimport { useQuery } from '@tanstack/react-query';\nimport { useRef, useState, Fragment } from 'react';\nconst CommentsUpvotes = ({\n  initialComments,\n  blogUrl,\n}: {\n  initialComments?: Comment[];\n  blogUrl: string;\n}) => {\n  const formRef = useRef<HTMLFormElement>(null);\n  const [formState, setFormState] = useState<'idle' | 'loading'>('idle');\n  const upToDateCommentsQuery = useQuery({\n    queryKey: [`comments-${blogUrl}`],\n    queryFn: async () => {\n      const allCommentsInDb = await fetch(\n        `/api/comments/list?blogUrl=${blogUrl}`\n      );\n      const allCommentsInDbJson = await allCommentsInDb.json();\n      return allCommentsInDbJson as Comment[];\n    },\n    initialData: initialComments,\n  });\n  const onSubmit = async (e: React.FormEvent) => {\n    setFormState('loading');\n    e.preventDefault();\n    if (e.currentTarget) {\n      const formData = new FormData(e.currentTarget as HTMLFormElement);\n      formData.set('blogUrl', blogUrl);\n      await fetch('/api/comments/create', {\n        method: 'POST',\n        body: formData,\n      });\n      formRef.current?.reset();\n      upToDateCommentsQuery.refetch();\n    }\n    setFormState('idle');\n  };\n  return (\n    <Fragment>\n      <h2 className=\"text-xl lg:text-2xl mb-4 font-bold\">Add a comment</h2>\n      <form\n        onSubmit={onSubmit}\n        ref={formRef}\n        className=\"flex flex-col lg:w-[50%] items-start\"\n      >\n        <label className=\"flex flex-col mb-2\" htmlFor=\"author\">\n          Author\n        </label>\n        <input\n          className=\"py-2 px-4 bg-white border-secondary border-2 rounded-lg w-full\"\n          placeholder=\"Author\"\n          name=\"author\"\n          required\n        />\n        <label className=\"flex flex-col mb-2 mt-4\" htmlFor=\"comment\">\n          Comment\n        </label>\n        <textarea\n          className=\"py-2 px-4 bg-white border-secondary border-2 rounded-lg w-full\"\n          placeholder=\"Comment\"\n          required\n          rows={4}\n          name=\"comment\"\n        ></textarea>\n        <button\n          disabled={formState === 'loading'}\n          className=\"px-8 mt-4 py-4 bg-secondary text-white rounded-lg lg:hover:scale-[1.04] transition-transform disabled:opacity-50 \"\n          type=\"submit\"\n        >\n          {formState === 'loading' ? 'Submitting' : 'Submit comment'}\n        </button>\n      </form>\n\n      <h2 className=\"text-xl lg:text-2xl mb-4 font-bold\">Comments</h2>\n      {upToDateCommentsQuery?.data && upToDateCommentsQuery?.data.length > 0 ? (\n        <div className=\"flex flex-col gap-y-4\">\n          {upToDateCommentsQuery?.data?.map(comment => (\n            <div key={comment.id} className=\"flex flex-col\">\n              <h3 className=\"font-bold\">{comment.author}</h3>\n              <div>{comment.text}</div>\n            </div>\n          ))}\n        </div>\n      ) : (\n        <div className=\"mt-4\">No comments yet. Be the first to add one!</div>\n      )}\n    </Fragment>\n  );\n};\n\nexport default CommentsUpvotes;\n```\n\nThe code for the API route to create blogs looks like this:\n\n```typescript\nimport type { APIRoute } from 'astro';\nimport { prisma } from '../../../lib/prisma-client';\n\nexport const post: APIRoute = async ({ request }) => {\n  const formData = await request.formData();\n  const comment = formData.get('comment') ?? '';\n  const author = formData.get('author') ?? '';\n  const blogUrl = formData.get('blogUrl') ?? '';\n  const blog = await prisma.post.findFirst({\n    where: { url: blogUrl as string },\n  });\n\n  await prisma.comment.create({\n    data: {\n      author: author as string,\n      text: comment as string,\n      post: {\n        connectOrCreate: {\n          create: {\n            url: blogUrl as string,\n          },\n          where: {\n            id: blog?.id,\n          },\n        },\n      },\n    },\n  });\n\n  return new Response(null, {\n    status: 200,\n  });\n};\n```\n\nAnd the code to list the comments for a post looks like this:\n\n```typescript\nimport type { APIRoute } from 'astro';\nimport { getCommentsForBlog } from '../../../lib/get-comments-for-blog';\n\nexport const get: APIRoute = async ({ request }) => {\n  const params = new URLSearchParams(request.url.split('?')[1]);\n  const allCommentsInDbForPost = await getCommentsForBlog(\n    params.get('blogUrl')\n  );\n  return new Response(JSON.stringify(allCommentsInDbForPost), {\n    status: 200,\n  });\n};\n```\n\n## Setting up the 'Edge' part\n\nDeploying Astro to Vercel Edge is as easy as adding the [Astro with Vercel integration](https://docs.astro.build/en/guides/integrations-guide/vercel/) and setting up the edge `target`.\nMy astro config (note the `edge` in the import path):\n\n```js\nimport { defineConfig } from 'astro/config';\nimport vercel from '@astrojs/vercel/edge';\n\nexport default defineConfig({\n  output: 'server',\n  adapter: vercel(),\n});\n```\n\nI also had to configure an [alias in Vite]() for the Prisma client to get it working on Vercel combined with Astro.\n\n```js\n// vite.config.js\nexport default {\n  resolve: {\n    alias: {\n      '.prisma/client/edge': './node_modules/.prisma/client/edge.js',\n    },\n  },\n};\n```\n\nWhen building the application on Vercel, we also want to [generate the client](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/generating-prisma-client) again to make sure the client is available in the `node_modules` there too.\nIn the `package.json` I use `\"build\": \"prisma generate --data-proxy && astro build\"` for this.\nInstantiating the Prisma client in the code is done in `lib/prisma-client.ts`.\nI used lazy imports from Node.js here to make it work correctly locally and on Vercel.\n\n```typescript\nimport type { PrismaClient } from '@prisma/client';\n\nlet prisma: PrismaClient;\n\nif (process.env.NODE_ENV === 'development') {\n  import('@prisma/client').then(mod => (prisma = new mod.PrismaClient()));\n} else {\n  import('@prisma/client/edge').then(mod => (prisma = new mod.PrismaClient()));\n}\nexport { prisma };\n```\n\nTo make my code run locally too, I needed to change the `DATABASE_URL` environment variable to make it point directly to PlanetScale instead of going through Prisma Proxy.<br></br>\nGo check it out on [my blog](https://www.thomasledoux.be/blog), and add a comment ;-).\nSource code can be found on [my Github](https://github.com/thomasledoux1/website-thomas-astro).\n";
                       ^
6: export const data = {title:"Adding comments to my Astro blog with PlanetScale and Prisma on Vercel Edge",layout:"..\u002F..\u002Flayouts\u002FBlogLayout.astro",tags:["react","javascript","databases","html"],date:"2022-11-28T16:14:39.004Z"};
7: export const _internal = {
 error   Unexpected token (Note that you need plugins to import files that are not JavaScript)
  File:
    /Users/thomas_ledoux/Documents/Projects/website-thomas-astro/src/content/blog/adding-comments-prisma-planetscale-astro-vercel-edge.mdx?astroContent=true:5:20
  Code:
    3: export const collection = "blog";
    4: export const slug = "adding-comments-prisma-planetscale-astro-vercel-edge";
    5: export const body = "\n# Adding comments to my Astro blog with PlanetScale & Prisma\n\nAfter I created my [blog platform using Astro](https://www.thomasledoux.be/blog/create-blog-astro-mdx), the next thing on my list was to make it possible for people to (anonymously) leave comments on blog posts.\nFor this I needed to add a database to my architecture.\n\n## Choice of technologies\n\nI chose [PlanetScale](https://wwww.planetscale.com) because it's serverless and MySQL, 2 of my criteria.\nTo communicate with my PlanetScale database, I chose to use [Prisma](https://www.prisma.io/), a Node.js and TypeScript ORM.\n\n## Set up Prisma\n\nI started by adding the Prisma client: `npm install prisma @prisma/client`.\nAfter this install, I added my Prisma schema to my codebase:\n\n```prisma\n// schema.prisma\n\ngenerator client {\n  provider        = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider     = \"mysql\"\n  url          = env(\"DATABASE_URL\")\n  relationMode = \"prisma\"\n}\n\nmodel Post {\n  id         Int       @id @default(autoincrement())\n  createdAt  DateTime  @default(now())\n  url        String\n  like_count Int @default(0)\n  Comment    Comment[]\n}\n\nmodel Comment {\n  id        Int      @id @default(autoincrement())\n  createdAt DateTime @default(now())\n  text      String\n  author    String\n  postId    Int\n  post      Post     @relation(fields: [postId], references: [id], onDelete: Cascade)\n}\n```\n\nThen it got a bit tricky.\nBecause I'm deploying my blog platform on Vercel's Edge network, the connections from the platform to the database can [not have a persistent connection](https://vercel.com/guides/using-databases-with-vercel#connecting-to-your-database).\nAfter some research, I found out Prisma offers a service to set up connection pooling called `Prisma Data Platform`.\nOnce I had created an account on the Data Platform, I was able to create a `Data Proxy`, which provided me with a connection string to use in my application.\nThis connection string is what I needed to put in the `DATABASE_URL` environment variable (which is used in the `prisma.schema`).\n\nTo generate the TypeScript types based on my Prisma schema, I just ran `npx prisma generate`, this will by default generate the types in the `node_modules` folder in your project locally.\n\n## Setting up PlanetScale\n\nSyncing the schema from Prisma to PlanetScale is as easy as running `npx prisma db push` in your terminal.\n\n## Creating comments\n\nTo communicate from my frontend to my API routes, I opted to use [TanStack Query](https://tanstack.com/query/v4), my favourite tool to handle client-side API calls in React.\nThe frontend code to add and list comments for a blog post looks like this (this part I wrote in React):\n\n```tsx\nimport type { Comment } from '@prisma/client';\nimport { useQuery } from '@tanstack/react-query';\nimport { useRef, useState, Fragment } from 'react';\nconst CommentsUpvotes = ({\n  initialComments,\n  blogUrl,\n}: {\n  initialComments?: Comment[];\n  blogUrl: string;\n}) => {\n  const formRef = useRef<HTMLFormElement>(null);\n  const [formState, setFormState] = useState<'idle' | 'loading'>('idle');\n  const upToDateCommentsQuery = useQuery({\n    queryKey: [`comments-${blogUrl}`],\n    queryFn: async () => {\n      const allCommentsInDb = await fetch(\n        `/api/comments/list?blogUrl=${blogUrl}`\n      );\n      const allCommentsInDbJson = await allCommentsInDb.json();\n      return allCommentsInDbJson as Comment[];\n    },\n    initialData: initialComments,\n  });\n  const onSubmit = async (e: React.FormEvent) => {\n    setFormState('loading');\n    e.preventDefault();\n    if (e.currentTarget) {\n      const formData = new FormData(e.currentTarget as HTMLFormElement);\n      formData.set('blogUrl', blogUrl);\n      await fetch('/api/comments/create', {\n        method: 'POST',\n        body: formData,\n      });\n      formRef.current?.reset();\n      upToDateCommentsQuery.refetch();\n    }\n    setFormState('idle');\n  };\n  return (\n    <Fragment>\n      <h2 className=\"text-xl lg:text-2xl mb-4 font-bold\">Add a comment</h2>\n      <form\n        onSubmit={onSubmit}\n        ref={formRef}\n        className=\"flex flex-col lg:w-[50%] items-start\"\n      >\n        <label className=\"flex flex-col mb-2\" htmlFor=\"author\">\n          Author\n        </label>\n        <input\n          className=\"py-2 px-4 bg-white border-secondary border-2 rounded-lg w-full\"\n          placeholder=\"Author\"\n          name=\"author\"\n          required\n        />\n        <label className=\"flex flex-col mb-2 mt-4\" htmlFor=\"comment\">\n          Comment\n        </label>\n        <textarea\n          className=\"py-2 px-4 bg-white border-secondary border-2 rounded-lg w-full\"\n          placeholder=\"Comment\"\n          required\n          rows={4}\n          name=\"comment\"\n        ></textarea>\n        <button\n          disabled={formState === 'loading'}\n          className=\"px-8 mt-4 py-4 bg-secondary text-white rounded-lg lg:hover:scale-[1.04] transition-transform disabled:opacity-50 \"\n          type=\"submit\"\n        >\n          {formState === 'loading' ? 'Submitting' : 'Submit comment'}\n        </button>\n      </form>\n\n      <h2 className=\"text-xl lg:text-2xl mb-4 font-bold\">Comments</h2>\n      {upToDateCommentsQuery?.data && upToDateCommentsQuery?.data.length > 0 ? (\n        <div className=\"flex flex-col gap-y-4\">\n          {upToDateCommentsQuery?.data?.map(comment => (\n            <div key={comment.id} className=\"flex flex-col\">\n              <h3 className=\"font-bold\">{comment.author}</h3>\n              <div>{comment.text}</div>\n            </div>\n          ))}\n        </div>\n      ) : (\n        <div className=\"mt-4\">No comments yet. Be the first to add one!</div>\n      )}\n    </Fragment>\n  );\n};\n\nexport default CommentsUpvotes;\n```\n\nThe code for the API route to create blogs looks like this:\n\n```typescript\nimport type { APIRoute } from 'astro';\nimport { prisma } from '../../../lib/prisma-client';\n\nexport const post: APIRoute = async ({ request }) => {\n  const formData = await request.formData();\n  const comment = formData.get('comment') ?? '';\n  const author = formData.get('author') ?? '';\n  const blogUrl = formData.get('blogUrl') ?? '';\n  const blog = await prisma.post.findFirst({\n    where: { url: blogUrl as string },\n  });\n\n  await prisma.comment.create({\n    data: {\n      author: author as string,\n      text: comment as string,\n      post: {\n        connectOrCreate: {\n          create: {\n            url: blogUrl as string,\n          },\n          where: {\n            id: blog?.id,\n          },\n        },\n      },\n    },\n  });\n\n  return new Response(null, {\n    status: 200,\n  });\n};\n```\n\nAnd the code to list the comments for a post looks like this:\n\n```typescript\nimport type { APIRoute } from 'astro';\nimport { getCommentsForBlog } from '../../../lib/get-comments-for-blog';\n\nexport const get: APIRoute = async ({ request }) => {\n  const params = new URLSearchParams(request.url.split('?')[1]);\n  const allCommentsInDbForPost = await getCommentsForBlog(\n    params.get('blogUrl')\n  );\n  return new Response(JSON.stringify(allCommentsInDbForPost), {\n    status: 200,\n  });\n};\n```\n\n## Setting up the 'Edge' part\n\nDeploying Astro to Vercel Edge is as easy as adding the [Astro with Vercel integration](https://docs.astro.build/en/guides/integrations-guide/vercel/) and setting up the edge `target`.\nMy astro config (note the `edge` in the import path):\n\n```js\nimport { defineConfig } from 'astro/config';\nimport vercel from '@astrojs/vercel/edge';\n\nexport default defineConfig({\n  output: 'server',\n  adapter: vercel(),\n});\n```\n\nI also had to configure an [alias in Vite]() for the Prisma client to get it working on Vercel combined with Astro.\n\n```js\n// vite.config.js\nexport default {\n  resolve: {\n    alias: {\n      '.prisma/client/edge': './node_modules/.prisma/client/edge.js',\n    },\n  },\n};\n```\n\nWhen building the application on Vercel, we also want to [generate the client](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/generating-prisma-client) again to make sure the client is available in the `node_modules` there too.\nIn the `package.json` I use `\"build\": \"prisma generate --data-proxy && astro build\"` for this.\nInstantiating the Prisma client in the code is done in `lib/prisma-client.ts`.\nI used lazy imports from Node.js here to make it work correctly locally and on Vercel.\n\n```typescript\nimport type { PrismaClient } from '@prisma/client';\n\nlet prisma: PrismaClient;\n\nif (process.env.NODE_ENV === 'development') {\n  import('@prisma/client').then(mod => (prisma = new mod.PrismaClient()));\n} else {\n  import('@prisma/client/edge').then(mod => (prisma = new mod.PrismaClient()));\n}\nexport { prisma };\n```\n\nTo make my code run locally too, I needed to change the `DATABASE_URL` environment variable to make it point directly to PlanetScale instead of going through Prisma Proxy.<br></br>\nGo check it out on [my blog](https://www.thomasledoux.be/blog), and add a comment ;-).\nSource code can be found on [my Github](https://github.com/thomasledoux1/website-thomas-astro).\n";
                           ^
    6: export const data = {title:"Adding comments to my Astro blog with PlanetScale and Prisma on Vercel Edge",layout:"..\u002F..\u002Flayouts\u002FBlogLayout.astro",tags:["react","javascript","databases","html"],date:"2022-11-28T16:14:39.004Z"};
    7: export const _internal = {
  Stacktrace:
Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
    at error (file:///Users/thomas_ledoux/Documents/Projects/website-thomas-astro/node_modules/vite/node_modules/rollup/dist/es/shared/rollup.js:1858:30)
    at Module.error (file:///Users/thomas_ledoux/Documents/Projects/website-thomas-astro/node_modules/vite/node_modules/rollup/dist/es/shared/rollup.js:12429:16)
    at Module.tryParse (file:///Users/thomas_ledoux/Documents/Projects/website-thomas-astro/node_modules/vite/node_modules/rollup/dist/es/shared/rollup.js:12806:25)
    at Module.setSource (file:///Users/thomas_ledoux/Documents/Projects/website-thomas-astro/node_modules/vite/node_modules/rollup/dist/es/shared/rollup.js:12711:24)
    at ModuleLoader.addModuleSource (file:///Users/thomas_ledoux/Documents/Projects/website-thomas-astro/node_modules/vite/node_modules/rollup/dist/es/shared/rollup.js:21959:20)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

My astro.config.js:

import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import mdx from '@astrojs/mdx';
import { remarkReadingTime } from './src/utils/calculate-reading-time.mjs';
import vercel from '@astrojs/vercel/edge';
import react from '@astrojs/react';
import prefetch from '@astrojs/prefetch';

// https://astro.build/config
export default defineConfig({
  integrations: [
    tailwind({
      config: {
        applyBaseStyles: false,
      },
    }),
    react(),
    mdx(),
    prefetch(),
  ],
  output: 'server',
  experimental: {
    contentCollections: true,
  },
  adapter: vercel(),
  markdown: {
    remarkPlugins: [remarkReadingTime],
    extendDefaultPlugins: true,
  },
  site: 'https://www.thomasledoux.be',
});

I didn't add a Stackblitz reproduction, because it happens during build time, and not sure if that would be useful. I linked my Github repo instead, make sure the "use-prerender" branch is selected.

Link to Minimal Reproducible Example

https://github.com/thomasledoux1/website-thomas-astro/tree/feature/use-prerender

Participation

  • I am willing to submit a pull request for this issue.
@surjithctly
Copy link

Have you found any solution for this @thomasledoux1 ?

I have the same problem with mdx, but it works fine on Astro Example. Not sure what's making the issue here.

@thomasledoux1
Copy link
Author

@surjithctly I didn't find it yet.
The MDX blog which is giving the error during the build, works fine while working on the development server...
I use the same MDX on another branch of my repo where I use the MDX as a page inside the /pages folder, and also works fine there.
So it does seem to be caused by something which was added as part of the Collections RFC.
Maybe @bholmesdev knows?

@surjithctly
Copy link

I'm also getting an error in development if I used mdx in a parent folder with spaces. eg: My Works.

Here's a related issue with the space in parent folder: #5598

@bholmesdev
Copy link
Contributor

Thanks for sharing @thomasledoux1! Looks like an issue with escaping content of the MDX body. Can you send a minimal example on Stackblitz with the contents of adding-comments-prisma-planetscale-astro-vercel-edge.mdx?

Also to clarify, is this an issue with spaces in the path to your project? This is being tracked separately as @surjithctly noted.

@bholmesdev bholmesdev added the - P3: minor bug An edge case that only affects very specific usage (priority) label Jan 4, 2023
@thomasledoux1
Copy link
Author

thomasledoux1 commented Jan 4, 2023

Hi @bholmesdev, thanks for getting back on this!
The issue is not with spaces in the path of the project, I just checked that.
Extra info: if I remove this specific MDX file, the build runs fine, while I do have a lot of other MDX files...
Link to minimal example:
https://stackblitz.com/edit/github-nabws4-nslpjk?file=src%2Flayouts%2FBlogLayout.astro,src%2Flayouts%2FLayout.astro,src%2Fpages%2Findex.mdx,src%2Fcomponents%2FFooter.astro,src%2Fcomponents%2FSocialLink.astro,src%2Fcomponents%2FNavigation.astro,src%2Fcomponents%2FNavigationItems.astro,package.json

@matthewp
Copy link
Contributor

matthewp commented Jan 9, 2023

Does this only happen with Content Collections or does it happen if the mdx file is just a normal page?

@thomasledoux1
Copy link
Author

@matthewp only happens with Content Collections, as a normal page it works fine

@bholmesdev bholmesdev assigned matthewp and unassigned bholmesdev Jan 9, 2023
@bholmesdev
Copy link
Contributor

@matthewp It's likely from the way we stringify the raw MDX body here. We do not expose the raw content in the regular MDX plugin. Maybe we need stronger serialization for MDX?
https://github.com/withastro/astro/blob/main/packages/astro/src/content/vite-plugin-content-server.ts#L156

@matthewp
Copy link
Contributor

I'm confused, this Stackblitz doesn't use content collections. What am I missing @thomasledoux1 ?

@thomasledoux1
Copy link
Author

@matthewp I just created a minimal reproduction with the MDX file in it as asked by @bholmesdev. If you want I can change the current Stackblitz, but I'm not sure if it's going to help a lot, since the error only occurs at build time? Not sure if you can run the build command in Stackblitz?

@matthewp
Copy link
Contributor

@thomasledoux1 I can pull it down and run the build locally. Just having something that breaks is super helpful, thank you!

@matthewp
Copy link
Contributor

Was able to reduce it down to being about the process.env.NODE_ENV, so far:

```typescript
if (process.env.NODE_ENV === 'development') {

}
```

Will do some more investigation.

@matthewp
Copy link
Contributor

Not able to recreate with this example: https://stackblitz.com/edit/github-kbdjml?file=astro.config.mjs,src%2Fpages%2Findex.astro,src%2Fcontent%2Fconfig.ts,src%2Fcontent%2Fblog%2Fone.mdx&on=stackblitz

My assumption is there is something else with your config causing this.

@thomasledoux1
Copy link
Author

My Astro.config.js looks like this if relevant:

import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import mdx from '@astrojs/mdx';
import { remarkReadingTime } from './src/utils/calculate-reading-time.mjs';
import vercel from '@astrojs/vercel/edge';
import react from '@astrojs/react';
import prefetch from '@astrojs/prefetch';

// https://astro.build/config
export default defineConfig({
integrations: [
tailwind({
config: {
applyBaseStyles: false,
},
}),
react(),
mdx(),
prefetch(),
],
output: 'server',
adapter: vercel(),
markdown: {
remarkPlugins: [remarkReadingTime],
extendDefaultPlugins: true,
},
site: 'https://www.thomasledoux.be',
});

@matthewp
Copy link
Contributor

It's Vercel Edge that's causing it. Doesn't break with any other adapters:

https://stackblitz.com/edit/github-kbdjml?file=astro.config.mjs,src%2Fpages%2Findex.astro,src%2Fcontent%2Fconfig.ts,src%2Fcontent%2Fblog%2Fone.mdx&on=stackblitz

Now going to see if mdx matters or not.

@matthewp
Copy link
Contributor

MDX does not matter. Also this is not related to content collections. Happens with a normal page too:

https://stackblitz.com/edit/github-kbdjml?file=astro.config.mjs,src%2Fpages%2Findex.astro,src%2Fpages%2Ftwo.md,package.json&on=stackblitz

@matthewp matthewp added pkg: vercel Related to Vercel adapter (scope) and removed content-collections labels Jan 10, 2023
@matthewp
Copy link
Contributor

This workaround fixes it:

define: {
  "process.env.NODE_ENV": `'${process.env.NODE_ENV}'`
}

In your astro.config file.

@matthewp
Copy link
Contributor

This is a bug in Vite, see vitejs/vite#9829

Probably won't keep this issue open since it's an upstream issue. cc @bluwy. Let me know if you think there's a fix in Vite that's not too difficult. Another option is we set the above define config in Astro although I'd prefer not to have to do that.

@thomasledoux1
Copy link
Author

Confirmed that it's working now! Thanks a lot @matthewp for the thorough research!
For others reading this, added the following in astro.config.js 's defineConfig():

  vite: {
    define: {
      'process.env.NODE_ENV': `'${process.env.NODE_ENV}'`,
    },
  },

@surjithctly
Copy link

I was not using vercel adapter but this issue happened to me as well (static)

If this is not related to user config, it should be patched in Astro until vite fixes this.

While checking the workaround, I have nothing related to node.env in my code, so that’s strange I have to add that code.

@bluwy
Copy link
Member

bluwy commented Jan 12, 2023

Probably won't keep this issue open since it's an upstream issue. cc @bluwy. Let me know if you think there's a fix in Vite that's not too difficult. Another option is we set the above define config in Astro although I'd prefer not to have to do that.

There's two fixes in Vite - vitejs/vite#9791 and vitejs/vite#11151. Both have its own tradeoffs that aren't fully thought out yet, so I don't think it would be fixed soon. I agree that we should keep this as an upstream issue though since there's not much we can do.

I don't think the define trick is a silver bullet too. It's assuming that the generated code uses double quotes, plus we shouldn't be replacing it in the first place so it's technically still undesired.

I'll close this one for now.

@bluwy bluwy closed this as not planned Won't fix, can't repro, duplicate, stale Jan 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
- P3: minor bug An edge case that only affects very specific usage (priority) pkg: vercel Related to Vercel adapter (scope)
Projects
None yet
Development

No branches or pull requests

5 participants