微前端框架学习记录 ——qiankun 新建demo(一)

官方:https://qiankun.umijs.org/zh
参考:https://juejin.cn/post/6844904042427056142


(全程CV即可))

一、 创建webpack项目

	该项目不是vue、react等前端脚手架,就是很简单的webpack项目
	
	> npm init

1. 调整webpack的packjson:

{
  "name": "vue-qiankun",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "init": "node config/install.js",
    "cinit": "node config/install.js cnpm",
    "serve": "node config/start.js",
    "build": "node config/build.js",
    "lint": "vue-cli-service lint"
  },
  "author": "",
  "license": "ISC"
}

2. 在项目目录中创建config文件夹,分别创建build.js、install.js、start.js

build.js

const fs = require('fs');
const path = require('path');
const util = require('util');
const sub_app_ath = path.resolve();
const sub_apps = fs.readdirSync(sub_app_ath).filter(i => /^subapp|master/.test(i));

console.log(`即将进入所有模块并打包项目:${JSON.stringify(sub_apps)} ing...`)

const exec = util.promisify(require('child_process').exec);
function build() {
  sub_apps.forEach(async i => {
    console.log(`${i} 开始打包,耗时较久请耐心等待...`)
    const { stdout, stderr } = await exec('npm run build', { cwd: path.resolve(i) });
    console.log(i, 'success', stdout)
    console.error(i, 'error', stderr)
  });
};
build();

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
  // application specific logging, throwing an error, or other logic here
});

install.js

const fs = require('fs');
const path = require('path');
const util = require('util');
const sub_app_ath = path.resolve();
const sub_apps = fs.readdirSync(sub_app_ath).filter(i => /^subapp|master/.test(i));

console.log(`即将进入所有模块并下载依赖:${JSON.stringify(sub_apps)} ing... 批量下载所有项目依赖推荐使用 npm run cinit`)

const exec = util.promisify(require('child_process').exec);

// npm 源
let registry = process.argv.length === 3 ? 'cnpm install' : 'npm install';

function install() {
  sub_apps.forEach(async i => {
    console.log(`${i} 开始下载,耗时较久请耐心等待...`)
    const { stdout, stderr } = await exec(registry, { cwd: path.resolve(i) });
    console.log(i, 'success', stdout)
    console.error(i, 'error', stderr)
  });
};
install()

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
  // application specific logging, throwing an error, or other logic here
});

start.js

const fs = require('fs');
const path = require('path');
const util = require('util');
const sub_app_ath = path.resolve();
const sub_apps = fs.readdirSync(sub_app_ath).filter(i => /^subapp|master/.test(i));

console.log(`即将进入所有模块并启动服务:${JSON.stringify(sub_apps)} ing...`)

const exec = util.promisify(require('child_process').exec);
function start() {
  sub_apps.forEach(async i => {
    console.log(`${i} 开始启动... 全部启动需要时间,请稍加等候,或刷新浏览器即可`)
    const { stdout, stderr } = await exec('npm run serve --fix', { cwd: path.resolve(i) });
    console.log(i, 'success', stdout)
    console.error(i, 'error', stderr)
  });
  exec('start http://localhost:7770/');
};
start();

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
  // application specific logging, throwing an error, or other logic here
});

3. 在项目目录中创建主程序master

	这里我使用的vue,也可替换成react、angular
	我这里创建的是master,可以是其他
	
	> vue create master

二、 在master中引入qiankun

	yarn add qiankun	或者
	npm i qiankun -S

1. 修改master中main.js

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
Vue.config.productionTip = false;

// 导入qiankun内置函数
import {
  registerMicroApps, // 注册子应用
  runAfterFirstMounted, // 第一个子应用装载完毕
  setDefaultMountApp, // 设置默认装载子应用
  start, // 启动
} from "qiankun";

let app = null;
/**
 * 渲染函数
 * appContent 子应用html
 * loading 如果主应用设置loading效果,可不要
 */
function render({ appContent, loading } = {}) {
  if (!app) {
    app = new Vue({
      el: "#container",
      router,
      data() {
        return {
          content: appContent,
          loading,
        };
      },
      render(h) {
        return h(App, {
          props: {
            content: this.content,
            loading: this.loading,
          },
        });
      },
    });
  } else {
    app.content = appContent;
    app.loading = loading;
  }
}
// 调用渲染主应用
render();
/**
 * 路由监听
 * @param {*} routerPrefix 前缀
 */
function genActiveRule(routerPrefix) {
  return (location) => location.pathname.startsWith(routerPrefix);
}

// 注册子应用
registerMicroApps(
  [
    {
      name: "vue-aaa",
      entry: "//localhost:7771",
      render,
      activeRule: genActiveRule("/aaa"),
    },
    {
      name: "vue-bbb",
      entry: "//localhost:7772",
      render,
      activeRule: genActiveRule("/bbb"),
    },
  ],
  {
    beforeLoad: [
      (app) => {
        console.log("before load", app);
      },
    ], // 挂载前回调
    beforeMount: [
      (app) => {
        console.log("before mount", app);
      },
    ], // 挂载后回调
    afterUnmount: [
      (app) => {
        console.log("after unload", app);
      },
    ], // 卸载后回调
  }
);

// 设置默认子应用,参数与注册子应用时genActiveRule("/aaa")函数内的参数一致
setDefaultMountApp("/aaa");

// 第一个子应用加载完毕回调
runAfterFirstMounted(() => {});

// 启动微服务
start();

2. 修改public中index.html

	将id为app的div,id改为container
	
	否则会跟子应用冲突,例如vue通常都是针对id为app的div进行操作

3. 修改App.vue

<template>
  <div id="root" class="main-container">
    <div class="main-container-menu"></div>
    <!-- 子应用盒子 -->
    <div id="root-view" class="app-view-box" v-html="content"></div>
  </div>
</template>

<script>
export default {
  name: "root-view",
  props: {
    loading: Boolean,
    content: String
  },
};
</script>

4. 修改vue.config.js

const port = 7770; // dev port
module.exports = {
  lintOnSave:false,// 关闭eslint
  // publicPath: './',  
  devServer: {
    // host: '0.0.0.0',
    hot: true,
    disableHostCheck: true,
    port,
    overlay: {
      warnings: false,
      errors: true
    },
    headers: {
      'Access-Control-Allow-Origin': '*',
    }
  }
};

三、 创建子程序

在项目目录中创建子程序subapp-time、subapp-news
注:与主程序同级目录

	> vue create subapp-time
	> vue create subapp-news

1. 修改App.vue

<template>
  <div id="app">
    <router-link to="/">Home</router-link>
     <router-link to="/about">About</router-link>
    <router-view />
  </div>
</template>

<script>
export default {
  name: "root-view",
  props: {
    loading: Boolean,
    content: String,
  },
};
</script>

2. 修改main.js

	重点:
	1.mount 方法中 base的 /aaa 与主应用注册子应用函数genActiveRule("/aaa")内的参数一致
import Vue from "vue";
import VueRouter from "vue-router";
import App from "./App.vue";
import "./public-path";
import routes from "./router";

Vue.config.productionTip = false;

// 声明变量管理vue及路由实例
let router = null;
let instance = null;

// 导出子应用生命周期 挂载前
export async function bootstrap(props) {
  console.log(props);
}

// 导出子应用生命周期 挂载前 挂载后
// **注意,实例化路由时,判断当运行在qiankun环境时,路由要添加前缀,前缀与主应用注册子应用函数genActiveRule("/aaa")内的参数一致**
export async function mount(props) {
  console.log(props)
  router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? "/aaa" : "/",
    mode: "hash",
    routes
  });
  instance = new Vue({
    router,
    render: h => h(App)
  }).$mount("#app");
}

// 导出子应用生命周期 挂载前 卸载后
export async function unmount() {
  instance.$destroy();
  instance = null;
  router = null;
}

// 单独开发环境
mount();

3. 修改router.js

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

Vue.use(VueRouter)
const routes = [
  {
    path: "/",
    name: "home",
    component: () =>
      import("../views/Home.vue")
  },
  {
    path: "/about",
    name: "a-about",
    component: () =>
      import("../views/About.vue")
  }
];

export default routes;

4. src下创建public-path.js

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

5. 修改vue.config.js

	重点:
	1.这里的port要与主程序 main.js 中 registerMicroApps 对应的 entry 一致
	2.port为端口号,尽量不要与主程序及其他子程序端口号产生冲突
const path = require('path');
const { name } = require('./package');

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

const port = 7771; // dev port

module.exports = {
  outputDir: 'dist',
  assetsDir: 'static',
  filenameHashing: true,
  devServer: {
    // host: '0.0.0.0',
    hot: true,
    disableHostCheck: true,
    port,
    overlay: {
      warnings: false,
      errors: true,
    },
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  // 自定义webpack配置
  configureWebpack: {
    resolve: {
      alias: {
        '@': resolve('src'),
      },
    },
    output: {
      // 把子应用打包成 umd 库格式
      library: `${name}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${name}`,
    },
  },
 }

四、 最后

demo目录

在这里插入图片描述 在这里插入图片描述

补依赖

	npm run cinit

启项目

	npm run serve
	
	需要注意的是,起完服务后需要等待一段时间后再进,起项目需要时间。

打包

	npm run build

如果有更漂亮的写法欢迎来讨论,让我们一起有条不紊的持续进步。
喜欢的话不妨点个小小的赞与关注,您的赞与关注将是我源源不断的前进动力。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值