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

Recommended way to use Custom Vue components in .md #157

Closed
patak-dev opened this issue Nov 26, 2020 · 10 comments
Closed

Recommended way to use Custom Vue components in .md #157

patak-dev opened this issue Nov 26, 2020 · 10 comments
Labels
docs Improvements or additions to documentation enhancement New feature or request

Comments

@patak-dev
Copy link
Member

I am looking into porting the using vue in Markdown from vuepress:
https://vuepress.vuejs.org/guide/using-vue.html

If I understand correctly, vitepress doesn't want to auto register components by convention as Vuepress does. Is this the case? I actually liked this feature, but I understand that vitepress wants to keep the moving parts as small as possible.

What is the recommended way to register the components? I see that in vue-router-next docs they are registered globally inside enhanceApp: https://github.com/vuejs/vue-router-next/search?q=HomeSponsors.
Same as with this comment: #92 (comment)

Should we document this way in the docs?

Some thoughts about this. It would be great that users that want to use the default theme as is, do not need to learn straight away about enhanceApp to be able to use a vue component in their markdown.

If auto registering by convention in a folder like .vitepress/components is not an option, could we import them directly in the markdown?

# Docs

This is a .md using a custom component

<CustomComponent />

## More docs

...

<script setup>
  import CustomComponent from '../components/CustomComponent.vue'
</script>

Script & style hoisting is working in vitepress: https://vuepress.vuejs.org/guide/using-vue.html#script-style-hoisting, but I tried this example to import a Component and it is not at this point.

@kiaking kiaking added docs Improvements or additions to documentation enhancement New feature or request labels Nov 27, 2020
@kiaking
Copy link
Member

kiaking commented Nov 27, 2020

If I understand correctly, vitepress doesn't want to auto register components by convention as Vuepress does. Is this the case?

Yes, at the moment it's. This is a kind of feature that we would want to tell users to use VuePress instead.

A little background on this. It might subject to change in the future, but for now, VitePress is aiming to be smaller VuePress. Like Lumen for Laravel (if you're familiar with PHP 👀). VitePress should have bare minimal features for authoring docs, and for simple markdown based build system for Vue, and all necessary features like Search, Service Workers, built in to the core, where else VuePress has those features enabled by plugins. That's reason why we're merging features like Carbon Ads.

And also to note, VuePress might integrate with Vite in the future. So that user can get benefits from Vite, with all the powerful features in VuePress (we should consider the naming though 😅).

However, maybe we could provide a script that traverse file system and auto include components inside .vitepress/theme/index.js (not sure if possible yet), then add that as a recipe in the docs.

What is the recommended way to register the components? I see that in vue-router-next docs they are registered globally inside enhanceApp

Yes, this is the way to go about it. However, I would really like to make this customization process much more smoother. Currently, creating a whole new theme, is easy but extending the default theme is painful. You have to import theme from vitepress/dist/theme-default and such.

So yes, we should document this, but before doing that I want to rethink, and refactor how to do the customization. So I guess we can use this issue to discuss about it!

Here's what I'm thinking, but not 100% sure yet.

Create brand new theme

export default {
  Layout: CustomLayout,
  NotFound: CustomNotFound,
  enhanceApp({ app, router, siteData }) {}
}

Very well. Easy. Good enough.

Only adding components

import Theme from 'vitepress/dist/client/theme' // <- rename to theme instead of default-theme
import CustomComponent from './components/CustomComponent.vue'

export default {
  ...Theme,
  enhanceApp({ app, router, siteData }) {
    app.component('CustomComponent', CustomComponent)
  }
}

I don't like 'vitepress/dist/client/theme' path... but... hmmm....

Extending default theme layout

import 'vitepress/dist/client/styles' // import global css

import NotFound from 'vitepress/dist/client/theme/NotFound.vue' // Use default NotFound component.
import Layout from './components/Layout.vue' // Use your own layout

export default {
  Layout,
  NotFound,
  enhanceApp({ app, router, siteData }) {
    app.component('CustomComponent', CustomComponent)
  }
}

And in Layout.vue

<template>
  <Layout>
    <!-- Inject something to slot -->
    <template #page-top>
      <p>Hello page top!</p>
    </template>
  </Layout>
</template>

<script setup>
import Layout from 'vitepress/dist/client/theme/Layout.vue'
</script>

I guess simple enough? Importing global CSS is not that... hmmm...

@patak-dev
Copy link
Member Author

And also to note, VuePress might integrate with Vite in the future. So that user can get benefits from Vite, with all the powerful features in VuePress (we should consider the naming though 😅).

So using Vite instead in VuePress, and not extending VitePress? Interesting, there could be a lot of duplication in that case 🤔

However, maybe we could provide a script that traverse file system and auto include components inside .vitepress/theme/index.js (not sure if possible yet), then add that as a recipe in the docs.

I like this, if you place it in the theme, you are not polluting the tool. Maybe it can be a config for the theme? Something like:

  themeConfig: {
    ...,
    components: './docs/components' // defaults to none
  }

(Or componentsDir, globalComponents)

+1 for renaming default-theme to theme.

For the paths, it would be great if we could tell users to just use something like the code uses internally

import Theme from '/@theme'

@patak-dev
Copy link
Member Author

Two ideas about importing the theme, sorry if this was discussed already.

  1. Move the default theme to its own package. So users would import it like
import { Theme, NotFound } from 'vitepress-docs-theme' 

This may also help to force vitepress to properly expose everything the default theme uses, so other themes can be play at the same level.

  1. Another option would be to provide a new helper enhanceTheme (or enhanceDefaultTheme) that is defined as:
function enhanceTheme(enhanceApp,custom) {
  import('../client/styles') // (can we do something like this?)
  return {
    ...Theme,
    ...custom,
    enhanceApp
  }
}

So your examples can be written as

Only adding components

import CustomComponent from './components/CustomComponent.vue'

export default enhanceTheme(
  ({ app, router, siteData }) => {
    app.component('CustomComponent', CustomComponent)
  }
)

And Extending default theme layout

import Layout from './components/Layout.vue' // Use your own layout

export default enhanceTheme(
  ({ app, router, siteData }) => {
    app.component('CustomComponent', CustomComponent)
  }, 
  { Layout }
)

@yyx990803
Copy link
Member

FWIW, adding this in .md file should already work:

<script setup>
  import CustomComponent from '../components/CustomComponent.vue'
</script>

@patak-dev
Copy link
Member Author

I just tested it and works fine 👍
I think I tried it before vue 3.0.3, my bad, and that is why it wasn't working.

In my opinion, importing the components you use on a page directly in the .md is quite nice. At least for one-of components (like examples, playgrounds, etc).
It would be interesting to document this in the use Vue in markdown guide.

For components like or a that you end up using everywhere across your docs, there should still be an easy way to register global components.

@harlan-zw
Copy link
Contributor

harlan-zw commented Dec 3, 2020

While you can write HTML directly into the md file, due to the md parsing it becomes almost impossible to do anything which would need any sort of layout.

When trying to get around this issue myself I ended up copying over the entire default theme folder so I could add my custom component to components and setting it up in enhanceApp.

I think it needs to be clear and easy for developers to add a custom component. It seems like it's trending to magically load them in when they're needed(Nuxt.js, Vuetify, etc).

I'm not sure about the performance cost of it but having a configurable components folder in .vitepress that automatically imported components as you used them, seems like a solid DX improvement.

@yyx990803
Copy link
Member

yyx990803 commented Dec 5, 2020

In the next release you can do

// .vitepress/theme/index.js
import { defaultTheme } from 'vitepress'
import MyGlobalComp from './Comp.vue'

defaultTheme.enhanceApp = ({ app }) => {
  app.component('MyGlobalComp', MyGlobalComp)
}

And yes we can consider auto registering components in a directory as global.

Also not sure what you mean by

due to the md parsing it becomes almost impossible to do anything which would need any sort of layout.

since you can use <script> and <style> in md files just like in an SFC.

@harlan-zw
Copy link
Contributor

harlan-zw commented Dec 5, 2020

Thanks for the reply @yyx990803 and good to know! That would make life easier.

Sorry for not being clear on the markdown parsing. Previously I had an issue using HTML markup within the markdown file, it was rendering out incorrectly (was moving divs around). I've tried to replicate it now but looks like I can't, so was likely an issue on my end.

Irrelevant to this issue either way.

@TheDutchCoder
Copy link

I use the following pattern currently:

// @ts-ignore
const modules = import.meta.globEager('../components/**/*.vue')
const components = []

for (const path in modules) {
  components.push(modules[path].default)
}

export default {
  ...DefaultTheme,
  enhanceApp({ app }) {
    components.forEach(component => {
      app.component(component.name, component)
    })
  }
}

@kiaking
Copy link
Member

kiaking commented May 24, 2022

Closing since this is documented with details 👍

@kiaking kiaking closed this as completed May 24, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
docs Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants