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

Need a way to transform other plugin(such as mdx)'s output. #38

Closed
4 tasks done
csr632 opened this issue Dec 4, 2022 · 17 comments · Fixed by #122
Closed
4 tasks done

Need a way to transform other plugin(such as mdx)'s output. #38

csr632 opened this issue Dec 4, 2022 · 17 comments · Fixed by #122
Labels
enhancement New feature or request

Comments

@csr632
Copy link
Member

csr632 commented Dec 4, 2022

Description

I am currently using mdx with react. I use @mdx-js/rollup transform .mdx files into React components.
But neither @mdx-js/rollup or @vitejs/plugin-react is doing react-refresh transform to the .mdx files (.i.e .mdx files are not self-accepting). Editing .mdx file during dev results in full reload if it not imported by a hmr boundary (.e.g imported by a .jsx file which is made self-accepting by @vitejs/plugin-react).

@vitejs/plugin-react options like exclude and include don't work.

Here is a example:
https://stackblitz.com/edit/vitejs-vite-ucnnpy?file=vite.config.ts,src%2Fdemo.mdx,src%2Fmain.tsx,src%2FWrapper.tsx,src%2Fvite-env.d.ts&terminal=dev

Can @vitejs/plugin-react provide a way to transform @mdx-js/rollup’s output?

Suggested solution

@vitejs/plugin-react should be able to handle other plugin's output.

This line should be adjustable by option so that .mdx can pass this check

if (/\.(?:mjs|[tj]sx?)$/.test(extension)) {

Alternative

No response

Additional context

No response

Validations

csr632 added a commit to vitejs/vite-plugin-react-pages that referenced this issue Dec 4, 2022
@csr632
Copy link
Member Author

csr632 commented Dec 4, 2022

Currently I use this pattern to workaround this issue:

/**
 * use @vitejs/plugin-react to handle the output of @mdx-js/rollup
 * workaround this issue: https://github.com/vitejs/vite-plugin-react/issues/38
 */
function createMdxTransformPlugin(): Plugin {
  let vitePluginReactTrasnform
  return {
    name: 'post-mdx-transform',
    configResolved: ({ plugins }) => {
      // find @vitejs/plugin-react's plugin to call it's transform function:
      // https://github.com/vitejs/vite-plugin-react/blob/b647e74c38565696bd6fb931b8bd9ac7f3bebe88/packages/plugin-react/src/index.ts#L206
      vitePluginReactTrasnform = plugins.find(
        (p) =>
          p.name === 'vite:react-babel' && typeof p.transform === 'function'
      )?.transform
      if (!vitePluginReactTrasnform) {
        throw new Error(
          `Can't find an instance of @vitejs/plugin-react. You should apply this plugin to make mdx work.`
        )
      }
    },
    transform: (code, id, options) => {
      const [filepath, querystring = ''] = id.split('?')
      if (filepath.match(/\.mdx?$/)) {
        // make @vitejs/plugin-react treat the "output of @mdx-js/rollup transform" like a jsx file
        // https://github.com/vitejs/vite-plugin-react/blob/b647e74c38565696bd6fb931b8bd9ac7f3bebe88/packages/plugin-react/src/index.ts#L215
        let newId
        if (querystring) {
          newId = id + '&ext=.jsx'
        } else {
          newId = id + '?ext=.jsx'
        }
        return vitePluginReactTrasnform(code, newId, options)
      }
    },
  }
}

But it rely on some internal facts of @vitejs/plugin-react, which are not documented and may be changed in the future.
Also, @vitejs/plugin-react never guarantee that its transform function can be called by other plugin (won't break in the feature). Can @vitejs/plugin-react provide this guarantee (in the document)?

@ArnaudBarre
Copy link
Member

ArnaudBarre commented Dec 4, 2022

Thanks for the detailed bug report and the repro.
vite-plugin-mdx is trying to make fast-refresh works but I think that as you noticed this does't mark the initial .mdx as a refresh boundary.

I think this is a bad idea for the future to tell that calling the transform from outside is supported.

Ideally we should have a better usage of the filter function, I will se if I can push something before v4.

The setup that I would advice for now is to rely on the query string:

import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { compile } from '@mdx-js/mdx';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    {
      name: 'mdx',
      enforce: 'pre',
      resolveId(id, importer) {
        if (id.endsWith('.mdx')) {
          return `${join(dirname(importer), id)}?ext.jsx`;
        }
      },
      async load(id) {
        const base = id.split('?')[0];
        if (base.endsWith('.mdx')) {
          const jsCode = await compile(readFileSync(base, 'utf-8'));
          return { code: jsCode.value, map: null };
        }
      },
    },
    react(),
  ],
});

Not tested, but could be changed to something like this to support the soon to be released swc plugin:

import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import { compile } from '@mdx-js/mdx';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    {
      name: 'mdx',
      enforce: 'pre',
      resolveId(id, importer) {
        if (id.endsWith('.mdx')) {
          return `${join(dirname(importer), id)}.jsx`;
        }
      },
      async load(id) {
        const base = id.split('?')[0];
        if (base.endsWith('.mdx.jsx')) {
          const jsCode = await compile(readFileSync(base.slice(0, -4), 'utf-8'));
          return { code: jsCode.value, map: null };
        }
      },
    },
    react(),
  ],
});

@csr632
Copy link
Member Author

csr632 commented Dec 4, 2022

Thanks for your reply!

Notice that the current vite-plugin-mdx only works for mdx v1. That's why we are using @mdx-js/rollup now.


Since vite-plugin-react is enforce: 'pre'. If we want it to handle other plugin's output (.e.g @mdx-js/rollup), the other plugin also need to be enforce: 'pre'! It brings a limitation to this solution. For example, @mdx-js/rollup does not have enforce: 'pre'.

We can overcome this limitation by providing another vite-plugin-react instance without enforce: 'pre'. And apply the two vite-plugin-react instances together. Some optimization can be done here to avoid transforming every file twice.

We can also overcome this limitation by creating a dedicated vite-mdx plugin to intergrade mdx v2 with vite-plugin-react. And this vite-mdx plugin will have enforce: 'pre'.


The code example you provided modify the resolveId of .mdx file, only to make it recognizable to vite-plugin-react. I think that is not ideal. It makes the resolveId less recognizable for other plugins. Can we have better way to mark a file to be transformed by vite-plugin-react?

@ArnaudBarre
Copy link
Member

ArnaudBarre commented Dec 4, 2022

I think the second version that I suggested is better. You just hiding the fact that it was originally an mdx file, and providing an early load function for it. What would be a usage for having other plugin see the raw mdx content?

@csr632
Copy link
Member Author

csr632 commented Dec 4, 2022

I think the second version that I suggested is better. You just hiding the fact that it was originally an mdx file, and providing an early load function for it. What would be a usage for having other plugin see the raw mdx content?

You are right. Now the .mdx.jsx extensions make sense to me! 😄
It means "it is mdx at first, then becomes jsx".

Just like the second code example you suggested, we need to create a dedicated plugin (@mdx-js/vite) to make it recognize create .mdx.jsx extension and have enforce: 'pre'.

@wooorm What do you think about this? I can create a PR to mdx repo if you agree.

@ArnaudBarre
Copy link
Member

to make it recognize .mdx.jsx

This is the plugin that creates these virtual files, not really "recognize" them.

@wooorm
Copy link

wooorm commented Dec 5, 2022

I don’t understand the whole thread. Quickly reading this though: you need to treat .mdx files the same as .ts files. It’s a compile-to-JS language. If you list TS extensions here as JavaScript, .mdx should also be listed here. If .ts is handled somewhere else, then that depends.

Note that MDX normally does not compile to .jsx. It compiles to .js. Just like .ts.

@ArnaudBarre
Copy link
Member

It compiles to js but without fast refresh. That why you need a good interrop with this plugin, because babel can't parse mdx and mdx can't output hmr component

@wooorm
Copy link

wooorm commented Dec 6, 2022

How does typescript "compile to fast refresh"? How does it "output hmr component"?

@ArnaudBarre
Copy link
Member

Thanks to babel

@wooorm
Copy link

wooorm commented Dec 6, 2022

I don’t have the context of how this plugin works and where it fits into typescript/babel/esbuild/rollup/vite/etc and what you want to do, so I can’t do much with these short answers, and I can’t advise on where you should fix this.

Presumably there is a way to run a babel transform on an AST which turns a module into an “HMR” module. That’s what you need to run after MDX.

I don’t think the solution is calling .mdx files .js files. As you don’t call .ts files .js either.

@csr632
Copy link
Member Author

csr632 commented Dec 6, 2022

@wooorm Sorry for bringing you here with this blurry context. Let me summarize this thread. So you can read this comment only, without reading the whole thread.

vite-plugin-react does this two kind of babel transform:

  1. Use react-refresh's babel plugin to transform all .tsx/.jsx files, making all React components to be able to accept "hot update" (also called "fast-refresh", the "HMR" solution provided by React).
  2. Transform jsx syntax away.

@mdx-js/rollup can already do ②. So "jsx syntax" is NOT the subject we talk about in this thread.
The problen this thread talks about is ①, the fast-refresh transformation. The mdx plugin does not (and should not) do that transformation. The problem of lacking "fast-refresh transformation" is shown by this example. That is why we want to have this transform pipline: .mdx files -> mdx plugin -> vite-plugin-react -> runnable js file.

The purpose of vite-plugin-react here is to do fast-refresh transformation.

We can let either the mdx plugin or the react plugin to transform the jsx syntax, or enabling both! So jsx transform is not an issue.

But currently, we only have this pipline: .mdx files -> @mdx-js/rollup -> runnable js file, but without fast-refresh. It is caused by two reasons:
(1). vite-plugin-react doesn't know .mdx extension so it never transform it (even though the output of @mdx-js/rollup is actually transformable by vite-plugin-react). This is a flaw of vite-plugin-react and it will improve on this (said in this comment). So we actually DON'T need to worry about using what file extension for resolvedId(.mdx or .mdx.js). Users will be able to tell vite-plugin-react to handle .mdx!
(2). vite-plugin-react is a enforce: 'pre' plugin, which is always run before all normal plugin(.i.e @mdx-js/rollup)! So the transform pipline we want is not achievable currently!

So, the only request we have for the mdx plugin is to fix (2): make it an enforce: 'pre' plugin. And tell users to put it before vite-plugin-react invite.config.js. (Updated for ArnaudBarre's remind: also tell users to config vite-plugin-react to "filter include" .mdx files)

@ArnaudBarre
Copy link
Member

So, the only request we have for the mdx plugin is to fix (2): make it a enforce: 'pre' plugin. And tell users to put it before vite-plugin-react invite.config.js.

On top of this, you need to be able to configure the global filer for this plugin. Which is the initial request in this issue.
Which is a breaking change so we need to do it before Vite. @aleclarson do you think you can back port your PR before Friday? I can do it otherwise.

@wooorm
Copy link

wooorm commented Dec 7, 2022

enforce: 'pre' plugin

I can’t find the word enforce in the rollup docs. So it seems this is a Vite only thing and does not apply to @mdx-js/rollup?
This seems to be something Vite users can do themselves according to these docs: https://vitejs.dev/guide/api-plugin.html#rollup-plugin-compatibility.

I wonder if enforce: 'pre' makes sense a) only in combination with both vite-plugin-react and @mdx-js/rollup, b) always for Vite users of @mdx-js/rollup

What is the reason vite-plugin-react has enforce: 'pre'? I guess to run before Vite core plugins, but why specifically?

@ArnaudBarre
Copy link
Member

Yeah this is used to run before esbuild.

A simple solution to avoid creating a vite plugin just for that is to document that people should do something like that with Vite:

plugins: [
  { enforce: "pre", ...mdx() }, 
  react(),
]

Which is ok IMO

@wooorm
Copy link

wooorm commented Dec 7, 2022

Yeah this is used to run before esbuild.

To confirm, so esbuild is a Vite core plugin?

people should do something like that with Vite:

I’m not clear whether this code always needed for Vite, or only when Vite is used with vite-plugin-react and @mdx-js/rollup. Can you confirm?

@ArnaudBarre
Copy link
Member

Yes there is a default esbuild plugin to process js/ts files

It will be needed only if you want to have good hmr with mdx. Otherwise it works but if you component is imported in root you get full page reload instead of hmr

wooorm added a commit to mdx-js/mdx that referenced this issue Dec 8, 2022
@sapphi-red sapphi-red added the enhancement New feature or request label Dec 19, 2022
csr632 added a commit to vitejs/vite-plugin-react-pages that referenced this issue Dec 27, 2022
* init search

* refactor(theme-doc): share pageGroups analysis

* search data with group info

* improve name

* improve code style

* save work

* upgrade deps

* no loger need @types/react-router-dom

* upgrade react-dom usage

* update deps

* keep rollup version align with vite

* migrate to react-router v6

* fix ts error

* dev mode works

* tweak ssr

* run types-react-codemod

* fix ssr

* fix types

* simplify ssr config

* migrate DemoMdxPlugin to mdx 2.x

* TsInfoMdxPlugin works with mdx 2.x

* FileTextMdxPlugin works with mdx 2.x

* replace ImageMdxPlugin with remcohaszing/remark-mdx-images

* add comment

* fix routes and topBar links

* disable search for now

* remove theme-basic

* don't need linkBins

* chore: publish 4.0.0-alpha.0

* update create-project templates

* chore: publish 4.0.0-alpha.1

* fix optimizeDeps

* bump deps of templates

* fix mdx code tag render

* fix antd style

* chore: publish alpha

* works in node commonjs

* fix ssr issue: commonjs interop

* tweak test timout

* update pnpm.lock

* fix ci: taskkill error

https://pipelines.actions.githubusercontent.com/serviceHosts/994468f0-9514-4a95-bb54-d52b4298100c/_apis/pipelines/1/runs/209/signedlogcontent/5?urlExpires=2022-11-24T15%3A31%3A48.5125848Z&urlSigningMethod=HMACV1&urlSignature=ijfBRodz0%2FlGqMcPz3vwUYkLYFkU8vHeE2Lp2boZ2gk%3D

* prepare to analyze outline info (table of content) at buildtime

* tweak windows test ci

* improve test-setup

* fix ssr on windows

* fix typo

* outline info render

* chore: publish alpha

* fix outline render

* improve demo

* chore: publish alpha

* fix import error in cjs env

* chore: publish alpha

* simplify demos

* upgrade antd to 5.x

* tweak demo

* chore: publish alpha

* fix theme style

* chore: publish alpha

* fix test

* improve search

* fix anchor link when using hash router

* chore: publish alpha

* fix ts error

* chore: publish alpha

* fix build

* chore: publish alpha

* fix import allPagesOutlines

* chore: publish alpha

* fix build

* fix ci

* fix anchor link scroll

* improve demos

* chore: publish alpha

* fix cleanStaticData

* OutlineInfoModuleManager should skip update it outline info didn't changed

* headings (outlines) update should trigger hmr hot update instead of full reload

* chore: publish alpha

* make hmr works with mdx files

workaround this issue: vitejs/vite-plugin-react#38

* don't show loading state when:
- User navigates back to a loaded page.
- Hmr update during dev.

* improve file names

* fix path

* fix hydration layout change

* chore: publish alpha

* better name

* update jotai and remove local copy

* bundle client modules to reduce browser request during dev and avoid conflict npm package with users

* update pnpm lock

* jotai provider-less mode

* experiment

* chore: publish alpha

* don't need to build client with tsc; cleanup

* update deps

* fix ts error

* adapt to vite-plugin-react 3.0 breaking change: no longer do jsx transform to .md files

* upgrade playwright test

* chore: publish alpha

* fix warning of useLayoutEffect during ssr

* fix react warning

* publish alpha

* cleanup setup for doc

* cleanup

* warn for old mdx plugin

* update lock

* make setupPlugins the default export

* update setup

* improve vite setup

* improve vite setup

* update docs

* publish alpha

* prevent search popup scroll with page

* improve mdx setup

* fix outline layout

* improve search popup style on narrow screen

* publish alpha

* add an option to turn off search

* publish alpha

* cleanup deps

* improve antd ssr

* fix ssr hydrate style flash

* publish alpha

* react-pages should not couple on @ant-design/cssinjs

* alpha

* use a rollup plugin to add style import to output bundles

* implement a SSR plugin system to decouple vite-pages ssr from antd ssr steps

* publish alpha

* vite-pages-theme-doc have "type": "module"

* pub

* support ssr plugin to let user hook into the ssr process

* improve ssr plugin

* improve ssr plugin system: no longer need vite plugin

* improve ssr plugin

* fix ssr plugin

* fix outline style

* cleanup

* update deps

* remove vite-plugin-mdx

* fix cleanStaticData

* fix demo

* fix demos

* publish alpha

* update contributing guide

* feat: minify html for ssg mode (#102)

* feat: minify html for ssg

* chore: format

Co-authored-by: 阿良仔 <32487868+cijiugechu@users.noreply.github.com>
csr632 added a commit to vitejs/vite-plugin-react-pages that referenced this issue Dec 27, 2022
* init search

* refactor(theme-doc): share pageGroups analysis

* search data with group info

* improve name

* improve code style

* save work

* upgrade deps

* no loger need @types/react-router-dom

* upgrade react-dom usage

* update deps

* keep rollup version align with vite

* migrate to react-router v6

* fix ts error

* dev mode works

* tweak ssr

* run types-react-codemod

* fix ssr

* fix types

* simplify ssr config

* migrate DemoMdxPlugin to mdx 2.x

* TsInfoMdxPlugin works with mdx 2.x

* FileTextMdxPlugin works with mdx 2.x

* replace ImageMdxPlugin with remcohaszing/remark-mdx-images

* add comment

* fix routes and topBar links

* disable search for now

* remove theme-basic

* don't need linkBins

* chore: publish 4.0.0-alpha.0

* update create-project templates

* chore: publish 4.0.0-alpha.1

* fix optimizeDeps

* bump deps of templates

* fix mdx code tag render

* fix antd style

* chore: publish alpha

* works in node commonjs

* fix ssr issue: commonjs interop

* tweak test timout

* update pnpm.lock

* fix ci: taskkill error

https://pipelines.actions.githubusercontent.com/serviceHosts/994468f0-9514-4a95-bb54-d52b4298100c/_apis/pipelines/1/runs/209/signedlogcontent/5?urlExpires=2022-11-24T15%3A31%3A48.5125848Z&urlSigningMethod=HMACV1&urlSignature=ijfBRodz0%2FlGqMcPz3vwUYkLYFkU8vHeE2Lp2boZ2gk%3D

* prepare to analyze outline info (table of content) at buildtime

* tweak windows test ci

* improve test-setup

* fix ssr on windows

* fix typo

* outline info render

* chore: publish alpha

* fix outline render

* improve demo

* chore: publish alpha

* fix import error in cjs env

* chore: publish alpha

* simplify demos

* upgrade antd to 5.x

* tweak demo

* chore: publish alpha

* fix theme style

* chore: publish alpha

* fix test

* improve search

* fix anchor link when using hash router

* chore: publish alpha

* fix ts error

* chore: publish alpha

* fix build

* chore: publish alpha

* fix import allPagesOutlines

* chore: publish alpha

* fix build

* fix ci

* fix anchor link scroll

* improve demos

* chore: publish alpha

* fix cleanStaticData

* OutlineInfoModuleManager should skip update it outline info didn't changed

* headings (outlines) update should trigger hmr hot update instead of full reload

* chore: publish alpha

* make hmr works with mdx files

workaround this issue: vitejs/vite-plugin-react#38

* don't show loading state when:
- User navigates back to a loaded page.
- Hmr update during dev.

* improve file names

* fix path

* fix hydration layout change

* chore: publish alpha

* better name

* update jotai and remove local copy

* bundle client modules to reduce browser request during dev and avoid conflict npm package with users

* update pnpm lock

* jotai provider-less mode

* experiment

* chore: publish alpha

* don't need to build client with tsc; cleanup

* update deps

* fix ts error

* adapt to vite-plugin-react 3.0 breaking change: no longer do jsx transform to .md files

* upgrade playwright test

* chore: publish alpha

* fix warning of useLayoutEffect during ssr

* fix react warning

* publish alpha

* cleanup setup for doc

* cleanup

* warn for old mdx plugin

* update lock

* make setupPlugins the default export

* update setup

* improve vite setup

* improve vite setup

* update docs

* publish alpha

* prevent search popup scroll with page

* improve mdx setup

* fix outline layout

* improve search popup style on narrow screen

* publish alpha

* add an option to turn off search

* publish alpha

* cleanup deps

* improve antd ssr

* fix ssr hydrate style flash

* publish alpha

* react-pages should not couple on @ant-design/cssinjs

* alpha

* use a rollup plugin to add style import to output bundles

* implement a SSR plugin system to decouple vite-pages ssr from antd ssr steps

* publish alpha

* vite-pages-theme-doc have "type": "module"

* pub

* support ssr plugin to let user hook into the ssr process

* improve ssr plugin

* improve ssr plugin system: no longer need vite plugin

* improve ssr plugin

* fix ssr plugin

* fix outline style

* cleanup

* update deps

* remove vite-plugin-mdx

* fix cleanStaticData

* fix demo

* fix demos

* publish alpha

* update contributing guide

* feat: minify html for ssg mode (#102)

* feat: minify html for ssg

* chore: format

Co-authored-by: 阿良仔 <32487868+cijiugechu@users.noreply.github.com>
@github-actions github-actions bot locked and limited conversation to collaborators Apr 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
4 participants