Closed yankeeinlondon closed 1 year ago
There is one limitation that will be hard to get around with a RegEx approach -- though this is a problem today too -- and that's in the rare case that you have VueJS component recursion. For instance you have a component which has itself in it's interior scope. This is pretty rare but it starts to make RegEx look like the wrong tool and instead require something like AST.
Thanks for the report! Sorry I think I'm still not getting the issue here. If I paste in:
```vue
<p-table>
<template #name="{ row }">
{{ row.name }}
</template>
<template #age="{ row }">
{{ row.age }}
</template>
</p-table>
```
To the markdown file, it looks like working fine. What is the problem here?
Sorry i must have done a really poor job describing things. You're just wrapping code into a code fence! I am talking about USING CODE.
Imagine the following markdown:
\`\`\`html
<p-table class="rounded-lg overflow-hidden body-text-blue-800"
:rows="[{ id: 1, name: 'Joe', age: 23 }, {id: 2, name: 'Sandy', age: 33}]"
:columns="[{id: 'name', name: 'Name'}, {id: 'age', name: 'Age'}]" >
<template #name="{ row }">
{{ row.name }}
</template>
<template #age="{ row }">
{{ row.age }}
</template>
</p-table>
\`\`\`
<p-table class="rounded-lg overflow-hidden body-text-blue-800"
:rows="[{ id: 1, name: 'Joe', age: 23 }, {id: 2, name: 'Sandy', age: 33}]"
:columns="[{id: 'name', name: 'Name'}, {id: 'age', name: 'Age'}]" >
<template #name="{ row }">
{{ row.name }}
</template>
<template #age="{ row }">
{{ row.age }}
</template>
</p-table>
the first block is in a code fence and is demonstrating to the user what you can do with the component, the lower part is showing what that code actually does.
There is zero problem with Vite/Vuepress presenting code blocks but you'll find actually trying to run the component will fail for almost any slot content (especially if it's beyond the default slot).
I have already fixed this by hacking Vitepress's code to give me the markdown
config option (as I understand there will be an updated release of Vitepress soon which fixes this formally) and this allows me to redefine the markdown-it rule externally to Vitepress but this really is a glaring issue for a solution like Vite/Vuepress and I feel it is better addressed with a PR.
The power of Vite/Vuepress has been quite limited by this restriction since inception but it could quite quickly become a Storybook killer for Vue users but this kind of functionality is critical. I have seen people posting questions about this for two years WRT to Vuepress but never had the time to dig into it. I now fully understand it and it is pretty easily addressed for the 2 of the 3 use cases I mention.
@kiaking can you let me know when the next Vitepress release will be completed? as discussed I have already done this locally in a repo but it's fragile to yarn update
and would like to be able to rely on the Markdown extension foundation so I can focus on this issue (which I need at the very least via the extension mechanism but ideally ends up as a PR). Alternatively if this Vitepress fix is not actually done yet, i can just send you a PR if you'll accept it. I need this done today so I'll have to fork soon if it's not actually coming.
it appears that
@master
is not building right now due to a type conflict between Vite and Vitepress ... is there a different branch I can build locally for now? Nevermind, i fixed this typing issue locally.
@kiaking I have solved 2 of the 3 use-cases now in what I feel is a graceful solution. I will create a short video to describe it. In the final use case, I will have to dig into the markdown-it a bit more to understand what my target should be but the "tools" are now in place to achieve it once I understand what markdown-it needs a bit better.
As I mentioned in a reply to an earlier issue, slots are usable in markdown, but you have to leave empty lines at the start and end of your slotted content and it is also true that you cannot use the # shorthand for named slots (I have a PR open to add this to the VuePress docs).
@ksnyde if you can get it to "just work" without needing to know about these gotchas that would be awesome!
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.
Nice, looking forward to the plugin! It should be really helpful yes.
Maybe this is off topic, if so I'm sorry! I just assume a "Layout" is also some kind of "Component"..
I tried to "reference" a named slot (sample) in Markdown using a custom Layout:
<template>
<Content />
<hr />
<slot name="sample" />
</template>
# Hello
<template slot="sample">
World!
</template>
or:
# Hello
::: slot sample
World!
:::
But both seem not to result in what I'd expect (slot content rendered below horizontal ruler). Instead in the first case using "template" it's written to the DOM (above hr) but not displayed in the browser.
In the latter cases it just gets rendered to the DOM at the end of the "Content" place (so no slot usage either).
Is this the intended behavior? What am I missing? I scanned the VitePress documentation, there the documentation about Slots was pointing to the VuePress documentation, which ought to be this ":::" syntax thingy..
Is it not possible to reference a slot from within a MarkDown? Do I have to write some "vue page" using the corresponding slots in a "Layout"? I'd be very happy to enhance the documentation as soon as I understand how this magic would work :)
The first example is close to being right, you should try:
<template v-slot:sample>
World!
</template>
This is just per the docs on named slots.
Ah yes, as per the vue documentation? right, I believe I also tried this but forgot to re-do and capture results for my above comment. I tried it right now again and upon accessing the application, I receive following on the console:
08:00:40 [vite] Internal server error: Codegen node is missing for element/if/for node. Apply appropriate transforms first.
Plugin: vite:vue
File: [...]/docs/index.md
I'm unsure on how to debug this error, as the error message is not helpful for me. I mean I have basically no idea, what I'm doing anyways :)
I am trying to use "windicss" in combination with vitepress according to https://github.com/seonglae/windipress maybe something is wrongly configured? does vite.config.ts and windi.config.ts really belong into the "docs" folder?
Could you add to the documentation, that the named slots shorthand is not supported? At least until a more robust solution is developed?
This just cost me quite a bit of time, due to confusing error messages.. ;)
OK so if you wrap slot item with element, it works.
<!-- WORKS -->
<MyComponent>
<p>Hello</p>
</MyComponent>
But not if you don't have element wrapping.
<!-- NOPE -->
<MyComponent>
Hello
</MyComponent>
Seems like the later one is being processed by markdown parser...? Not sure.
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.
Hi! I guess this was fixed by #665. Can someone try this on latest VitePress release and see if it works?
Okay so if I have a component (BaseLayout
) like this:
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
Then I am able to do this inside my markdown without any errors:
<BaseLayout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template #default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
Here's some contact info
</template>
</BaseLayout>
<script setup>
import BaseLayout from './BaseLayout.vue'
</script>
Closing this for now, let us know if there is still some issue.
I tried using markdown instead of html in the md file (as below)
<BaseLayout>
<template v-slot:header>
# This won't show as a heading
</template>
<template #default>
# But this will
</template>
<template #footer>
## but this won't
</template>
</BaseLayout>
Is this the expected behaviour?
https://stackblitz.com/edit/github-zbjrsg-czuw6p?file=package.json,index.md,BaseLayout.vue
Is this the expected behaviour?
- ensure that there's an empty line above & below the markdown content
@akil-rails Yes. It's part of the CommonMark Spec: https://spec.commonmark.org/current/#html-blocks
- do not indent more than 2 spaces
Yes. It'll be treated like indented code blocks: https://spec.commonmark.org/current/#indented-code-blocks
Thank you !
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 theHTML_SEQUENCES
symbol (some lines removed for brevity):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: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:
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 aleft
andright
slot and allows authors to more readily leverage their horizontal space.Imagine the following:
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:
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:
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:In all likelihood this last option should be done as an optional second step.