qiankun框架

什么是微前端

微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。

什么是微前端?. 微前端(Micro-Frontends)是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。. 各个前端应用还可以独立运行、独立开发、独立部署。. 微前端不是单纯的前端框架或者工具,而是一套架构体系

项目基本配置

下载主体项目文件,及其附属框架,主体文件也是一个框架,react或vue,

随后在项目中设置.env文件配置端口号

PORT=端口号

基座

此处基座是react

在主体文件中设置index文件,配置监听端口以及文件,设置挂载点
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'react app', // app name registered
    entry: '//localhost:3011',//设置监听端口
    container: '#micro-app1',//设置挂载点
    activeRule: '/micro-app1',//访问子应用的规则比如:主应用为localhost:3010,那访问该子应用的url应为localhost:3010/micro-app1
    props:{
      nickname:'张三'
        //传递的数据
    }
  },
  {
    name: 'vue app',
    entry: '//localhost:3012',//设置监听端口
    container: '#micro-app2',//设置挂载点
    activeRule: '/micro-app2',//访问子应用的规则比如:主应用为localhost:3010,那访问该子应用的url应为localhost:3010/micro-app2
    props:{
      nickname:'李四'
        //传递的数据
    }
  },
]);
start()挂载上去
const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);


reportWebVitals();

react

子应用设置
//src里设置public-path.js文件 为了设置图片引入
if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
  }
下载react-app-rewired插件,更改子应用启动项

//package.js文件中
  "scripts": {
    "start": "react-app-rewired start",//更改启动区为react-app-rewired
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
重写webpack中的方法,创建config-overrides.js文件
const { name } = require('./package');

module.exports = {
  webpack: (config) => {
    config.output.library = `${name}-[name]`;
    config.output.libraryTarget = 'umd';//注入方式
    // config.output.jsonpFunction = `webpackJsonp_${name}`;//*在2020-10-10发布的webpack 5中已将 output.jsonpFunction 更名为 output.chunkLoadingGlobal​​​​​​​
    config.output.chunkLoadingGlobal = `webpackJsonp_${name}`;// 中自动推断出一个唯一的构建名称,并将其作为 output.uniqueName 的默认值。这个值用于使所有潜在的冲突的全局变量成为唯一。
    config.output.globalObject = 'window';

    return config;
  },

  devServer: (_) => {
    const config = _;

    config.headers = {
      'Access-Control-Allow-Origin': '*',//允许跨域访问
    };
    config.historyApiFallback = true;
    config.hot = false;
    config.watchContentBase = false;
    config.liveReload = false;

    return config;
  },
};
子组件进行生命周期的暴露
/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {

}


/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {

}


/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount(props) {

}


/**
 * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
 */
export async function update(props) {

}
在入口文件中导入public-path.js文件,webpack5需要在package.json中改为全局变量
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],"globals": {
      "__webpack_public_path__": true
    }
      //改为全局变量
  },
配置子应用入口文件进行数据传递
//react 18版本之前
/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props: any) {
  console.log(props);//接收的数据 数据来自路由中的registerMicroApps中的props
  ReactDOM.render(
    <App />,
    props.container ?props.container.querySelector('#root'):document.getElementById('root')
  )
}


//react 18版本之后 render改为了createRoot 并且写法改变了 改为了render进行返回
/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props: any) {
  console.log(props);//接收的数据 数据来自路由中的registerMicroApps中的props
  ReactDOM.createRoot(
    props.container ?props.container.querySelector('#root'):document.getElementById('root')
  ).render(<App/>)
}

主项目中进行监听,配置生命周期函数

const state={
  name:'张三'
}
//定义全局状态,并返回通信方法,建议在主应用使用,微应用通过 props 获取通信方法。


// 初始化 state
const actions: MicroAppStateActions = initGlobalState(state);

actions.onGlobalStateChange((state, prev) => {
  // state: 变更后的状态; prev 变更前的状态
  console.log(state, prev);
});
//onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void, 在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback

actions.setGlobalState(state);
//setGlobalState: (state: Record<string, any>) => boolean, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性

actions.offGlobalStateChange();
//setGlobalState: (state: Record<string, any>) => boolean, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性
子应用监听数据的变化
export async function mount(props: any) {

  props.onGlobalStateChange((state:any, prev:any) => {
    // state: 变更后的状态; prev 变更前的状态
    //变化后会自动触发
    console.log(state, prev);
  });

  console.log(props);
  ReactDOM.createRoot(
    props.container ?props.container.querySelector('#root'):document.getElementById('root')
  ).render(<App/>)
}
在mount生命周期函数中进行设置,校验是否有父应用 是否是单开的
//react18版本的写法
//18版本中  ReactDOM.render变为了ReactDOM.createRoot
ReactDOM.createRoot(
    props.container ? props.container.querySelector('#root') : document.getElementById('root')
  ).render(
    <BrowserRouter 
      basename={window.__POWERED_BY_QIANKUN__ ?
      '/' : 
      '/micro-app1'}>//路由匹配默认名称
      <App /></BrowserRouter>
  )


//设置默认单开运行情况
if (!window.__POWERED_BY_QIANKUN__) {
    //判断是否无父级,是否单开子应用
  // render({});
  root.render(
    <BrowserRouter>
      <App />
    </BrowserRouter>
  );
}

//如果使用ts需要在react-app-env.d.ts中设置
declare interface Window {
    __POWERED_BY_QIANKUN__:boolean;
  }

vue3

配置vue3子应用,在 src 目录新增 public-path.js:
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
//为了引入静态资源
//同样改变webpack中的package.json中的globals 让其改为全局变量
"globals": {
      "__webpack_public_path__": true
    }
导入路由

vue3的创建实例从vue变为了createApp,创建模式变为了工厂模式

//vue3
import routes from './router';

let router = null;
let history = null;

let app;
function render(props = {}) {
    const { container } = props;
    // router =createApp({
    //   // base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
    //   history,
    //   routes,
    // });
    app=createApp(App)//挂载
    app.use(routes).mount(container ? container.querySelector('#app') : '#app');
  }
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
    render();
  }
  export async function bootstrap() {
    console.log('[vue] vue app bootstraped');
  }
export async function mount(props) {
  console.log('[vue] props from main framework', props);
  render(props);
}
export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = '';
  instance = null;
  router = null;
}

//vue2
import store from './store';

Vue.config.productionTip = false;

let router = null;
let instance = null;
function render(props = {}) {
  const { container } = props;
  router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
    mode: 'history',
    routes,
  });

  instance = new Vue({
    router,
    store,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}
配置监听端口号,配置vue允许夸端口 设置vue.config,并且设置挂载点
const { name } = require('./package');
module.exports = {
  devServer: {
    port:3012,//设置端口号
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd', // 把微应用打包成 umd 库格式
      jsonpFunction: `webpackJsonp_${name}`,
    },
  },
};
更改路由匹配规则,判断是否有父应用
const router = createRouter({
  history: createWebHistory(window.__POWERED_BY_QIANKUN__ ? 
                            '/'
                            : '/micro-app3'//访问子应用的规则
                           ),
  routes,
});

这里是我总结的一些问题,包括代码的基本使用,希望帮助到一些人,里面可能会有一些错误的地方,欢迎大家在评论区留言指正。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
qiankun框架可以通过将子应用的vuex实例作为主应用vuex实例的一个模块来实现共用。具体步骤如下: 1. 在主应用的vuex实例中,使用`registerModule`方法注册子应用的vuex实例为一个模块,可以指定模块名称和命名空间。 ```javascript import { registerMicroApps, runAfterFirstMounted, setDefaultMountApp, start } from 'qiankun'; import store from './store'; registerMicroApps([ { name: 'sub-app', entry: '//localhost:8080', container: '#subapp-container', activeRule: '/sub-app', }, ]); store.registerModule('subAppStore', { state: {}, mutations: {}, actions: {}, getters: {}, }); ``` 2. 在子应用的vuex实例中,导出vuex实例。 ```javascript import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ state: {}, mutations: {}, actions: {}, getters: {}, }); ``` 3. 在子应用的入口文件中,将子应用的vuex实例作为参数传递给子应用的渲染函数。 ```javascript import Vue from 'vue'; import App from './App.vue'; import store from './store'; Vue.config.productionTip = false; function render() { new Vue({ store, render: h => h(App), }).$mount('#app'); } if (window.__POWERED_BY_QIANKUN__) { // 动态添加publicPath,使子应用可以正确加载静态资源 __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } else { render(); } ``` 这样,主应用和子应用之间就可以共用一个vuex实例了。在主应用中使用`store.state.subAppStore`访问子应用的vuex状态,在子应用中使用`this.$store`访问自己的vuex状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值