mdx-js / mdx

Markdown for the component era
https://mdxjs.com
MIT License
17.78k stars 1.14k forks source link

Vue Support #238

Closed brennj closed 4 years ago

brennj commented 6 years ago

Hey guys, I'm in love with this library. Its super cool and easy to use. I use Vue in my day job, and I would really love to be able to write some component docs with this, because as far as I know - there is nothing in the Vue world for this, even though we have JSX.

I think its because of the differences that Vue needs, in comparison to being able to define a functional React component that makes it slightly non-trivial? I'm rusty with my parsers, so not sure how another layer of abstraction ontop of parsing with deciding to use a JSX outputter is.

i.e.

export default {
  render() {
    return <div>Hello World</div>;
  }
};

in comparison to:

const MyComponent = () => <div>Hello World</div>

I miss React. :) Would love to understand whether it was possible or not.

Thanks guys!

silvenon commented 6 years ago

I have zero experience with Vue, but MDX has a compilers option which is an array of processors that operate on JSX. Maybe you could add a custom one there which modifies the final JSX output into something Vue-friendly?

What would really help is if you could take a look at JSX that MDX outputs and outline which changes in that JSX would be necessary for it to work in Vue.

brennj commented 6 years ago

I'm having a look into it @silvenon! As far as I understand theres a few tasks:

  1. Make compatible MDXTag and MDXProvider Vue components (I've worked on this today over at https://github.com/brennj/mdx/tree/vue-plugin ! I've written some tests to match the React side and looks good so far, maybe)
  2. Like you say, pass a custom compiler that will change the following code:
export default ({components, ...props}) => <MDXTag name="wrapper"  components={components}><MDXTag name="p" components={components}>{`Hello World!`}</MDXTag></MDXTag>

into Vue friendly code. I'm still trying to figure this bit out as theres some specific React parts in the loader and stuff but I think it should be fairly fine. I might see how far I can get and offer up a PR if I'm happy with it :)

brennj commented 6 years ago
screen shot 2018-08-26 at 23 18 33

The markdown file:

import Test from './Test.vue';

# Hello World!

This is great!
_No React here!_

<Test />

Really enjoyed this! Surprised it works!!

I'm exhausted so won't get the PR just today - will do during the week, but basically the API I have proposed will look like this:

const { VueJSXCompiler } = require('@mdx-js/vue-plugin-mdx');
....
    module: {
      rules: [
        ...
        {
          test: /.mdx?$/,
          use: ['babel-loader', {
            loader: '@mdx-js/loader',
            options: {
              compilers: [VueJSXCompiler]
            }
          }],
        }
      ]
    }

So it means that a new package called @mdx-js/vue-plugin-mdx would be added. Theres also some knowledge of it in the loader in order to know whether to render Vue stuff or React stuff.

I'll need to look at the code with fresh eyes during the week before I open the PR. I'm sure I've duplicated one too many things.

johno commented 5 years ago

I have a PR open (https://github.com/mdx-js/mdx/pull/455) that gets us a lot of the way there thanks to the fine work of @brennj.

I'm currently stuck on the way Vue handles element creation (I've never really used it before 🙃). I've created the custom pragma function for Vue to receive the type and props which is happening as expected. But, for whatever reason I can't seem to get it to render.

If anyone wants to tinker around in that branch there's a directory (examples/vue) you can get running and then edit packages/vue/create-element.js. Would love any insights as to what I'm doing wrong.

ChristopherBiscardi commented 5 years ago

A working createElement (and related code) is merged into #455

callumflack commented 5 years ago

A vanilla install from the MDX Vue example fails with:

image

johno commented 4 years ago

A new Vue beta is now shipped in the latest version of MDX thanks to @codebender828! 🎉

calaoa commented 4 years ago

Hi everybody, Would anyone have a pointer at a working example on how to embed a Vue component into a Markdown file? As far as I understand, @mdx-js/vue allows to expose a Markdown file as a Vue component, but how to achieve the other way round (it seems the vue-plugin-mdx by @brennj does not exist as such anymore), that is for instance, as mentioned above:

import Test from './Test.vue';

# Hello World!

<Test />
codebender828 commented 4 years ago

Hey @calaoa ! Yes it's possible to consume Vue components in your MDX files. You'd need to consume it as JSX in your MDX file.

Here's an example of how consume Vue components in MDX files.

(This is an old demo but works. I made this when I was working on adding support for Vue.js. All functionality is already added to the MDX package.) Demo: https://mdx-vue.now.sh/

calaoa commented 4 years ago

Thanks a lot @codebender828! Meantime I just noticed that @mdx-js/examples/vue is showcasing an example along this line as well. Quite powerful... Now wondering how to load mdx files dynamically into a Vue app without the need to hardcode any mdx file import into the source code, a bit like what @nuxt/content offers (see the first demo video illustrating a Markdown file calling a Vue component as far as I understand)...

callumflack commented 4 years ago

@calaoa I'm excited about @nuxt/content — what was your experience like? Interested to know your thoughts comparing it to MDX + Vue.

calaoa commented 4 years ago

Hey @callumflack, @nuxt/content looks very appealing indeed, however there's two things I'm not fond of so far with it (a plugin could come into play for the first one I guess, I need to experiment further):

(Hopefully not hijacking the thread too much… MDX + Vue opens so many paths… E.g. something like Jupyter with an MDX-Vue-Node-Git stack… A route I'm humbly exploring with Babouk…)

calaoa commented 4 years ago

For what it's worth, I actually achieved the usage of Vue components 'within' (sort of) Markdown by using v-runtime-template👏 coupled with remark-rehype (and other remark's👏): Markdown gets transformed to HTML, then the embedded Vue tags are made executable by v-runtime-template (provided the Vue displaying the result imports the components declared in the Markdown, which can be made dynamic as well via Vue async components👏). Eventually nothing involving MDX here yet (possible follow up though), sorry for the noise.

callumflack commented 4 years ago

Thanks @calaoa — I see your digital garden fascination! I've got similar interests. Markdown + components can mean rich, interactive "gardening" w/o being tied to a platform. I hope people like you can make new information systems with these tools. As such, it's a good thing to converse about them here.