-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
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
Establish a standard way to document component and its props #7186
Comments
Wouldn't it be more interesting to add props: {
width: {
type: Number,
description: 'Width of the modal'
}
} Libs usually use the object syntax already As long as it can be stripped off from build productions, I think it could be nice to add something like this. But maybe prepending those attributes with a special character could be even better, something like |
Does this have to be part of the component options / API? It seems they don't serve any particular purpose for Vue's own runtime behavior. In that case, would a comment-based syntax be more reasonable (as it is stripped by default)? Using a component option would require extra toolchain changes to properly strip them. |
Is it possible to read comments with the language server? 😮 |
Hey. For specific BootstrapVue we needed component typings from a long time ago. The first iteration was exactly using component's runtime instance to extract props and auto-generating documentation. Here is componentdoc.vue implementation. PROS:
CONS:
So we added a custom meta descriptor for components inside Both of above methods are both used for our nuxt based docs and also for generate-vetur-helpers.js (Written by @alexsasharegan) Maybe we can unify metadata structure which is used by BV, Onesen and Vuetify and hand-craft or auto-generate meta for any component library in either This way, just like any other part of Vue's ecosystem tooling can be delegated to library authors. We may also provide some helpers making the process easier and not forcing to use specific syntax like JSDocs. ( {
"vue": {
"library": true,
"components": [
{
"name": "b-table" // Use for hinting of <b-table> tags
"props": [
{
name: "title",
type: "Boolean",
description: "Table title"
}
],
}
],
directives: [
// ....
]
}
} |
Something cool I've discovered so far is Project polymer's component documentation spec. They have a nice CLI which analyzes components JSDocs and extracting meta json: polymer analyze > analysis.json Then using a similar component like our |
It would be great t have vue-language-server parse the JSDoc inside the components 😄 |
I disagree. I can imagine a lot of cases where Vue's warnings and devtools could be improved by this extra information. Here are some examples.
Yes, but I think the changes would be quite simple, since we're already manipulating the options exported from SFCs. It's possible there's a complexity I'm not realizing though, so please correct me if that's the case. @pi0 I'd really like to avoid having to manage a separate types file, as I find these can fall out of date very quickly when their accuracy is not enforced by a compiler. Plus, remembering to check another file every time you want to update a component is pretty significant cognitive overhead. |
@chrisvfritz SFCs only manipulate the options at runtime, so all the big description strings will be included in the bundle and cannot be minified. They can only be dropped with a special babel plugin or hacked buble transform. |
It won't be easy, but it's possible, since TypeScript server supports analysis of JSDoc.
I agree with @chrisvfritz -- one of the strength of Vue SFC is a sensible way of organizing related information by colocating html/css/js. It'd be very un-vue-like to put this component specific information to some centralized place. The idea is to make it possible to write components that's self-documenting, in the same spirit of JSDoc / JavaDoc / etc. This also helps reading Vue libraries' source code.
👍 This is something we can look into & learn from.
Doesn't have to be, and I agree it doesn't help runtime and would be a bloat for code size. It has to be compiled away at build time. However, after thinking through this, I think JSDoc might be a better approach. Another idea is to make this a custom block in SFC like so (chose yaml since it looks cleanest)
For libraries that's using js components, they can convert to this format by putting their js file into a As I mentioned this info can be used by Vetur, component doc generator, etc for better DX, but it can go beyond that. One example is ElementUI's https://github.com/ElementUI/element-helper-json/blob/master/element-tags.json#L4 {
"el-row": {
"attributes": ["gutter", "type", "justify", "align", "tag"],
"subtags": ["el-col"],
"description": "A row in grid system"
}
} We can just use this info to enhance |
I wrote It supports:
<template>
<label>
<input :disabled="disabled" type="text" v-model="checkbox">
<!-- Default slot comment -->
<slot></slot>
<!-- Use this slot to set the checkbox label -->
<slot name="label">Unamed checkbox</slot>
</label>
</template>
<script>
/**
* A simple checkbox component
*
* @author Sébastien
*/
export default {
name: 'checkbox',
props: {
/**
* The checkbox model
* @model
*/
value: {
type: Array,
required: true
},
/**
* Initial checkbox value
*/
checked: {
type: Boolean,
default: true
}
},
data () {
return {
initialValue: null
}
},
computed: {
id () {
return `checkbox-${this.initialValue}`
}
},
created () {
/**
* Emit when the component has been loaded
*/
this.$emit('loaded')
},
methods: {
/**
* Check the checbox
*/
check () {
/**
* Event with identifier name
*/
this.$emit('check', true)
}
}
</script> Will generate something like: {
"header": [
{
"entry": {
"name": "checkbox" // The component name
},
// The component description
"comments": [
"A simple checkbox component"
],
// Attached keywords
keywords: [
{ name: "author", "description": "Sébastien" }
]
}
],
"props": [
{
"entry": {
"v-model": {
"type": "Array",
"required": true
}
},
"comments": [
"The checbox model"
]
},
{
"entry": {
"checked": {
"type": "Boolean",
"default": true
}
},
"comments": [
"Initial checbox value"
]
}
],
"data": [
{
"visibility": "public",
"description": null,
"keywords": [],
"value": null,
"name": "initialValue"
}
],
"computed": [
{
"visibility": "public",
"description": null,
"keywords": [],
"value": [Object],
"name": "id",
"dependencies": [
"initialValue"
]
}
],
"slots": [
{
"name": "label",
"comments": [
"Use this slot to set the checkbox label"
]
}
],
"events": [
{
"name": "loaded",
"comments": [
"Emited when the component has been loaded"
]
},
{
"name": "check",
"comments": [
"Event with identifier name"
]
}
],
"methods": [
{
"entry": {
"check": {
"type": "FunctionExpression"
}
},
"comments": [
"Check the checbox"
]
}
]
} |
@yyx990803 Thanks for clarifying. 🙂 I just did a little research to see how difficult a Babel plugin would be and much to my amazement, I accidentally created a working proof-of-concept! 😄 I'm definitely not a Babel expert, so there could be issues with it, but it seemed to work on the 2 codebases I just tested it against without breaking anything. It could even be expanded to strip out other properties not needed in production, like Does this change your thoughts on feasibility at all? |
@octref Just saw this comment. When you say you can't access this information easily, how difficult are you thinking it would be and is there any way I could help explore possibilities? I ask, because I'd personally prefer to avoid JSDoc. We already have some meta information as properties (like component name and prop types) and with comments, we'd lose the ability to use additional information in the Vue's warnings or devtools. As for the custom block, it would solve the 2nd problem assuming Vue's template compiler could parse it into a JavaScript object, but there's still the issue of component meta information being fragmented (some included as a component option, some in a new custom tag). Some other things that bother me about it:
|
@chrisvfritz I was thinking along the line of using TypeScript to extract the data and use it to supplement the html completion, but actually it doesn't have to be this way. We can:
Task 1 and 2 should exist independent of Vetur, so they can also be used for other tools. |
Might want to include non SFC components and functional components (i.e. |
@octref I like the idea of tooling to create a manifest file! Then Vetur, eslint-plugin-vue, and other tooling would never have to worry about parsing that information themselves - but we still have it available for Vue's warnings and devtools. Best of all worlds. 🙂 Having a separate tool like |
@tmorehouse It could be tricky for the Babel plugin to detect non-SFC Vue components, since files unrelated to Vue could export similarly-shaped JS objects. Also, functional components can now exist as |
When generating ES style builds (transpiling to a es directory module structure) there is currently no vue-template compiler that will handle this situation. One shouldn't conclude that every one is using SFCs. We ran into this issue when generating ES module build for Bootstrap-Vue (to allow user's to have better tree shaking), and |
@tmorehouse According to @chrisvfritz idea we can still have both ES style builds and SFCs as the source with custom props. And stripping/extracting those comments using babel during build into meta.json. |
Just as a summary to all of the nice comments until now, Something I think all of us agree on it is that we need a final manifest (Something like @demsking suggested) which can be used for both documentation and IDE hintings. The big questions are where to declare typings and how to extract it. SFCs seems the best place and we can put it inside:
And we've got some possible methods for extracting this manifest:
But IMO if we enforce any combination of above methods, we are still forcing a toolchain and methodology for this task. What if we just agree on a standard manifest structure and let developers make and choose the best tooling? We can then recommend and add support for the best method which is probably PS: Sorry if talking a lot. I'm just little excited about this enhancement 😆 |
I want to add some observations from Vetur's report. Most users use third library as global plugin. E.g. element-ui/bootstrap-vue provide global components. Another problem is how to ship component library. We should support shipping component in SFC format as well as compiled JS. @pi0 has already done an awesome summary. Thanks! |
SFC should be preferred over JS as component render functions are built in two ways now – a javascript function (in browser build) and string concatenation (in SSR build). I'm experimenting with a utility library to define prop validation rules. I'm shimming all utility functions for the production build, then using prepack, extra meta is dropped. I think similar techniques can be used for documentation. Maybe a babel plugin can analyze AST and export meta at compile time. |
I agree with Evan this does not seem to serve any particular purpose. If you want to allow this feature however I like @pi0 idea of adding it inside the prop |
Some time ago, I was interested in creating a Vetur integration with Quasar framework by @rstoenescu (which I delayed as it approaches 0.15 and 1.0). As Quasar is deliberately huge, I toyed a very simple JS-to-Vetur-like JSON converter to make things more sane. From this (brief) experience, my two cents is that, if the community is going to settle on the custom block approach, JS (e.g.
Disconsider this message if this is doable otherwise and I'm missing something. |
On would use a script to generate the JSON file (preferably), based on information pulled out from the library (and possibly other meta files). With source code JSDOC, one would need to pull that info out into some file during build. For component definitions, the actual component definition most likely wouldn't have any description fields for props (as that would greatly bloat the compiled component size with text that is not used at runtime) |
@tmorehouse the JSON files would be generated then, that makes total sense. I do not think it does not answer the issue itself though: establish a standard way to document a component. I believe the question to be more about authoring (writing the code of the) documentation. About the description field of the prop, I agree. The dev documentation should not be available for end users in production. It would needlessly bloat the final package. The use of HTML comments and JSDoc is preferable. |
@elevatebart I think there are two sides to the problem. One is documenting the source code (and I am 100% with you that code should be self documented) and the other is sharing documentation of a compiled library with others. As a tooling author I am more interested in the latter and that's what web-types format aims on providing solution for. Having a common metadata interchange format allows various source code documentation styles, which by their dedicated tooling are compiled into common format and than pulled by various other tools like web documentation creators, validators or IDEs. |
Thank you @piotrtomiak, I completely missed this part of the subject. I cannot help much on the tooling standard as I am not supporting any IDE myself. |
@elevatebart As far as I know, there is no standard ways for documenting source code and every library provider is writing their own generator at the moment. Just 2 weeks ago quasar has merged PR to include web-types (quasarframework/quasar#4749) and the feature should be released soon (dev branch was merged yesterday). Bootstrap-vue and vuetify have opened PRs to generate web-types. On my side I've written a generic generator which extracts information during runtime and combines it with static code analysis (https://github.com/JetBrains/web-types/tree/master/scripts/vue), which is used for extracting web-types for older versions of libraries already published on NPM. There are still some missing pieces of information in the format (e.g. JetBrains/web-types#7) and thanks to reports from the community the format is being improved. Some of WebStorm users are surprisingly generating I am interested on working to support |
Just my humble opinion, but since JSDoc already has ways to generate documentation from comments, I want to experiment just writing JSDoc style comments and then worry about having that comment show up in VSCode later. My question is, does anyone have a recommended way, or ever experiment with prop documentation extraction, if your props has JSDoc comments? export default {
props: {
/**
* The state you want the component to have. Can be 'on' or 'off'.
* @type {'on' | 'off'}
*/
state: {
type: String,
}
}
} I'd love to be able to generate some docs based on the above! |
@mesqueeb have you looked into vue-styleguidist. I believe it does all you want... and more. |
@elevatebart thanks so much !! This is what I was looking for. There are so many links to competing projects here, that all looked very complex! But I must have missed this one. ;) |
I'm in favor of web-types and I've created a feature request in Vetur to consider it (vuejs/vetur#2090). Some comments about the competing JSDoc-based solution: I'm not sure I fully understand the idea of JSDoc-based solution so excuse me if I completely missed the point. |
@rchl good feedback. You did not miss the point at all. QuestionsKeep in mind we are talking about 2 very different subjects here that are often confused.
ArchitectureOne file format does not have to take care of both. Choices - AuthoringOn the choice of formats to author documentation, there are a couple of consideration that will orient your choice:
export default {
props: {
color:{
type: String,
required: true,
docs: {
description: "use this prop to color your button",
examples: "`blue`, `grey`",
deprecated: true
}
}
}
} Choices - UsageChoosing web-types as a standard for the Vue LSP: @znck and @octref are working on a TypeScript plugin for vue 3 that will leverage the Language Server Protocol. I am with you on that last point, I can't wait to know more. |
It looks like the JSDoc approach of documenting components is more or less standarized with Here is a screenshot of documentation popup taking advantage of web-types generated from styleguidist example: |
@piotrtomiak are these popups usable in VSCode as well? |
@mesqueeb VSCode does not have support for "web-types.json", it uses a much more simplified format split into two files. As @rchl has mentioned above he has filed a feature request for Vetur to support web-types - vuejs/vetur#2090. |
Also don't forget that we need a way to access the documentation (in IDE/static analysis) even when using dynamic components, e.g.
which is currently very cumbersome to use (plus it's difficult to apply any form of defensive programming to ensure that we only use existing props). As an alternative we could implement our own wrapper that exposes the same props, but there's also no way to inherit an existing documentation, making integration with third party libraries very painful (and not forward compatible, lacking warnings). |
@scscgit this is a valid point, dynamic component resolution should be working. Are you still talking about adding documentation to the available props/events/slots? If you are talking about the validation of prop types in the IDE this is another story. I believe that most of the time what you want to achieve here should be accomplished with a What do you think? Any good ideas on how to display all the possible props of all the possible components? |
For dynamic components, TS/VueDX would show intersection of props. It's not a good idea to use dynamic components with very different props, either use if/else or a render function. |
Yeah, the set of all possible (dynamic) components may not be known beforehand, but it'd be great if we could cover at least the scenarios when they are constants (and the best case would include inference of actual prop values if they utilize the same conditions as in As the if/else causes a huge duplication of code, especially when using children (and there's sadly no such thing as conditional props), the render function does indeed seem like the best alternative; it's just that it may obviously over-complicate the component (and sadly can't be done "inline" within an existing template). Well, it'd be way easier for us if we could use v-if on parents that share the same child. I don't know the details of integration between VueDX and tools like Vetur, so if it already supports showing intersection of props, is there any DX-oriented guide for new users about the currently "best" options of setting up the project (possibly including further static/dynamic analysis, considering that Vue silently ignores so many problems even with eslint)? Searching for setup recommendations currently feels very random (including this lack of consensus on documentation, which especially hurts new library authors), and that's even if one starts on Nuxt.js, so maybe some hints could be back-integrated into official articles. |
@scscgit it would probably be awesome indeed, but very complicated. I believe @znck VueDX does this already. I insist though. If you want your code to be readable by noobs and newcomers, you should avoid using |
@elevatebart I agree that Still, it feels like overkill if every time you make a small change requiring changing component you risk having to create a new component, re-document all props and duplicate them (using
|
Is vue storybook basically the most developed option for users needing this on a per-project basis? Vue styleguidist looks ok but it doesn't seem like the documentation lives as close to the component as with storybook. |
@travis5491811 I invite you to try styleguidist if the proximity of the docs is important to you. The SFC model of styleguidist contains a docs block with all the needed examples. <template functional>
<!-- @prop {string} id name attribute of the button -->
<button :name="props.id" style="background: pink;">
<!-- @slot name of the button -->
<slot />
</button>
</template>
<docs>
Document your functional templates in docs blocks
```vue
<FunctionalButton id="test">
In the docs block
</FunctionalButton>
```
</docs> |
Thanks for the link @elevatebart. Proximity is important but id also like the ability to easily test different states of my components or show (through code and interactivity) how they work with different props. I don't see how to do that with styleguidist. However, assuming the following are my goals when documenting components:
Are you able to accomplish all those with styleguidist? From the docs and examples i can see you can do 1, 2, 3, 5, and 6. |
For anybody interested, there is a interesting video on this topic from Vue Mastery here Component Documentation Made Easy by Bart Ledoux | VueConf US 2020 |
Hey @travis5491811, I love it !!
|
Thanks @elevatebart for the feedback and I'm glad that video will reach more people. I noticed the
Is the library mainly geared toward I am still trying to get styleguidist working with |
very cool! |
What problem does this feature solve?
vuejs/vetur#276
Currently, Vetur offers auto-completion & hover info for custom components defined in ElementUI, OnsenUI and Bootstrap-Vue. However, hand-maintaining such json files seem to be a lot of work. Also not co-locating the doc and the component definition can make updating component challenging.
Helper-json repos at:
This feature makes it possible to write the doc in the SFC / js component file, and auto-generate a helper json that can be used for enhancing editing experience or auto-generating API / doc website.
What does the proposed API look like?
Two more optional attributes on the default export:
I was thinking maybe using a custom block for it, but then that only applies to SFC, not js components. jsdoc might be another option.
Other ideas welcome.
Another idea is similar to the
typings
in package.json, have avueTypings
for component libraries. It'll point to the generated helper-json file and editors could pick it up to enhance editing experience./cc
@Leopoldthecoder for ElementUI
@masahirotanaka for OnsenUI
@pi0 for Bootstrap-Vue
@rstoenescu for Quasar
@johnleider for Vuetify
Would you be interested in using this feature in the Vue component libraries that you are maintaining? Would you be interested in helping spec'ing a format for the generated json file and the editing experiences that should be enabled by using that file?
The text was updated successfully, but these errors were encountered: