最近在思考如何实践微前端, 方案有许多,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中使用
最后浏览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/