qiankun微服务子系统对接文档

Vue子系统

  • main.js 入口文件修改
let instance = nullfunction 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)
// })
  • 接入主应用的子系统,需要另外开个路由,去掉头尾,只有内容区域的-----自行配置
    • 使用 webpack 运行时 publicPath 配置 qiankun 将会在微应用 bootstrap 之前注入一个运行时的
      publicPath 变量,这就需要处理一下几处
      • webpack配置文件,譬如vue.config.js 配置
 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模式
})
  • 对应项目下载的iconfont、字体文件等,让主应用去注册,子应用把相应的东西交由主应用

React子系统

  • 入口文件修改
let instance = nullfunction 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
}
  • 重写 react 中的 webpack 配置文件 ( config-overrides.js )
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;
      }
 }
}
  • React路由配置
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>
);
}
  • 配置 .env 文件
PORT=20000
WDS_SOCKET_PORT=20000
  • 纯html应用
    html里面加入入口
<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
  • 修改config.js
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`,
      }
    })
  },
})
  • 修改defaultSettings.js
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;
  • 新增src/app.ts
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);
  },
};

通讯
通讯:

  • 登录过期,子应用通知主应用,主应用做清楚登录信息操作,并跳转到登录页面,让用户进行操作,在操作完成后做路由重定向到子应用
    • 基于浏览器自带的CustomEvent实现通信
//主应用
window.dispathEvent( 
    new CustomEvent('master:collapse-menu'),{detail: {collapsed:true} }
 )
//子应用
window.addEventLister('master:collapse-menu', 
      event => console.log(event.detail.collapsed))
  • 基于props主子应用间通信,类似组件通信一样
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 注入方法,给到主应用

你可能感兴趣的:(qiankun微服务子系统对接文档)