從零開始的微前端—qiankun篇(2)

前言

之前写的那个qiankun是有问题的,所以重新写了一下,最近才发现好久没写文章总结了,这段时间我会基于qiankun项目,写一个完整的项目步骤,(1)想写qiankun介绍,不过好像挺多类似的文章,就不急着写了,后续补上

一, 準備

1. vue-cli版本

image.png

2. vue, qiankun , vuerouter

image.png

二. 創建項目

1.首先通过vue creat文件名,创建两个项目,作为主应用和子应用,这里使用qiankun-test,qiankun-testchild1作为示例.

image.png

image.png

其他选项一直回车即可,创建好项目之后,当前文件下就会出现两个项目包,如下

image.png

我們將qiankun-test作為主項目,開始使用qiankun

2. 主项目中,需要使用qiankun来加载子应用,所以,需要在主项目中install qiankun,子项目不需要,然后再安装一个vue-router,这个是需要的

image.png

image.png

3. 接下来就是需要在主项目中使用qiankun了,进入到主项目的main.js中,先引入qiankun,引入三个参数:分别是registerMicroApps,setDefaultMountApp,start,其中setDefaultMountApp默认子应用这个参数,引不引入都可以.

image.png

apps数组用来存放加载子应用的信息,包含入口,连接,传参等等,registerMicroApps可以设置各子应用启动前后,状态变化的函数及自定义操作,start用于启动qiankun

import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import { registerMicroApps,setDefaultMountApp, start } from "qiankun"
Vue.config.productionTip = false
Vue.use(ElementUI);

let apps = [
  {
    name: "qiankun-testchild1", // 這個是子項目的名稱
    entry: '//localhost:9725',  // 這個是子項目的入口鏈接
    container: "#subapp",  // 這個是主應用中子應用盒子, id
    activeRule: "/qiankun-testchild1", // 這個是子應用路徑規則
    props: {  // 这个是传给子应用的参数信息
      name: "kuitos"
    }
  }
]
registerMicroApps(apps, 
  {
    beforeLoad: [
      app => {
        console.log('[LifeCycle] before load %c%s', 'color: green;', app.name);
      },
    ],
    beforeMount: [
      app => {
        console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name);
      },
    ],
    afterUnmount: [
      app => {
        console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name);
      },
    ],
  },);
  

// 设置默认子应用,与 genActiveRule中的参数保持一致
// setDefaultMountApp("/app1");
// 启动
start();

new Vue({
    router,
    render: h => h(App)
  }).$mount("#app");
复制代码

4. 接下来在app.vue中,放置子应用盒子,id与main.js里container的id一样,

image.png

5.然后在src目录下,创建router文件夹,导出router供main.js引用

import Vue from 'vue'
import VueRouter from 'vue-router'
import HelloWorld from '../components/HelloWorld.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'HelloWord',
    component: HelloWorld
  }
]

const router = new VueRouter({
  mode: 'history',
  // base: '/qiankun-testchild1', // 这个base,是默认路径,如果不将其注释,会将首页与子应用共同显示router-view中.
  routes
})

export default router
复制代码

6. 然后再在src下创建shared文件夹,提供给多应用之间通信,

image.png

import { initGlobalState } from "qiankun";

 const initialState = {};
 const actions = initGlobalState(initialState);

 export default actions;
复制代码

7. 创建并添加好actions之后,就可以在主应用中,使用actions去建立通信了,比如,在主应用的helloWorld,中,先引入actions,然后通过actions.onGlobalStateChange来监听数据变化,通过setGlobalState来改变数据

image.png

8.到此,主应用就简单的完成了,那么接下来就要来改造一下子应用.

9. 首先,在子应用的根目录下,创建一个vue.config.js文件,这个文件可以用来修改添加webpack配置,这块不明白的话,后续再讲一下,配置如下:主要解决跨域,和子应用died问题

image.png

const path = require('path');
const packageName = require('./package').name;

function resolve(dir) {
  return path.join(__dirname, dir);
}

const port = 9725; // dev port
module.exports = {
  publicPath:`//localhost:${port}`, // 這個是子應用的訪問路徑
  outputDir: 'dist',
  assetsDir: 'static',
  filenameHashing: true,
 
  devServer: {
    // host: '0.0.0.0',
    hot: true,  // 這個是重點, 需要添加進去, 否則, 子應用會died
    historyApiFallback: true,//添加 重点
    port,
    overlay: {
      warnings: false,
      errors: true,
    },
    headers: {
      'Access-Control-Allow-Origin': '*', // 這個是跨域
    },
  },

  configureWebpack: {
    resolve: {
      alias: {
        '@': resolve('src'),
      },
    },
    output: { // 這一塊配置子應用打包配置, 不配置也會died,
      library: `${packageName}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${packageName}`,
    },
  },
};

复制代码

10. 接下来,就需要修改一下public文件夹下,html中根元素的id,不能与主应用id相同

image.png

11.然后,需要在子应用的main.js中注入qiankun的生命周期,

image.png

    import Vue from "vue";
    import App from "./App.vue";
    import router from "./router";
    import actions from "../src/shared/action";

    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    Vue.use(ElementUI);
    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;
    }
    Vue.config.productionTip = false;

    if (window.__POWERED_BY_QIANKUN__) {
      // eslint-disable-next-line no-undef
      __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
    }

    if (!window.__POWERED_BY_QIANKUN__) {
      render();
    }
    let instance = null;
    function render(props={}) {
      if (props) {
        // 注入 actions 实例
        actions.setActions(props);
      }
      const { container } = props;
      console.log(container,props,888)
      instance = new Vue({
        router,
        render: h => h(App)
      }).$mount(container ? container.querySelector("#app2") : "#app2");
    }


复制代码

12. 同樣, main.js中會引入router 和actions, 所以, 需要在src目錄下分別添加 shared文件夾和router文件夾

// shared ==>action.js

```

    function emptyAction() {
      // 警告:提示当前使用的是空 Action
      console.warn("Current execute action is empty!");
    }

class Actions {
  // 默认值为空 Action
  actions = {
    onGlobalStateChange: emptyAction,
    setGlobalState: emptyAction
  };

  /**
       * 设置 actions
       */
      setActions(actions) {
        this.actions = actions;
      }

  /**
   * 映射
   */
  onGlobalStateChange(...args) {
    return this.actions.onGlobalStateChange(...args);
  }

  /**
   * 映射
   */
  setGlobalState(...args) {
    return this.actions.setGlobalState(...args);
  }
}

const actions = new Actions();
export default actions;

```
复制代码

// router==> index.js

    import Vue from 'vue'
  import VueRouter from 'vue-router'


  Vue.use(VueRouter)

    const routes = [

  ]
  const router = new VueRouter({
    base: '/',
    mode: 'history',
    routes,
  });

  export default router

复制代码

13. 然後, 在需要的地方, 使用action監聽修改

image.png

14. 在路由跳轉上, 使用的是history模式跳轉,

image.png

image.png

15. 到这里,一个简单的qiankun示例就基本上实现了,跟着步骤一步步做,就能成功启动并使用,给出下效果截图,

image.png

image.png

image.png

image.png

16. 最後附上這階段的代碼連接

github.com/hejiyun/qia…

結語

时间从来不语,却回答了所有问题,各位,前路漫漫,沿途亦是风景.且行且珍惜.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享