Web组件化(Web Components) - React转换为Web Component

最近在思考如何实践微前端, 方案有许多,Web Components也是其中之一。 本文就先从如何将React组件转换为Web Component组件开始,探索Web Component实现微前端的方案。 当然市面上成熟的框架,如SingleSPA,QianKun自然也是可以实现Micro-Frontend,本文只是作为一种可能性研究。

首先,参考我先前的文章,建立一个React项目。
最终结构如下:

webpack.config.js

const path = require('path');
module.exports = {
  entry: './src/app.tsx',
  module: {
    rules: [
      {
        test: /\.(ts|js)x?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              "@babel/preset-env",
              "@babel/preset-react",
              "@babel/preset-typescript",
            ],
          },
        }
      }
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  output: {
    path: path.join(__dirname, 'public'),
    filename: 'bundle.js'
  }
};

package.json

{
  "name": "web-component",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack --mode=development",
    "build": "webpack --mode=production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.15.8",
    "@babel/preset-env": "^7.15.8",
    "@babel/preset-react": "^7.14.5",
    "@babel/preset-typescript": "^7.15.0",
    "@types/react": "^17.0.31",
    "@types/react-dom": "^17.0.10",
    "babel-loader": "^8.2.3",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "webpack": "^5.59.1",
    "webpack-cli": "^4.9.1"
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "typescript": "^4.4.4"
  }
}

.babelrc

{
    "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"],
    "plugins": ["@babel/plugin-proposal-class-properties"]
}

app.tsx

import React from 'react';
import ReactDOM from 'react-dom';

function Hello() {
  
    return (
      <div>
        Hello World!
      </div>
    );
  }

// Name of our class doesn't matter.
class HelloElement extends HTMLElement {
    // Happens every time an instance of this element is mounted
    // (can be called again when moved from one container element to another)
    connectedCallback() {
      ReactDOM.render(
        <div>
            <Hello></Hello>
            <button onClick={() => alert("Clicked")}>
                Click Me!
            </button>
        </div>,
        this
      );
    }
  }
  
  const tagName = "hello-component";
  
  if (!window.customElements.get(tagName)) {
    // prevent rerunning on hot module reloads
    // register to be rendered in place of every <evil-plan> tag
    window.customElements.define(tagName, HelloElement);
  }

index.html

<html>
    <script src='bundle.js'></script>

    <body>
        <hello-component></hello-component>
    </body>
</html>

执行npm run build
webpack会在public文件夹下生成bundle.js, 并被index.html引用。 index.html中使用标签输出React组件。

最后浏览index.html页面即可。

当然,该demo仅仅是第一步,后面还会讨论:
1:Shell App与Web Component的交互,包括通过属性传参、触发事件等等
2:路由,Shell App如何通过路由变化加载对用的Web Component。 作为React应用,Web Component应该选择什么路由策略,才不会影响Shell App。
3:样式隔离。 Web Component间的样式互相隔离,但Shell App可以通过设置全局变量改变Web Component的样式
4:动态加载Web Component
5:其他暂时未想到的

顺便说一句,GitHub的网站就是通过Web Component实现的,打开源码可以看到。

参考:
https://tinloof.com/blog/how-to-create-microfrontends-with-web-components-in-react/

posted @ 2021-10-24 22:19  老胡Andy  阅读(1880)  评论(0编辑  收藏  举报