最近在思考如何實踐微前端, 方案有許多,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/