registermodule 微前端_qiankun + vue + element 微前端实践

qiankun + vue + element 的微前端架构项目,主项目与子应用均使用vue。支持三大前端框架可根据自己需求调整。

微前端 qiankun

微前端是什么、为什么要做微前端、qiankun是什么这些笔者将不再叙述,在前端微服务话提出的两年里已经有过了很多次的讨论和“定义”。

qiankun有兴趣的可以搜一下。

暂时还对这方面未有过了解的同学-> 传送门:可能是你见过最完善的微前端解决方案, qiankun

简单使用教程

鉴于qiankun文档只有寥寥十几行,这里做一个简单的概述(搬运)。

话不多说上步骤及代码:

创建一个主项目工程目录

npm install qiankun

改造主项目入口文件:

main.js// 导入qiankun依赖

import {

registerMicroApps,

runAfterFirstMounted,

setDefaultMountApp,

start

} from "qiankun";

function render({ appContent, loading }) {

if (!app) {

app = new Vue({

el: "#container",

router,

store,

data() {

return {

content: appContent,

loading

};

},

render(h) {

return h(App, {

props: {

content: this.content,

loading: this.loading

}

});

}

});

} else {

app.content = appContent;

app.loading = loading;

}

};

function genActiveRule(routerPrefix) {

return location => location.pathname.startsWith(routerPrefix);

}

render({loading: true});

// 注册子应用

registerMicroApps(

[{

name: "app1"

entry: "//localhost:7771",

render,

activeRule: genActiveRule("/app1")

props: 'mg' // 传递给子应用

}],

{

beforeLoad: [

app => {

console.log("before load", app);

}

],

beforeMount: [

app => {

console.log("before mount", app);

}

],

afterUnmount: [

app => {

console.log("after unload", app);

}

]

}

)

// 设置默认子应用

setDefaultMountApp("/app1");

// 第一个子应用加载完毕回调

runAfterFirstMounted();

// 启动微服务

start();

// 注意, 主应用的el绑定dom为#container,因此你也需要修改一下index.hrml模板中的id

app.vue 增加一个渲染子应用的盒子

export default {

name: "root-view",

props: {

loading: Boolean,

content: String

}

};

创建一个子项目工程目录并改造子应用

vue.comfig.jsconst path = require("path");

const packageName = require("./package.json").name;

function resolve(dir) {

return path.join(__dirname, dir);

}

const port = 7771; // dev port

module.exports = {

outputDir: "dist",

assetsDir: "static",

// 默认在生成的静态资源文件名中包含hash以控制缓存

filenameHashing: true,

lintOnSave: false,

devServer: {

hot: true,

disableHostCheck: true,

port,

overlay: {

warnings: false,

errors: true

},

headers: {

"Access-Control-Allow-Origin": "*"

}

},

// 自定义webpack配置

configureWebpack: {

resolve: {

alias: {

"@": resolve("src")

}

},

output: {

//把子应用打包成 umd 库格式

library: `${packageName}-[name]`,

libraryTarget: "umd",

jsonpFunction: `webpackJsonp_${packageName}`

}

}

};

main.jsimport Vue from "vue";

import VueRouter from "vue-router";

import App from "./App.vue";

import "./public-path";

import routes from "./router";

import store from "./store";

import "./plugins/element.js";

import "@/assets/css/demo.min.css"

Vue.config.productionTip = false;

let router = null;

let instance = null;

// 导出子应用生命周期到父应用

export async function bootstrap(props) {

console.log(props)

}

export async function mount() {

router = new VueRouter({

base: window.__POWERED_BY_QIANKUN__ ? "/app1" : "/",

mode: "history",

routes

});

instance = new Vue({

router,

store,

render: h => h(App)

}).$mount("#app");

}

export async function unmount() {

instance.$destroy();

instance = null;

router = null;

}

// 子应用单独开发环境

window.__POWERED_BY_QIANKUN__ || mount();

眼尖的同学可能看到了我们在main.js引入了一个public-path,其他的大家都眼熟那么这个public-path是什么东西?

main.js同级增加public-path.js。或者你喜欢的其他地方。// 仅仅配置下公共路径

if (window.__POWERED_BY_QIANKUN__) {

// eslint-disable-next-line no-undef

__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;

}

需要注意的是,我们对vue的router.js导出做了一点小小的改动。(你也可以不改动,在main.js也就无需router = null)。// 我们将导出的实例化之后的router改为只导出了路由数据

const routes = [

{

path: "/",

name: "home",

component: Home

},

{

path: "/about",

name: "about",

// route level code-splitting

// this generates a separate chunk (about.[hash].js) for this route

// which is lazy-loaded when the route is visited.

component: () =>

import(/* webpackChunkName: "about" */ "../views/About.vue")

}

];

/* const router = new VueRouter({

mode: "history",

routes

}); */

export default routes;

经过上述改造,一个简易的微前端环境就草草建成了,是不是很简单,你是不是已经跃跃欲试了?

父子应用通信

在上述所建微前端应用中,父子间的通信是极其普遍且无法绕过的需求,而qiankun在这方面当然有所考虑。

在上述构建项目步骤中,有一步是在主应用main.js注册子应用:

registerMicroApps(

[{

name: "app1"

entry: "//localhost:7771",

render,

activeRule: genActiveRule("/app1")

props: 'mg' // 传递给子应用

}],

)

其中props参数即为传递给子应用的数据,其内容你可以自由定制。

子应用在main.js导出的生命周期函数中均可接收到所传props数据:

export async function bootstrap(props) {

console.log(props)

}

其props的应用类似于react框架的父子组件通信,传入data数据供自组件使用,传入fn函数给子组件触发向上回调。

按照这个思路我们将主应用的main.js和子应用的main.js都改造一番:

改造后的主应用main.js

...

// 定义传入子应用的数据

let msg = {

data: {

auth: false

},

fns: [

{

name: "LOGOUT_",

LOGOUT_(data) {

alert('父应用返回信息:' + data)

}

}

]

};

// 注册子应用

registerMicroApps(

[{

name: "app1"

entry: "//localhost:7771",

render,

activeRule: genActiveRule("/app1")

props: msg // 将定义好的数据传递给子应用

// 注意:通常这里会通过获取后台数据异步传入,具体不再细说

}],

{

beforeLoad: [

app => {

console.log("before load", app);

}

],

beforeMount: [

app => {

console.log("before mount", app);

}

],

afterUnmount: [

app => {

console.log("after unload", app);

}

]

}

)

// 设置默认子应用

setDefaultMountApp("/app1");

// 第一个子应用加载完毕回调

runAfterFirstMounted();

// 启动微服务

start();

改造后的子应用main.js

...

let router = null;

let instance = null;

// 导出子应用生命周期到父应用

export async function bootstrap(props = {}) {

// 将主应用传递过来的函数挂在vue原型方面全局使用

// 你也可以在mount中接收挂在methods或者直接设定传入mixin,坏处便是框架耦合度太大不符合微前端思想

Array.isArray(props.fns) && props.fns.map(i => {

Vue.prototype[i.name] = i[i.name]

});

}

export async function mount() {

router = new VueRouter({

base: window.__POWERED_BY_QIANKUN__ ? "/app1" : "/",

mode: "history",

routes

});

instance = new Vue({

router,

store,

render: h => h(App)

}).$mount("#app");

}

export async function unmount() {

instance.$destroy();

instance = null;

router = null;

}

// 子应用单独开发环境

window.__POWERED_BY_QIANKUN__ || mount();

一个简单的基于qiankun和vue的示例就这么结束啦

当然我们需要考虑的还有很多,但是我前天刚买的狼叔的【前端架构:从入门到微前端】告诉我们,架构是一件持续性和渐进式的事儿,其他的后续再说吧~~~

另附Github上的demo地址:wl-qiankun。不想看我在这罗里吧嗦的直接代码跑起吧,如果你觉得还有一点点可以,就请留个star吧~

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页