ionic-team / ionic-docs

https://ionicframework.com/docs
Apache License 2.0
583 stars 3k forks source link

How to use jsdoc for typesafety on Ionic webcomponents #2658

Open Tommertom opened 1 year ago

Tommertom commented 1 year ago

Hi

Currently hitting a wall for the use of Ionic webcomponents in Svelte

I would like to use JSdoc type annotations to have typesafety and completion in the Ide

I reckon these are there but can you add some docs on how to use these for all and/or individual components?

Example https://dev.to/dakmor/type-safe-web-components-with-jsdoc-4icf

Svelte native wrappers limitations hence this request

Thx

sean-perkins commented 1 year ago

Hello @Tommertom can you elaborate more about what information you are trying to access?

Ionic includes the core.json file in the bundle: https://unpkg.com/@ionic/docs@6.3.8/core.json

This includes the type information we use to generate the individual doc pages.

Is this what you are looking for?

Tommertom commented 1 year ago

Hi @sean-perkins

Thanks for getting back and sorry for my telegram-style message.

Not sure if the background is clear so let me try to give you that.

I am maintaining a Ionic Svelte integration (https://github.com/Tommertom/svelte-ionic-npm) which currently does not enforce typesafety when you are coding. The integration let's you implement Ionic elements in kebab case (so dom elements registered via webcomponents).

So <ion-card> like Angular instead of the Vue/React way <IonCard> etc.

I believe in Angular, we have some sort of typechecking and completion in the kebab way. Angular (or the IDE) will complain if you use an unsupported property and so on (correct, right? has been a while since I developed in Angular).

So <ion-content (ionChange)="doThings()"> will give an error because ionChange does not exist on ion-content

I would like to have the same thing for SvelteKit. And hence I wonder how to do so. I reckon it involves at least two steps: 1-finding/using/generating type annotations (JSDoc I presume), the IDE or a linter can ingest - maybe using core.jons indeed 2-configuring SvelteKit in such a way it uses these globally for the project, so the developer does not need to do type annotations her/himself.

So I was hoping anyone from Ionic can help with 1. Not sure if you can help with 2 - as SvelteKit (Vite?) is not on the roadmap (yet)

I see all sorts of typings generated in core-package which seems like a good start. Now the question is how to connect this with some sort of tsconfig thing - or in vite - etc. (will check if I can find how it is done for Angular).

On a side note-

The core.json is an interesting file. Thx! Especially as for an earlier try, I am parsing Ionic's Stencil code to generate native wrappers. Core.json seems a bit more usefull! So to generate IonContent.svelte etc. That was my original way to create type safety, type ahead and even tree shaking. But that won't fly out-of-the-box as svelte component styles are encapsulated. So now way to pass easily style properties from parent to child.

Hope this makes sense and you have some pointers.

Edit- I thought I wanted to raise this issue at the docs, as it might be something related to informing users on how to do this when using non-supported libraries and bundlers like webpack (or vite)- not an issue for @ionic/core. And there are less issues here - so I guessed higher chance on a response :) :) :)

sean-perkins commented 1 year ago

I believe in Angular, we have some sort of typechecking and completion in the kebab way. Angular (or the IDE) will complain if you use an unsupported property and so on (correct, right? has been a while since I developed in Angular).

Angular has the Angular Language Service (+ the VSCode plugin) which provides type checking to the template. With Ionic, we handle this by creating Angular component wrappers and using a feature in typescript called declaration merging, to effectively apply the web component type to the generated wrapper component class.

I think what you may be looking to need is a custom Stencil output target. However I don't think we have a solid process in place for generating wrappers on code that you don't directly manage. With the Stencil output target you have access to all the compiler metadata that Stencil generates when it is compiling the web component. We use this for generating the Angular, React and Vue component wrappers. We at one time had a community contribution for Svelte output targets, but we decided to remove it from our primary repository at this time, as we do not have the resources or experience to manage this code: https://github.com/ionic-team/stencil-ds-output-targets/pull/300. I recommend the output target over the core.json here, because the core.json only has a subset of that compiler metadata and I don't know if it contains the relationship between complex types, for you to refer to.

Web components have a loose proposal for some custom element manifest that some IDEs will respect (I think VSCode may be one of them). But other IDEs like Webstorm have a completely different syntax that doesn't work with it.

https://custom-elements-manifest.open-wc.org/blog/intro/

This is close to what core.json puts out and with a script you could probably convert what we ship to match that format. Stencil might have built-in support for this with: https://stenciljs.com/docs/docs-vscode, but Ionic Framework does not currently use that or ship that (although with a compelling use case/benefit it wouldn't be that much trouble to include). You could create a fork and try adding that output target to the Stencil config to see if it generates anything that impacts the type checking/intellisense.

I have no exposure to SvelteKit so unfortunately cannot give a strong recommendation on how this ties into that ecosystem. If you can diagnose (or if it is documented) how SvelteKit picks up the types from a Svelte component, we can likely use that information to tie into it.

Tommertom commented 1 year ago

ionic-team/stencil-ds-output-targets#300.

Hi Sean - thx again for this - I looked at the library and interesting to see how the components are generated. Much how I am trying, but in your case a bit fancier logic - :)

There is a fundamental issue with the way this (discarded) output target builds Svelte components. It does not allow (as far as I can see) you to target css custom properties in the most elegant way -namely adding to the component and using the encapsulated CSS magic Svelte has. With this syntax you need to add css custom props to the global style sheet, which is very undesirable. Happy to explain if you are interested.

But the type generator is probably what I need, so I just will figure out how to fork this commit and so on.

Maintainer at Svelte pointed out to me how to integrate typings into Svelte(kit) - https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#im-using-an-attributeevent-on-a-dom-element-and-it-throws-a-type-error . Haven't tested it. Adding here for reference.

Tommertom commented 1 year ago

Got it to work!!! Thx for core.json - that is a real treat. Still some stuff to fix - like adding to doc-text per prop in the IDE tooltips

But easily generated the svelte-typings:

// generated typings
declare namespace svelte.JSX {

  interface IntrinsicElements {

    'ion-accordion': {

      /*
      ** @property {boolean} disabled -  If `true`, the accordion cannot be interacted with.
      */
      "disabled"?: boolean;

      /*
      ** @property {"ios" | "md"} mode -  The mode determines which platform styles to use.
      */
      "mode"?: "ios" | "md";

      /*
      ** @property {boolean} readonly -  If `true`, the accordion cannot be interacted with, but does not alter the opacity.
      */
      "readonly"?: boolean;

      /*
      ** @property {string} toggleIcon -  The toggle icon to use. This icon will be rotated when the accordion is expanded or collapsed.
      */
      "toggleIcon"?: string;

      /*
      ** @property {"end" | "start"} toggleIconSlot -  The slot inside of `ion-item` to place the toggle icon. Defaults to `'end'`.
      */
      "toggleIconSlot"?: "end" | "start";

      /*
      ** @property {string} value -  The value of the accordion. Defaults to an autogenerated value.
      */
      "value"?: string;
    }