question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proper processing of Vue Component slot content

See original GitHub issue

Describe the bug/feature

In both Vitepress and Vuepress the way in which the Markdown-it rule htmlBlock is implemented is highly subpar. This is particularly true because the primary use-case for both is documentation but currently adding in a VueJS component which takes advantage of slot content tends to break rather quickly. This is because – by default web-components are considered inline components by Markdown (as per the spec). When Markdown encounters inline components it treats the interior scope of the web-component as Markdown content and therefore tends to wreck havoc on slot content.

Looking at the src/node/markdown/plugins/component.ts file you can start to see the problem when looking at the HTML_SEQUENCES symbol (some lines removed for brevity):

// An array of opening and corresponding closing sequences for html tags,
// last argument defines whether it can terminate a paragraph or not
const HTML_SEQUENCES: [RegExp, RegExp, boolean][] = [
  // PascalCase Components
  [/^<[A-Z]/, />/, true],
  // custom elements with hyphens
  [/^<\w+\-/, />/, true],
]

The intent here is to mark the opening and closing of scope for a component but as you can see from the RegEx it is only looking for inline components not block components!

For example, the component p-table has several named slots which help it to render the way the user intends:

<p-table>
  
  <template #name="{ row }">
    {{ row.name }}
  </template>

  <template #age="{ row }">
    {{ row.age }}
  </template>

</p-table>

Put this into the template section of a Vue CLI app and it works just fine. Put it into Vuepress or Vitepress and watch the cloud of smoke start to rise as it fumbles around; particularly failing on the # symbols used as shorthand for named slots. This is particularly troublesome for a documentation site that is trying to document a set of VueJS components! There should be a way to ensure that this VueJS component’s interior scope is left untouched by Markdown-it … at least when that’s what you want.

There is a second use-case that I would expect Vitepress to just handle and that is kind of what it’s doing today but in a hit and miss fashion currently. Let’s say that I just have a default slot in my component and therefore I want my component to be seen by the Markdown engine as being an “inline” component and process the interior as markdown. Great, then the following should work:

<super-sexy>
# some heading
## some sub heading
</super-sexy>

This would just provide some HTML wrapper elements that would in this case make this very dull markdown sexy.

Finally there is a third use-case that really should be considered required too … this is the hybrid but it will allow for all sorts of simple but useful documentation components. The use-case presents as a component that exposes named slots – and therefore is seen by Markdown as a block component – but these named slots are processed by markdown. An obvious example might be a <two-columns> component which provides a left and right slot and allows authors to more readily leverage their horizontal space.

Imagine the following:

<two-columns>

  <template #left>
   I'm a lumberjack and I'm ok
  </template>
  <template #right>
  I sleep all night and I work all day
  </template>

</two-columns>

This will fail miserably today but it could be grand!

** Proposed Solution **

Rework the src/node/markdown/plugins/components.ts file in Vitepress (same change can be applied to Vuepress) to:

  • use more sophisticated RegEx patterns to actually capture BLOCK content not just inline components

  • support two modes of processing for BLOCK VueJS components:

    1. Isolated - the interior scope is not processed as markdown and all registered VueJS components can operate exactly like they would normally do
    2. Parsed - the interior scope is processed as markdown; this will work well for default slots where the interior content is Markdown content
  • the Isolated mode should be seen as the default as it is more powerful and allows components that work outside the context of Vitepress/Vuepress to just work here as well

  • the parsed mode may be popular for components designed strictly for Vitepress and Vuepress and it could be opted into in the HTML template like so:

    <my-crazy-idea parsed>There I was, _there I was_, in the Congo</my-crazy-idea>
    

This solution so far could pretty easily support the first two use cases which is a big step forward. The third use-case would certainly be nice but would need a bit more thought. I could imagine something as simple as adding the md prop to the parent component being used as a means to pass in the Markdownit object into the top-level component so it could chain the rendering into the various named slots:

```html
<my-crazy-idea md>
  <template #left>
    There I was, _there I was_, 
   <template #right>
     I sleep all night and I work all day
   </template>
</my-crazy-idea>
```

In all likelihood this last option should be done as an optional second step.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:23 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
yankeeinlondoncommented, Nov 24, 2020

i should be able to this plus a few more fixes which should be helpful. i will create a plugin first and we can talk about whether we should add into core once that’s done.

1reaction
yankeeinlondoncommented, May 24, 2022

I was looking at this issue because it came into my inbox and then I realized that I started the thread. Ha! Well I do want to get back to this soon. I’ve been working on the vite-plugin-md plugin a lot recently and had intended to slip some fixes in there but to be honest it would be better to do this more globally in ViteJS scope rather than just this plugin.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Slots - Vue.js
Slot Content and Outlet #. We have learned that components can accept props, which can be JavaScript values of any type. But how...
Read more >
All You Need to Know About Slots in Vue.js - Telerik
Learn everything you need to know about using slots in Vue.js to create customizable, reusable components for your apps.
Read more >
Using Component Slots in VueJS — An Overview - ITNEXT
Slots are another way in Vue for a component to inject content into a child component. This does this using template code.
Read more >
How to Use Slots in Vue.js
Slots are very essential when we want to render some data passed from parent to child components. Unlike props, slots have quite a...
Read more >
A Guide to Vue Slots - LearnVue
The best way to organize a slot-based component system is to name your slots. This way you can make sure you're injecting content...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found