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

Support for custom components in mitosis compiler #1303

Open
11 tasks
aminezouari52 opened this issue Nov 22, 2023 · 11 comments
Open
11 tasks

Support for custom components in mitosis compiler #1303

aminezouari52 opened this issue Nov 22, 2023 · 11 comments
Labels
enhancement New feature or request

Comments

@aminezouari52
Copy link

aminezouari52 commented Nov 22, 2023

I am interested in helping provide a feature!

Yes

Which generators are impacted?

  • All
  • Angular
  • HTML
  • Qwik
  • React
  • React-Native
  • Solid
  • Stencil
  • Svelte
  • Vue
  • Web components

What problem does this feature solve?

The feature aims to enable Mitosis compiler, to effectively handle custom components. Currently, the compiler struggles for example with lower-cased component names containing dashes, leading to issues during compilation.

Here is an example of the compilation error

example

What does the proposed API look like?

The proposed API enhancements would involve refining the JSX parser within Mitosis to appropriately recognize and handle custom components. This improvement would ensure that when encountered, these components are preserved as-is in the generated output without undergoing any alterations by the Mitosis compiler.

The API might involve modifications or additions to the parsing logic to accurately identify and handle these custom components during compilation.

Additional Information

No response

@aminezouari52 aminezouari52 added the enhancement New feature or request label Nov 22, 2023
@samijaber
Copy link
Contributor

There are two things that need to be done:

  • Types: I am unsure how to handle this, but the JSX types need to be improved to allow custom components. Or at least, allow a way for the JSX runtime types to be augmented such that the user can manually include their custom components.
  • Parsing: it looks like the main issue is that the JSX parser adds spaces to the component name when it has dashes:

input:

export default function MyComponent(props) {
  return (
    <my-custom-div></my-custom-div>
  );
}

JSON output:

{
  "@type": "@builder.io/mitosis/component",
  "imports": [],
  "exports": {},
  "inputs": [],
  "meta": {},
  "refs": {},
  "state": {},
  "children": [
    {
      "@type": "@builder.io/mitosis/node",
      "name": "my - custom - div",
      "meta": {},
      "scope": {},
      "properties": {},
      "bindings": {},
      "children": []
    }
  ],
  "context": {
    "get": {},
    "set": {}
  },
  "subComponents": [],
  "name": "MyComponent",
  "hooks": {
    "onMount": [],
    "onEvent": []
  }
}

playground link

This is where we grab the name from the parsed AST:

const nodeName = generate(node.openingElement.name).code;

I am unable to see how this introduces spaces in the dash. There might be something else running a transformation on the name fields of Mitosis Nodes before/after this code executes.

Best bet to find the solution for this:

If you are able to take a stab at this, that would be amazing! Otherwise, I will try to whenever I have the time to dedicate to this issue.

@rqzheng2015
Copy link
Contributor

rqzheng2015 commented Dec 10, 2023

Hi @samijaber, I have figured out how to support the web-components in mitosis. Please have a look when you have time, thanks.

Tag name issue

The web component tag name has extra spaces after mitosis transforming, for example. swiper-container becomes swiper - container

Reason

I dig in the code, and found out the tag add wrong spaces after codeProcessorfunction execution.
image
And in deeper levels, it's happening because of the babelTransform code in babel-transform.ts. Babel will consider - as an operator, and automatically add a space before and after it.
image
We could easily reproduce it in babel playground

Fix

We could remove the unnecessary spaces at babelTransformCode function. I have submitted a PR to fix this issue. Please check it here.

@rqzheng2015
Copy link
Contributor

rqzheng2015 commented Dec 10, 2023

Type issue

Also, another issue mentiond above, the type issue of web-components in mitosis, I found out it is caused by developers defining jsxImportSource as @builder.io/mitosis in tsconfig.json. The developers can't extend jsx namespace in tsx file, which is necessary to add ts definiton to custom element in mitosis jsx.
So, we need to find a way to allow JSX tag type definition extendibility in mitosis.

This is a sample code to allow user to use Swiper in JSX, if we have fixed the type issue, it will work out in mitosis tsx.

declare namespace JSX {
  interface IntrinsicElements {
    'swiper-container': any,
    'swiper-slide': any,
}

export default function Swiper(){
  return <swiper-container slides-per-view="3" speed="500" loop="true" css-mode="true">
    <swiper-slide>Slide 1</swiper-slide>
    <swiper-slide>Slide 2</swiper-slide>
    <swiper-slide>Slide 3</swiper-slide>
  </swiper-container>
}

Further details about Swiper element can be read here.

@samijaber
Copy link
Contributor

Tag name issue:

@rqzheng2015 that's awesome, thanks for investigating! I saw your fix to replace() the spaces: I think it should be localized to this codeProcessor logic:

const result = `node.name.contains('-') ? node.name : codeProcessor('dynamic-jsx-elements', json)(node.name, '');

That's because we only want that codeProcessor to run if the node.name value is dynamic JavaScript. Checking for - here should handle most scenarios.

Type issue

Oh, this is actually already possible! You can extend the runtime by putting this in a .d.ts file:

declare module '@builder.io/mitosis/jsx-runtime' {
  declare namespace JSX {
    interface IntrinsicElements {
      'swiper-container': any;
      'swiper-slide': any;
    }
  }
}

We should document it somewhere for clarity. 🤔

@rqzheng2015
Copy link
Contributor

Thanks @samijaber! And I'm gonnna test the new solution you provided asap.

@rqzheng2015
Copy link
Contributor

Hi @samijaber . I've changed the code in codeProcessor like you said, and it successfully solves the jsx tag name space-adding issue.

// plugins/process-code/index.ts
   const result = node.name.includes('-')
        ? node.name
        : codeProcessor('dynamic-jsx-elements', json)(node.name, '');

But now, I met another issue when I set the targets to react or preact. It still throws out the same space-adding issue.
I dig in the code, and found out it's happening because of the processBindinng function in processTagReferences in core/src/react/hepers.ts, used by both targets' generators.
image
And in processBinding function ,it called stripStateAndPropsRefsfunction, and deeper, it called replaceStateIdentifier function, which leads to babelTransformExpression, thus, once again, transformed by babel makes it add spaces in tag name again.
image
So, @samijaber do you have a better way to solve this babel transform issue? I'm afraid there might be somewhere also trigger the babel transform like these two functions that I have not found, which will break the tag name display normally.
I would love to hear from your advice, thanks again.

@rqzheng2015
Copy link
Contributor

Hi @samijaber, one more question, to fix type issue, I have added the ts definition like you said above.

declare module '@builder.io/mitosis/jsx-runtime' {
     namespace JSX {
        interface IntrinsicElements {
            'swiper-container': any;
            'swiper-slide': any;
        }
    }
}

But now I am facing two issues, playground can be seen here

  1. Mitosis project popup eslint warning to ts declaration, which says "Mitosis component files should only contain import declarations, the component itself (in a default export), and type declarations (only-default-function-and-imports)".
  2. After generation, the ts declration is missing in the result.
image How could I have better way to make ts declaration to support `web component`? Please take a look if you have time, thanks.

@samijaber
Copy link
Contributor

@rqzheng2015 for the types issue: what youre showing is a playground-only issue. Mitosis component files .lite.tsx cannot have anything else at the root other than the component itself and certain hooks like useMetadata.

You should add the declare module {} logic in a separate .d.ts file in your project folder, and it will work then.

@samijaber
Copy link
Contributor

@rqzheng2015 thanks for digging further into this. processTagReferences is another place where we should check for -, and if we find that, then we do not call processBinding.

@rqzheng2015
Copy link
Contributor

@rqzheng2015 thanks for digging further into this. processTagReferences is another place where we should check for -, and if we find that, then we do not call processBinding.

Thanks, I will fix this soon.

@rqzheng2015
Copy link
Contributor

Hi @samijaber, I have fixed the issue. Please check the PR here, thanks. #1318

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants