从React组件创建纯Web组件

10

我正试图从React组件构建Web组件,一切都运作良好,但有两个问题需要解决:

  1. 有没有一种方法可以将这种Web组件转换为纯Web组件(使用Webpack、转译或其他方式),以便不捆绑React和其他依赖项?
  2. 是否有一种方法只包含所需的依赖项部分或仅是全部/无部分,并且必须使用Webpack的外部设置来使用主机的版本?

谢谢。

4个回答

12

对于第一个问题,没有直接将React组件转换为Web Component的方法。您需要将其包装在Web Component Class中:

对于第一个问题,没有直接将React组件转换为Web Component的方法。您将不得不将其包装在Web Component Class中:

export function MyReactComponent() {
  return (
    <div>
      Hello world
    </div>
  );
}


class MyWebComponent extends HTMLElement {
  
  constructor() {
    super();
    // Do something more
  }

  connectedCallback() {
    
    // Create a ShadowDOM
    const root = this.attachShadow({ mode: 'open' });

    // Create a mount element
    const mountPoint = document.createElement('div');
    
    root.appendChild(mountPoint);

    // You can directly use shadow root as a mount point
    ReactDOM.render(<MyReactComponent />, mountPoint);
  }
}

customElements.define('my-web-component', MyWebComponent);

当然,您可以将其概括并创建可重复使用的函数,例如:

function register(MyReactComponent, name) {
  const WebComponent = class extends HTMLElement {
    constructor() {
      super();
      // Do something more
    }
  
    connectedCallback() {
      
      // Create a ShadowDOM
      const root = this.attachShadow({ mode: 'open' });
  
      // Create a mount element
      const mountPoint = document.createElement('div');
      
      root.appendChild(mountPoint);
  
      // You can directly use shadow root as a mount point
      ReactDOM.render(<MyReactComponent />, mountPoint);
    }
  }
  
  customElements.define(name, MyWebComponent);
}

register(MyReactComponent, 'my-web-component');

现在可以重复使用相同的注册函数,以使您要公开为Web组件的所有组件都能够使用。如果您的组件接受应该传递的props,则可以将此功能更改为接受第三个参数作为字符串数组,其中每个值都将使用Object.define注册为此组件的setter。每次调用setter时,您只需再次调用ReactDOM.render即可。

对于第二个问题,你尝试做的有多种情况。

  • 如果您正在绑定应用程序并使用CDN加载React或其他依赖项,则Webpack的externals是一个好方法。在这里,您将教WebPack如何替换应用程序将运行的全局环境中的importrequire
  • 如果您正在绑定要发布到NPM库供他人在其应用程序中使用的,则必须使用library target配置构建项目。在此处阅读更多关于编写库的信息

为库进行打包稍微棘手,因为您必须决定输出格式(common.js、ES模块或UMD或全局或多个格式)。如果您正在为浏览器打包,则理想的格式是ES模块,因为它允许更好的树摇。以前Webpack不支持Module格式,最近开始支持它。总的来说,我建议对于应用程序使用Webpack,对于库使用Rollup.js。


谢谢Harshal的回答。webpack externals是我们一直在考虑的方式。所以总体来说,现在似乎没有将包装的React组件转换为纯Web组件的实用程序/包? - syed

5
如果您想手动完成此操作,Harshal Patil的答案是正确的方式。我还想指出一个库,我协助创建,react-to-webcomponent。它简化了该过程并且无缝支持React 16-18。

我只想指出它不支持React children,这在我看来是一个巨大的缺陷。 - Chris

0
你可以使用 remount 库。

/** Main.jsx */

import React from 'react'
import App from './App'
import { define } from 'remount';

define({'react-counter':  App},
    {
    attributes: ['defaultValue'],
    shadow:false
})

/** App.jsx */

import React from "react";
import Counter from "./components/Counter.jsx";

function App({defaultValue}) {
  return (
    <div>
      <h1>Counter Component</h1>
      <Counter defaultValue={defaultValue}/>
    </div>
  )
}

export default App;

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React</title>
  </head>
  <body>
    <react-counter defaultValue="5"></react-counter>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>


前两个代码片段有错误,最后一个代码片段没有显示任何内容。 - Danny '365CSI' Engelman

0

React并不是一个用于构建本地Web组件的库。

手动编写Web组件也不是最佳选择,因为它无法处理条件、循环、状态变化、虚拟DOM和其他基本功能。

React、Vue、Svelte和其他自定义库确实有一些优点,而本地Web组件则具有许多其他优点,如生态系统的简单性以及被浏览器和W3C支持。

以下是一些可帮助您以现代和便捷方式编写本地Web组件的库:

  • Lego 是一个轻量级、本地化且具有Vue风格的全功能库。
  • Nativeweb 轻量级和原始的Web组件
  • ElemX 是一个将本地Web组件绑定到ElemX功能的概念验证。

如果您真的想将React组件包装成本地Web组件,可以尝试以下方法:

class MyComponent extends HTMLElement {
  constructor() {
    this.innerHTML = '<MyReactComponent />'
  }
}

customElements.define('my-component', MyComponent)

并在您的HTML页面中使用它 <my-component />


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接