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

Feat/cem module path as module path #163

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tkgroot
Copy link
Contributor

@tkgroot tkgroot commented Mar 7, 2025

With the customElementReactWrapperPlugin the configuration option provided by providing a custom modulePath with the given parameters is not sufficient for web-components and their generated wrappers. Namely, if components are grouped in a directory, like myCustomTab and myCustomTabs it can create the impossible challenge to use className and tagName to resolve the path to the correct component.

consider the following structure for the custom-elements:

modulePath: (className, tagName) => `./${tagName}/${className}.js` 
|- src
|-- tabs
|--- myCustomTab.js
|--- myCustomTabs.js
/**
 * @tag my-custom-tab
 */
export class MyCustomTab extends HTMLElement { /* ... */ }
/**
 * @tag my-custom-tabs
 */
export class MyCustomTabs extends HTMLElement { /* ... */ }

the output will be two components with the path

./my-custom-tab/MyCustomTab.js
./my-custom-tabs/MyCustomTabs.js

Even if you would configure the modulePath differently like ${tagName.split('-').reverse()[0]} you wouldn't get the desired outcome.

./tab/MyCustomTab.js
./tabs/MyCustomTabs.js

CEM provides a path which is better suited to do some custom modulePath resolution:

{
      "kind": "javascript-module",
      "path": "src/tabs/MyCustomTab.js",
      "declarations": [
        {
          "kind": "class",
          "description": "",
          "name": "MyCustomTab",
          "...": "..."
         }
      ]
}

This PR adds this functionality.

tkgroot added 2 commits March 7, 2025 14:57
- add additional component property modulePath which contains
the path from the CEM.

Signed-off-by: Tobias Kuppens Groot <[email protected]>
@break-stuff
Copy link
Owner

Unfortunately, that path reflects the component's source path, not the output path, so that would only work in specific circumstances.

In a situation like yours, I would recommend adding some logic to the modulePath function:

modulePath: (className, tagName) => {
  switch (tagName) {
    case 'my-custom-tab':
    case 'my-custom-tabs':
      return `./tabs/${className}.js`;
    case 'my-select':
    case 'my-option':
      return `./select/${className}.js`;
    default:
      return `./${tagName}/${className}.js`;
  }
}

@tkgroot
Copy link
Contributor Author

tkgroot commented Mar 7, 2025

indeed it's the source of the component, but as far as I know that is the path which is used by the getReactComponentTemplate() to add the import of the component (I think here you really want to source path of the component, anything else would be useless). Is that the specific circumstance you are referring to?

return `
    ${config.ssrSafe ? '"use client"' : ""}
    import React, { forwardRef, useImperativeHandle ${
      useEffect ? ", useRef, useEffect" : ""
    } ${config.scopedTags ? ", useContext" : ""} } from "react";
    ${!config.ssrSafe ? `import '${modulePath}';` : ""}
    ...
`

the additional parameter for the modulePath function could be renamed to reflect that it's the actually the source path of the component, like sourcePath.

@tkgroot
Copy link
Contributor Author

tkgroot commented Mar 7, 2025

I was thinking of similar solution as you proposed, but it just does not feel that clean to keep a map of all my components somewhere. In case something changes I have to update this as well and keep this web-component map in sync with my component sources. Somehow this ruins the automation of things a bit ;)

@break-stuff
Copy link
Owner

You don't want the source path for the react wrappers. You want to reference where their final output is. Otherwise, the module will be missing in production.

@tkgroot
Copy link
Contributor Author

tkgroot commented Mar 10, 2025

With final output you mean the path to the web-components. In my case, since I do not build my components, the source and output path are the same, which probably will be a specific circumstance you mentioned. Therefore it works when updating the modulePath for the react-wrappers by using the additional parameter I've added in the PR. I do understand that you probably do not want to expose this, since for others it might be confusing.

Anyways, in my case that is a bit troublesome to not have access to the sourcePath directly. I will have to figure something out.

@break-stuff
Copy link
Owner

I really wish the manifest would define a source path, an output path, and a types path. That would make this tooling a lot easier.

The nice thing is that if you are using any of my other tools, they follow the same pattern, so you could define this once and reuse it for all of them.

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

Successfully merging this pull request may close these issues.

2 participants