1. 程式人生 > 其它 >Web元件化(Web Components) - React轉換為Web Component

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/