Vue子系统
let instance = null
function render(props = {}) {
const { container } = props
instance = new Vue({
// el: '#app',
router,
store,
render: h => h(App)
}).$mount(container ? container.querySelector('#app') : '#app') // 这里是挂载到自己的html中,基座会拿到这个挂载后的html,将其插入进去
}
if (window.__POWERED_BY_QIANKUN__) { // 动态添加public_path
window.__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
// 有些时候我们希望直接启动微应用从而更方便的开发调试,你可以使用这个全局变量来区分当前是否运行在 qiankun 的主应用的上下文
if (!window.__POWERED_BY_QIANKUN__) { // 默认独立运行
render()
}
// 到处bootstrap mount、unmount
// 子组件的协议就OK了
// 启动
export async function bootstrap() {
}
// 装载
export async function mount(props) {
render(props)
}
// 卸载
export async function unmount(props) {
instance.$destroy()
instance = null
}
// new Vue({
// el: '#app',
// router,
// store,
// render: h => h(App)
// })
publicPath: `http://192.168.8.100:${port}`, // 这里要配置成发布的地址,或者现 在开发环境的启动地址,绝对地址
outputDir: 'dist',
assetsDir: 'static',
filenameHashing: true,
lintOnSave: process.env.NODE_ENV === 'development',
productionSourceMap: false,
devServer: {
port: port,
historyApiFallback: true, // 添加 重点
headers: { // 因为qiankun 使用的是fetch,需要做跨越处理
'Access-Control-Allow-Origin': '*'
},
open: false,
overlay: {
warnings: false,
errors: true
},
proxy: {
[process.env.VUE_APP_BASE_API]: {
target: require('./env.js').url,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
}
},
configureWebpack: {
// provide the app's title in webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
name: name,
resolve: {
alias: {
'@': resolve('src')
}
},
output: {
library: 'baasApp', // 打包名称,这个如果子应用定义好,要告知主应用,因为这个和主应用注册子应用的名称一致
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_baas`
}
},
const router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/console/baas' : '/', // 这里根据主应用容器的名称一致
routes,
// mode: 'history', // require service support----这个和主应用保持一致,后期发布到线上一定会用history模式
})
React子系统
let instance = null
function render(props = {}) {
const { container } = props
instance = ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
container ? container.querySelector('#app') : document.getElementById('app')
// 这里是挂载到自己的html中,基座会拿到这个挂载后的html,将其插入进去
}
if (window.__POWERED_BY_QIANKUN__) { // 动态添加public_path
window.__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
// 有些时候我们希望直接启动微应用从而更方便的开发调试,你可以使用这个全局变量来区分当前是否运行在 qiankun 的主应用的上下文
if (!window.__POWERED_BY_QIANKUN__) { // 默认独立运行
render()
}
// 到处bootstrap mount、unmount
// 子组件的协议就OK了
// 启动
export async function bootstrap() {
}
// 装载
export async function mount(props) {
render(props)
}
// 卸载
export async function unmount(props) {
ReactDOM.unmountComponentAtNode(document.getElementById("app")); // 卸载
instance = null
}
yarn add react-app-rewired --save-dev
module.exports = {
webpack: (config) => {
config.output.library = `reactApp`; // 注意,这个是主应用注册的子应用名称
config.output.libraryTarget = "umd";
config.output.publicPath = 'http://localhost:20000/' // 注意,这个是你子应用的启动地址
return config
},
devServer: function (configFunction) {
return function (proxy, allowedHost) {
const config = configFunction(proxy, allowedHost);
config.headers = { "Access-Control-Allow-Origin": "*",
}; // 配置跨域
return config;
}
}
}
import { BrowserRouter, Route, Link } from "react-router-dom"
const BASE_NAME = window.__POWERED_BY_QIANKUN__ ? "/react" : ""; // /react 需要与主应用保持一致
function App() {
return (
<BrowserRouter basename={BASE_NAME}>
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
<Route path="/" exact render={() => <h1>hello home</h1>}></Route> <Route path="/about" render={() => <h1>hello about</h1>}></Route>
</BrowserRouter>
);
}
PORT=20000
WDS_SOCKET_PORT=20000
<div id="purehtml-container" style="text-align:center">div>
创建entry.js,注入方法
const render = $ => {
$('#purehtml-container').html('Hello, render with jQuery'); // 名称保持和定义的一致
return Promise.resolve();
};
(global => {
global['purehtml'] = {
bootstrap: () => {
console.log('purehtml bootstrap');
return Promise.resolve();
},
mount: () => {
console.log('purehtml mount');
return render($);
},
unmount: () => {
console.log('purehtml unmount');
return Promise.resolve();
},
};
})(window);
在html中引入
<script src="//localhost:7104/entry.js" entry>script>
umi中应用
yarn add @umijs/plugin-qiankun -D
export default defineConfig({
base: '/console/baas', //新增配置---这个和主应用配合协调好
publicPath: 'http://localhost:9005/', //当前应用地址,本地联调可以写ip地址
// mountElementId: 'baas',
hash: true,
history: {
type: 'hash', // 本地姑且先用hash模式
},
qiankun: { // 配置qiankun开启
slave: {}
},
chainWebpack (config) { // webpack配置
config.merge({
output: {
library: `datawork-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_datawork`,
}
})
},
})
const proSettings = {
navTheme: 'light', // 主题。因为我们是浅色系,所以这里修改了下
// 拂晓蓝
primaryColor: '#375FF3', // 主题色
layout: 'side',
contentWidth: 'Fluid',
fixedHeader: false,
fixSiderbar: false, // 这里要注意下,不要fix sider,不然布局会出问题
colorWeak: false,
menu: {
locale: true,
},
title: 'Datawork',
pwa: false,
iconfontUrl: '',
};
export default proSettings;
export const qiankun = {
// 应用加载之前
async bootstrap(props) {
console.log('app1 bootstrap', props);
},
// 应用 render 之前触发
async mount(props) {
console.log('app1 mount', props);
},
// 应用卸载之后触发
async unmount(props) {
console.log('app1 unmount', props);
},
};
通讯
通讯:
//主应用
window.dispathEvent(
new CustomEvent('master:collapse-menu'),{detail: {collapsed:true} }
)
//子应用
window.addEventLister('master:collapse-menu',
event => console.log(event.detail.collapsed))
initGlobalState (onGlobalStateChange、setGlobalState)
乾坤 状态交互 调用流程图:
a.先执行主应用main.js
const { onGlobalStateChange, setGlobalState } = initGlobalState({
user: 'qiankun',
});
函数
b.再执行主应用render.js 的onGlobalStateChange 函数 ,prev ={} ,val = 在main.js 里执行过的initGlobalState
state 状态
c.如果在main.js 执行了setGlobalState 函数
setGlobalState({
ignore: 'master',
user: {
name: 'master',
},
});
那么会再次调用render.js的onGlobalStateChange函数
d.然后再执行main.js 中onGlobalStateChange 回调函数
e. 然后再执行子应用的onGlobalStateChange 函数
f. 如果在子应用执行setGlobalState函数,会再次执行render.js的onGlobalStateChange 函数
g.然后执行主应用main.js 的onGlobalStateChange函数
h.最后执行子应用的onGlobalStateChange 函数
主应用: import { initGlobalState } from 'qiankun'; const { onGlobalStateChange, setGlobalState } = initGlobalState({ user: 'qiankun', }); onGlobalStateChange((value, prev) => console.log('[onGlobalStateChange - master]:', value, prev)); setGlobalState({ ignore: 'master', user: { name: 'master', }, }); 子应用: function storeTest(props) { props.onGlobalStateChange && props.onGlobalStateChange( (value, prev) => console.log([onGlobalStateChange - ${props.name}]:, value, prev), true, ); props.setGlobalState && props.setGlobalState({ ignore: props.name, user: { name: props.name, }, }); } export async function mount(props) { console.log('[vue] props from main framework', props); storeTest(props); }
主应用:
import { initGlobalState } from 'qiankun';
const { onGlobalStateChange, setGlobalState } = initGlobalState({
user: 'qiankun',
});
onGlobalStateChange((value, prev) => console.log('[onGlobalStateChange - master]:', value, prev));
setGlobalState({
ignore: 'master',
user: {
name: 'master',
},
});
子应用:
function storeTest(props) {
props.onGlobalStateChange &&
props.onGlobalStateChange(
(value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
true,
);
props.setGlobalState &&
props.setGlobalState({
ignore: props.name,
user: {
name: props.name,
},
});
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
storeTest(props);
}
沙箱
注意: @keyframes, @font-face, @import, @page 将不被支持 (i.e. 不会被改写) P.S: 在目前的阶段,该功能还不支持动态的、使用 标签来插入外联的样式,但考虑在未来支持这部分场景。
将main.js 注入方法,给到主应用