react-router icon indicating copy to clipboard operation
react-router copied to clipboard

[Bug]: (v7) @mdx-js/rollup: Unexpected `FunctionDeclaration` in code: only import/exports are supported. Error for a custom vite server.

Open zdunecki opened this issue 1 year ago • 2 comments

What version of React Router are you using?

v7

Steps to Reproduce

  1. Install react-router (7.0.0-pre.1)
  2. Install @mdx-js/rollup (tested with ^3.1.0 and ^3.0.1)
  3. Create a custom vite server and add plugins for mdx + react-router
  4. Run custom vite server

Demo: https://stackblitz.com/edit/vitejs-vite-xmllxz?file=package.json

Expected Behavior

As a user, I expect the same behaviour for a custom vite server as a react-router one when using a mdx plugin.

Actual Behavior

When I run a react-router via a custom vite server with @mdx-js/rollup plugin I got error:

[plugin:@mdx-js/rollup] Unexpected `FunctionDeclaration` in code: only import/exports are supported
/home/projects/vitejs-vite-xmllxz/Post.mdx:2:1
1  |  import {jsxDEV as _jsxDEV} from "react/jsx-dev-runtime";
2  |  function _createMdxContent(props) {
   |   ^
3  |    const _components = {
4  |      h1: "h1",

Demo: https://stackblitz.com/edit/vitejs-vite-xmllxz?file=package.json

zdunecki avatar Oct 21 '24 11:10 zdunecki

I fixed that by removing mdx plugin from vite.config.ts. Since it's reasonable it would be great to have better developer experience here IMO.

Additionally react-router/remix requires configFile inside vite createServer and this leds to create vite config which is not really needed (below stackblitz demo). Because of that fact I did mistake to pass mdx plugin twice.

Here's a demo: https://stackblitz.com/edit/vitejs-vite-mhy6h5?file=vite.config.ts

zdunecki avatar Oct 21 '24 14:10 zdunecki

I've updated your demo and it worked. I've removed all of the options from server.ts and then it takes them from vite.config.ts by default.

vite.config

import { reactRouter } from '@react-router/dev/vite';
import { defineConfig } from 'vite';
import mdx from '@mdx-js/rollup';

export default defineConfig({
  plugins: [mdx(), reactRouter()],
  optimizeDeps: {
    include: ['react/jsx-runtime'],
  },
});

server.ts

import { createServer } from 'vite';

async function startServer() {
  const server = await createServer({});

  await server.listen(5173);
  server.printUrls();
  server.bindCLIShortcuts({ print: true });
}

startServer();

StackBlitz doesn't let me save some why, so no link for the demo.

DovydasNavickas avatar Oct 22 '24 22:10 DovydasNavickas

Since it's reasonable it would be great to have better developer experience here IMO.

Agreed! I'm working on it 👍

pcattori avatar Nov 25 '24 20:11 pcattori

Thanks for raising this issue.

The specific issue raised here is caused by the @mdx-js/rollup plugin being used twice. You're seeing this error message because the 2nd plugin instance is trying to parse the JS output from the 1st plugin instance as if it was MDX. This is happening in your example because it's merging the plugins arrays from both the inline config and vite.config.ts, resulting in duplicated plugins.

As you noted, the React Router plugin currently requires the presence of a Vite config file. This is so that we can load a fresh copy of all plugins to pass to our child compiler, which is needed to support non-JS routes (like MDX) and so we can ensure code is run through your plugins before analysing code for Split Route Modules support.

The correct usage to avoid this issue is what @DovydasNavickas posted above, avoiding inline config and using vite.config.ts instead. As of right now, this is expected behaviour. Ideally we'd like to drop the requirement for having a vite.config.ts file, but this will require some re-work and would likely be a breaking change. In the meantime, this behaviour is not considered a bug.

markdalgleish avatar Apr 29 '25 06:04 markdalgleish