easy-mft
v1.0.7
Published
a micro-frontend solution
Downloads
5
Readme
mft
📦 安装
npm i easy-mft -S
getting started
运行 example
npm install
npm run init
npm run run:fragment
// open http://localhost:9100
// global.js
import ctrlapp, { globalEvent } from 'easy-mft'
export default new ctrlapp(appConfig)
.
.
.
import Ctrlapp, {globalEvent} from './global'
// if is react
componentDidMount () {
const appinfo = [
{
name: "a50", // 应用名需唯一
applicationName: "reactnews", // 应用模块名需唯一
entry: "http://912-mft-app1.dev.za-tech.net/app", //应用接入地址
contain: this.refs.container2, // 应用挂载容器,须在页面存在的dom元素
baseUrl: "/", // 子应用的主路径
canActive(path) { // 应用激活规则
return window.location.pathname.startsWith(this.baseUrl);
}
}
Ctrlapp.registerApps(appinfo)
}
// if is vue
mounted () {
const appinfo = [
{
name: "a50",
applicationName: "reactnews",
entry: "http://912-mft-app1.dev.za-tech.net/app",
contain: this.refs.container2,
baseUrl: "/",
canActive(path) {
return window.location.pathname.startsWith(this.baseUrl);
}
}
Ctrlapp.registerApps(appinfo)
}
.
.
.
子应用
export default {
bootstrap: async function bootstrap(parent) {
console.log('react app bootstraped');
Ctrlapp.parent = parent
},
mount: async function mount(contain, baseUrl, appinfo, parent) {
Ctrlapp.parent = parent
console.log('parent::', parent)
Ctrlapp.baseUrl = baseUrl;
console.log('this is news mount')
console.log(contain)
ReactDOM.render(<App baseUrl={baseUrl} appinfo={appinfo}/>, contain)
},
unmount: async function unmount(contain) {
ReactDOM.unmountComponentAtNode(contain)
}
}
子应用输出 3 个方法 bootstrap - 创建时运行 mount - 被挂载时运行 unmount - 卸载时运行
应用之间通讯
基于 eventemitter2 实现的应用间通讯 通过使用 globalEvent easy-mft 继承于 eventemitter2
const Ctrlapp = new ctrlapp()
Ctrlapp.on('event', 'this is event)
Ctrlapp.emit('event', 'this is event)
// master application
function BodyTop(){
function handleTypeClick(e) {
globalEvent.emit('father-type-click', e.currentTarget.dataset.type)
}
return (
<React.Fragment>
<div onClick={handleTypeClick}>
提交事件
</div>
</React.Fragment>
)
}
// child application
import React from 'react';
import { globalEvent } from 'easy-mft'
import './index.scss';
export default class Home extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
globalEvent.on('father-type-click', data => {
console.log('data from father-type-click', data);
})
}
render() {
return (
<div className="newsList">
this is child
</div>
)
}
}
打包
子应用需被打包为 umd 形式 通过 postcss-selector-namespace 实现 css 样式隔离 为方便调试将项目改成多页,通过访问路径不同来实现隔离
koa
const http = require('http')
const url = require('url')
const fs = require('fs')
const path = require('path')
const serve = require('koa-static')
const cors = require('@koa/cors')
const Koa = require('koa')
const views = require('koa-views')
const app = new Koa()
const config = require('./config/application.json')
const compress = require('koa-compress')
const PORT = config.port
app.use(cors())
app.use(serve('dist'))
const options = { threshold: 2048 }
app.use(compress())
app.use(views(path.resolve(__dirname, './dist')))
app.use(async function (ctx, next) {
console.log(ctx.req.url)
if (ctx.req.url === '/app') {
return await ctx.render('app')
} else if (ctx.req.url === '/health') {
return ctx.body = '200'
} else {
return await ctx.render('index')
}
})
app.listen(PORT, () => {
console.log(`SPA Fragment Server started at ${PORT}`)
})
通过 koa 设置应用的静态资源访问路径 当主应用子应用发生跨域请求时候,用@koa/cors 设置请求跨域 如果想子应用访问界面和被微服务调用页面分开访问,可在 koa 内设置路由
html entry
默认将页面内最后一个 js 为整个引用的入口文件,如最后一个非启动 js 可使用 entry 标签
<script src='http://localhost:3000/a.js' entry>
如 html 内 js 不想被执行,可使用 ignore
<script src='http://localhost:3000/a.js' ignore>
Tips
- 当前路径下有子应用时,router path 不要使用 exact 绝对匹配,否则导致子应用不显示
- 子应用的 webpack publicPath 请带上主域 ex: http://localhost:9001, 因当子应用嵌入主应用时当前地址为主应用,导致资源调用不出
- 子应用打包需采用 umd 模式, 设置唯一的 library
- 主应用在开发模式下,嵌入的子应用不为开发模式,因被嵌入后热更新丢失导致失败
- 注意主应用调用子应用的跨域问题