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

Establish a standard way to document component and its props #7186

Open
octref opened this issue Dec 5, 2017 · 69 comments
Open

Establish a standard way to document component and its props #7186

octref opened this issue Dec 5, 2017 · 69 comments

Comments

@octref
Copy link
Member

octref commented Dec 5, 2017

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:

export default {
  name: 'v-card',
  description: 'A card component',
  props: ['width', 'height'],
  propsDescription: [
    'width of the rendered card component',
    'height of the rendered card component'
  ]
}

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 a vueTypings 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?

@posva
Copy link
Member

posva commented Dec 5, 2017

Wouldn't it be more interesting to add description to the props:

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 '#description' or $description to clearly make the distinction

@yyx990803
Copy link
Member

yyx990803 commented Dec 5, 2017

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.

@yyx990803 yyx990803 reopened this Dec 5, 2017
@posva
Copy link
Member

posva commented Dec 5, 2017

Is it possible to read comments with the language server? 😮

@pi0
Copy link
Contributor

pi0 commented Dec 5, 2017

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:

  • Doesn't adds any extra bytes to runtime
  • General purpose and can be used to document any type of Vue components on the fly even at runtime.
  • Can be used for both SFCs and JS components.

CONS:

  • Can not add any custom description for each prop (If we add additional description field to props it costs lots of unneeded runtime comments)
  • Custom slots and events not supported

So we added a custom meta descriptor for components inside package.json which can be used for making a full set of docs and hintings. (Example)

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 package.json or vue.json file.

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-xxx/package.json or vue-xxx/vue.json)

{
  "vue": {
     "library": true,
     "components": [
         {
             "name": "b-table" // Use for hinting of <b-table> tags
             "props": [  
                 {
                   name: "title",
                   type: "Boolean",
                   description: "Table title"
                 }
             ],
          }
     ],
     directives: [
       // ....
     ]
  }
}

/CC @tmorehouse @egoist @mosinve @alexsasharegan

@pi0
Copy link
Contributor

pi0 commented Dec 5, 2017

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 ComponentDoc we can use iron-component-page to visually render the docs. or exporting Via package.json for vue-language-server usage.

@Akryum
Copy link
Member

Akryum commented Dec 5, 2017

It would be great t have vue-language-server parse the JSDoc inside the components 😄

@chrisvfritz
Copy link
Contributor

@yyx990803

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)?

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.

Using a component option would require extra toolchain changes to properly strip them.

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.

@yyx990803
Copy link
Member

yyx990803 commented Dec 5, 2017

@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.

@octref
Copy link
Member Author

octref commented Dec 6, 2017

@posva

Is it possible to read comments with the language server? 😮

It won't be easy, but it's possible, since TypeScript server supports analysis of JSDoc.

@pi0

So we added a custom meta descriptor for components inside package.json which can be used for making a full set of docs and hintings.

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.

https://www.polymer-project.org/2.0/docs/tools/documentation

👍 This is something we can look into & learn from.

@yyx990803

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)?

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.
I think it's achievable through babel plugin though.

However, after thinking through this, I think JSDoc might be a better approach.
Either way, I can't have the runtime info easily so I need to parse the script myself and find the descriptions. The parser can be reused in the vue-template-compiler 2.0 redesign: vuejs/vue-component-compiler#28 (comment), where the descriptions go into descriptor.metadata or descriptor.descriptions.

Another idea is to make this a custom block in SFC like so (chose yaml since it looks cleanest)

<script>
export default {
  name: 'v-card',
  props: ['width', 'height']
}
</script>

<description>
description: A card component
props:
  width: width of the rendered card component
  height: height of the rendered card component
</description>

For libraries that's using js components, they can convert to this format by putting their js file into a <script> tag and the extra description info into this custom tag. It can be compiled away in compile time. This also makes it super easy to extract the description data.


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 subtags:

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 eslint-plugin-vue to warn the user, but we can do runtime check too.

@mosinve
Copy link

mosinve commented Dec 6, 2017

I like the idea with custom block, as this pattern already used by some VueJS-ecosystem libraries, like @kazupon vue-i18n . And we sure can easily strip this block away at compile time.

@demsking
Copy link

demsking commented Dec 6, 2017

I wrote @vuedoc/parser to generate SFC doc.

It supports:

  • Extract the component name (from the name field of from the filename)
  • Extract the component description
  • Keywords Support: You can define your own keywords with the @ symbol like @author Sébastien
  • Extract component props
  • Extract component data
  • Extract computed properties with dependencies
  • Extract component events
  • Extract component slots
  • Extract component methods

Sample:

<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"
      ]
    }
  ]
}

@chrisvfritz
Copy link
Contributor

@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 required and validator for props.

Does this change your thoughts on feasibility at all?

@chrisvfritz
Copy link
Contributor

chrisvfritz commented Dec 6, 2017

However, after thinking through this, I think JSDoc might be a better approach.
Either way, I can't have the runtime info easily so I need to parse the script myself and find the descriptions. The parser can be reused in the vue-template-compiler 2.0 redesign: vuejs/vue-component-compiler#28 (comment), where the descriptions go into descriptor.metadata or descriptor.descriptions.

@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:

  • If we use this information in Vue's warnings and devtools, we'll have made those dev features exclusive to SFCs, when they didn't really need to be. If we don't make this meta information exclusive to SFCs, then Vetur would have to learn how to parse it anyway for people who chose not to use the custom block.
  • From an education perspective, I'd personally prefer to avoid introducing a completely new concept in SFCs.

@octref
Copy link
Member Author

octref commented Dec 6, 2017

@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:

  1. Have one independent tool that takes commands such as vue-component-doc ./src/**/*.vue
  2. The tool generates a manifest file
  3. User edit vue files to add documentation
  4. manifest file is regenerated
  5. Vetur reloads the manifest file to enhance html editing

Task 1 and 2 should exist independent of Vetur, so they can also be used for other tools.

@tmorehouse
Copy link

Might want to include non SFC components and functional components (i.e. .js files)

@chrisvfritz
Copy link
Contributor

chrisvfritz commented Dec 6, 2017

@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 vue-component-doc might have some issues though, since having these properties in JavaScript means they could be runtime dependent (e.g. description: myDynamicDescription()). To solve this problem, I wonder if vue-loader could build a manifest file (or perhaps a manifest file per component) at runtime? If we stored these manifest files in a standardized location, then Vetur and other tools would be able to check that location for extra information. As an added bonus, the parsing would be agnostic to syntax (e.g. Babel, TypeScript, CoffeeScript, etc). @yyx990803 Is this remotely possible? 😄 What are your thoughts?

@chrisvfritz
Copy link
Contributor

@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 .vue files as well, so there isn't really a reason not to use SFCs for any kind of component if you're using a build system (which you would be, if you're expecting a Babel plugin to strip out these properties in production).

@tmorehouse
Copy link

tmorehouse commented Dec 6, 2017

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 .vue files were causing SSR errors, due to differences in vue-loader options. So we converted to using render functions instead of .vue files

@pi0
Copy link
Contributor

pi0 commented Dec 6, 2017

@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.

@pi0
Copy link
Contributor

pi0 commented Dec 6, 2017

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:

  • JSDocs / TS
  • A new custom block
  • Inline props (Which will be stripped out when production compiling)

And we've got some possible methods for extracting this manifest:

  • Using vue-language-server to parse .vue files and extract the needed parts
  • Adding support for vue-loader which can extract meta when loading SFCs
  • Making an external CLI tool to do the job
  • Manually Document Components

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 SFCs + vue-loader or something else ...

PS: Sorry if talking a lot. I'm just little excited about this enhancement 😆

@HerringtonDarkholme
Copy link
Member

HerringtonDarkholme commented Dec 7, 2017

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.
It would be hard for Vue-language-server to find all components in a third lib if we don't specify library component manifest. So declaration extraction is also crucial in the spec.

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!

@znck
Copy link
Member

znck commented Dec 8, 2017

Another problem is how to ship component library. We should support shipping component in SFC format as well as compiled JS.

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.

@samayo
Copy link
Contributor

samayo commented Dec 14, 2017

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

@leopiccionia
Copy link

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. export default some object + some import custom logic) seems like a better alternative to structured-text formats (like YAML or JSDoc), due to some use cases where it'll avoid duplication, thus improving maintainability, like the following:

  • Components extending other components;
  • Components sharing common properties.

Disconsider this message if this is doable otherwise and I'm missing something.

@tmorehouse
Copy link

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)

@elevatebart
Copy link
Contributor

@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.

@piotrtomiak
Copy link

@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.

@elevatebart
Copy link
Contributor

Thank you @piotrtomiak, I completely missed this part of the subject.
Since the web-types files would be generated, what script would generate it?
Does an NPM package that compiles web-types already exist?
If it does, do you have an example of the conventions it is using in the sources?

I cannot help much on the tooling standard as I am not supporting any IDE myself.

@piotrtomiak
Copy link

@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 web-types for their own source files to have a better code completion when working with their own components.

I am interested on working to support web-types output format for whatever tool will support the standard Vue components source code documentation.

@mesqueeb
Copy link

mesqueeb commented Apr 30, 2020

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!

@elevatebart
Copy link
Contributor

@mesqueeb have you looked into vue-styleguidist. I believe it does all you want... and more.

Https://vue-styleguidist.github.io

@mesqueeb
Copy link

@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. ;)

@rchl
Copy link

rchl commented Aug 1, 2020

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:
a) the JSDoc comments would have to be stripped on publishing the component as otherwise, the comments would add to component size. So how would a language server (like Vetur) then read that information when all of that would be stripped?
b) if the idea is to parse the JSDoc and include parsed form of it separately on releasing, then those could be as well just transformed into web-types right? Why invent another format?

I'm not sure I fully understand the idea of JSDoc-based solution so excuse me if I completely missed the point.

@elevatebart
Copy link
Contributor

@rchl good feedback.

You did not miss the point at all.

Questions

Keep in mind we are talking about 2 very different subjects here that are often confused.

  1. How documentation is written?
    In extenso, how the author of a component writes the docs for his component.
    Options mentioned above are:

    • JSDoc
    • A separate JSON file
    • a generated TOML object in an additional block
    • additional members added to props like suggested above
  2. How this documentation is consumed?
    id-est, what files are necessary for Vetur and WebStorm or any editor to understand the library the user has imported in his project.
    Options mentioned above are:

    • WebTypes
    • Vetur typings

Architecture

One file format does not have to take care of both.
One does not have to read the components themselves directly.
When we publish a library we could have a build step generating any format we want.

Choices - Authoring

On the choice of formats to author documentation, there are a couple of consideration that will orient your choice:

  • Size of a component file: Since JSDoc can be very verbose with 3 lines for every comment, it can extend the number of lines of a component a lot. If size matters to you JSDoc might not be your thing. Prefer having a separate JSON file.
  • Ease of adoption/learning curve: Explaining to a new developer that he needs to open an extra file when he adds a new prop to you component brings extra friction to documentation, that is most of the time completely ignored. If onboarding new dev is something you do, then you should look at JSDoc instead of JSON.
  • Escaping text: If you are OK using \' instead of ' in the description of your props and do not wish to use markdown, then an additional member in props like below might be a better more readable solution (less verbose, more standard)
    NOTE: this last format can easily be removed in production with a babel plugin. No worries about bloating the final bundle.
export default {
  props: {
    color:{
      type: String,
      required: true,
      docs: { 
        description: "use this prop to color your button",
        examples: "`blue`, `grey`",
        deprecated: true
      }
    }
  }
}

Choices - Usage

Choosing web-types as a standard for the Vue LSP:
@octref was saying above that web-types were more complete therefore more complex than Vetur types format, making web-types a little slower to parse and to maintain.

@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.

@piotrtomiak
Copy link

piotrtomiak commented Aug 17, 2020

It looks like the JSDoc approach of documenting components is more or less standarized with vue-docgen-api package present (thanks to styleguidist project), so I've just added basic support for generating web-types using it - https://www.npmjs.com/package/vue-docgen-web-types . If there are "api" packages available for other documentation options I'll be glad to add generators for them as well.

Here is a screenshot of documentation popup taking advantage of web-types generated from styleguidist example:

vue-styleguidist-web-types-test

@mesqueeb
Copy link

@piotrtomiak are these popups usable in VSCode as well?

@piotrtomiak
Copy link

@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.

@scscgit
Copy link

scscgit commented Jan 5, 2021

Also don't forget that we need a way to access the documentation (in IDE/static analysis) even when using dynamic components, e.g.

<component :is="condition ? 'v-textarea' : 'v-text-field'" any-documented-prop />

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).

@elevatebart
Copy link
Contributor

@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?
-> I do not see a proper way to display it in VSCode or WebStorm without being extremely confusing. TS tried to merge all the definitions and the errors you get are confusing, to say the least.

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 v-if unless you do not know the component you are going to get. I would let aside the dynamic analysis for runtime and focus, for the live documentation, on static components.

What do you think? Any good ideas on how to display all the possible props of all the possible components?

@znck
Copy link
Member

znck commented Jan 5, 2021

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.

@scscgit
Copy link

scscgit commented Jan 5, 2021

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 :is) - and in the worst case, there's always an opportunity to introduce workarounds like some special comment above the <component> tag, in which we'd specify everything we expect (maybe with metadata to for example include/exclude props as required), describing the intention that also validates further refactoring.

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.

@elevatebart
Copy link
Contributor

@scscgit it would probably be awesome indeed, but very complicated.
In short, you would have to deduce the component used from the props passed in order to re-validate the prop types.

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 <component>.
If you already know the components you might want to use and they have exactly the same API, maybe make an intermediary component with a render function that does the mapping. If the 2 are completely different, then you should use a v-if, even if they have one thing (a slot) in common

@scscgit
Copy link

scscgit commented Jan 6, 2021

@elevatebart I agree that <component> doesn't increase readability for newcomers, but it does remove a code duplication, making the long-term maintenance way easier as you don't have to guess by using eyes to make a diff; and you face the same decision of using v-if even in the intermediary component (and it's difficult to document an intention if some aspects don't live in any single place). In any case, the key requirement here would be to be able to inherit (prop) documentation and types from the (proxied) components.

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 v-if), plus make a new render function to insert the child.

  • Thinking about a compromise, maybe in the future we could have one generic component intended specifically for the scenario of switching between components that provide the same props.
    • Though this wouldn't even be very different from being bridged by <component> that would accept a list of props that are "expected to be of the same type` (possibly inferring all props implicitly), and maybe a name of primary component supplying the documentation (but when prop descriptions differ, it could make more sense to display both).

@travis5491811
Copy link

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.

@elevatebart
Copy link
Contributor

elevatebart commented Mar 19, 2021

@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>

Example

Documentation

@travis5491811
Copy link

travis5491811 commented Mar 22, 2021

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:

  1. Ability to document component description, name, props, actions and event.
  2. Ability to document my style guide (typography, css classes, etc)
  3. Ability to display examples of my components in isolation for use when building the component and showcasing it to others.
  4. Ability to interact with my component for testing (example i want to see if i put a date range "from date" newer than "to date") (should i just be using my test suite for this kind of stuff)
  5. Have the documentation live as close to the component as possible so it's more likely to be updated when the component changes.
  6. Be as DRY as possible

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. I don't see how you can do the rest. What is your workflow for automated testing?

@travis5491811
Copy link

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

@elevatebart
Copy link
Contributor

Hey @travis5491811, I love it !!
You just made my day.
You linked my talk about storybook and styleguidist.

  1. SB & VSG use the same library (vue-docgen-api maintained by yours truly) to extract those descriptions. Even WebTypes generation from the WebStorm intelliJ ecosystem use the same lib.
  2. Check out the vue design system example, it shows how to do this quite simply on top of styleguidist. I took the liberty of updating the shell in the home repo of styleguidist since the main vueds is not maintained anymore by the original author. But @viljamis did an incredible job.
  3. These examples are the heart and soul of styleguidist and are meant to document each component with some proper live and editable use cases. I tried to write a simple documentation but any question would help me make it more useful.
  4. For real testing today my opinion is that you should extract the logic from the rendering of your components. This way, you can use node to test your logic and only have examples of the visual parts of your components that you can check at a glance. Cypress.io can help you at this point test and screenshot the components from your styleguide and compare it with previous screenshots or test properties visually.
  5. Component Workbench 101 and my philosophy forever with both Styleguidist and Storybook
  6. That is hard to achieve and can push you into doing some stuff that are impossible to understand. But overall I agree (and my team at cypress is working on solving it).

@travis5491811
Copy link

Thanks @elevatebart for the feedback and I'm glad that video will reach more people.

I noticed the vue design system examples depend on react (first import)

Is the library mainly geared toward react users? Do teams have to know both react and vue to effectively used the systems or is that only if you need to use vue design system, or maybe it's just that the example is not fully for vue?

I am still trying to get styleguidist working with nuxt so i can play with it more in a real project.

@lywufei
Copy link

lywufei commented Feb 16, 2022

Hey @travis5491811, I love it !! You just made my day. You linked my talk about storybook and styleguidist.

  1. SB & VSG use the same library (vue-docgen-api maintained by yours truly) to extract those descriptions. Even WebTypes generation from the WebStorm intelliJ ecosystem use the same lib.
  2. Check out the vue design system example, it shows how to do this quite simply on top of styleguidist. I took the liberty of updating the shell in the home repo of styleguidist since the main vueds is not maintained anymore by the original author. But @viljamis did an incredible job.
  3. These examples are the heart and soul of styleguidist and are meant to document each component with some proper live and editable use cases. I tried to write a simple documentation but any question would help me make it more useful.
  4. For real testing today my opinion is that you should extract the logic from the rendering of your components. This way, you can use node to test your logic and only have examples of the visual parts of your components that you can check at a glance. Cypress.io can help you at this point test and screenshot the components from your styleguide and compare it with previous screenshots or test properties visually.
  5. Component Workbench 101 and my philosophy forever with both Styleguidist and Storybook
  6. That is hard to achieve and can push you into doing some stuff that are impossible to understand. But overall I agree (and my team at cypress is working on solving it).

very cool!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests