mitosis
mitosis copied to clipboard
Support for custom components in mitosis compiler
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
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
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": []
}
}
This is where we grab the name from the parsed AST:
https://github.com/BuilderIO/mitosis/blob/c43e61f518be5dd8d1c1199661b554934b78ffe6/packages/core/src/parsers/jsx/element-parser.ts#L122
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:
- create a unit test using the simple mitosis component in this comment (see https://github.com/BuilderIO/mitosis/blob/main/developer/README.md for instructions)
- generate the test snapshots, and check if the new snapshot for this test in https://github.com/BuilderIO/mitosis/blob/main/packages/core/src/tests/snapshots/parse-jsx.test.ts.snap has those spaces or not.
- use this unit test to find the root cause of the problem
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.
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 codeProcessor
function execution.
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.
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.
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.
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. 🤔
Thanks @samijaber! And I'm gonnna test the new solution you provided asap.
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.
And in
processBinding
function ,it called stripStateAndPropsRefs
function, and deeper, it called replaceStateIdentifier
function, which leads to babelTransformExpression
, thus, once again, transformed by babel makes it add spaces in tag name again.
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.
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:
- 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)".
- After generation, the ts declration is missing in the result.
How could I have better way to make ts declaration to support
web component
? Please take a look if you have time, thanks.
@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.
@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 thanks for digging further into this.
processTagReferences
is another place where we should check for-
, and if we find that, then we do not callprocessBinding
.
Thanks, I will fix this soon.
Hi @samijaber, I have fixed the issue. Please check the PR here, thanks. https://github.com/BuilderIO/mitosis/pull/1318