MDX+Vite guide (with workaround for Jest)

MDX+Redwood+Vite (now with a workaround for Jest)

@mdx-js/rollup plugin

Install the plugin at the Redwood project root (not under the web workspace) with yarn add @mdx-js/rollup

In theory you should be able to import the plugin and add it to vite.config.ts plugins array. In theory … In practice, you’ll run into a CSJ vs ESM module incompatibility issue. There are 2 ways resolve this.

  1. The first involves adding "types: "module" to web/package.json.

  2. The second involves using dynamic import for the @mdx-js/plugin.

I’ve opted for the 2nd option as its effect is localized to just vite.config.ts. Modify vite.config.ts the following way:

// const viteConfig: UserConfig = {
//   plugins: [redwood()],
// }

// export default defineConfig(viteConfig)
export default defineConfig(async () => {
  const mdx = await import('@mdx-js/rollup')
  const viteConfig: UserConfig = {
    plugins: [redwood(), mdx.default()],
  }

  return viteConfig
})

After this, you should be able to define an MDX component file like this:

web/src/components/Sample/Sample.mdx

# Hello World

This is an mdx example

And import it like this from another TSX or JSX file and use it like any other React component.

import Sample from 'src/components/Sample/Sample.mdx'

... <Sample /> ...

Source: MDX v2 not working · Issue #44 · brillout/vite-plugin-mdx · GitHub

Fix type errors in vscode

After the above, the MDX sample component should render. However, you’ll see the error Cannot find module 'Sample.mdx' or its corresponding type declarations in vsCode

  1. Add the mdx types package
yarn workspace web add @types/mdx -D
  1. Declare types by creating mdx.d.ts under web/types with this content
declare module '*.mdx' {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let MDXComponent: (props: any) => JSX.Element

  export default MDXComponent
}
  1. Reference the above declaration in tsconfig.json by adding the “mdx” to the list of types in compilerOptions
{
  "compilerOptions": {
    ...
    "types": [..., "mdx"]
  },
  ...
}

Source: Fix typescript error for mdx files in React

Fix jest error

At this point, Jest tests for components that import mdx content will fail. Setting up actual MDX rendering is a bit convoluted for Jest. For now, I’m settling for just rendering the MDX content as null. This should keep Jest quiet.

Create the file /web/transformers/jest-return-null.js

const mdx = require('@mdx-js/mdx')

const transformer = {
  //eslint-disable-next-line no-unused-vars
  process: function (sourceText, sourcePath, options) {
    return {
      code: 'module.exports = () => null',
    }
  },
}

module.exports = transformer

Then add it to web/jest.config.js

const config = {
  ...
  transform: {
    '^.+\\.mdx$': '<rootDir>/web/transformers/jest-return-null.js',
  },
}

All good now. Sort of.

5 Likes

Hi @tvo Thanks for the write-up, v helpful. Are you aware of any Redwood + MDX blog examples? Something similar to this but for Redwood. Thank you.

Hello,
It’s been a while since I’ve worked on this subject. I only remember finding out-of-date articles and answers that were 80% there. Afaik 6 months ago, no example for Redwood+MDX blog existed. That’s why I posted my finding above.

Are you looking to start a Redwood+MDX blog? What is currently the missing piece for you? Lmk. No guarantee but perhaps I can help.

Thank you sir, saved me many headaches :pray: