本文介绍 Vue 项目如何实现前端微服务
一、前言
什么是微前端
Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. -- Micro Frontends
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
更多关于微前端的相关介绍,推荐大家可以去看这几篇文章:
qiankun
qiankun 是蚂蚁金服开源的一套完整的微前端解决方案。具体描述可查看 文档 和 Github。
下面将通过一个微服务Demo 介绍 Vue 项目如何接入 qiankun,代码地址:micro-front-vue
二、配置主应用
- 使用 vue cli 快速创建主应用;
- 安装 qiankun
$ yarn add qiankun # 或者 npm i qiankun -S复制代码
- 调整主应用 main.js 文件:具体如下:
import Vue from "vue"import App from "./App.vue"import router from "./router"import { registerMicroApps, setDefaultMountApp, start } from "qiankun"Vue.config.productionTip = falselet app = null;/** * 渲染函数 * appContent 子应用html内容 * 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; } }/** * 路由监听 * @param {*} routerPrefix 前缀 */function genActiveRule(routerPrefix) { return location => location.pathname.startsWith(routerPrefix); }function initApp() { render({ appContent: '', loading: true }); } initApp();// 传入子应用的数据let msg = { data: { auth: false }, fns: [ { name: "_LOGIN", _LOGIN(data) { console.log(`父应用返回信息${data}`); } } ] };// 注册子应用registerMicroApps( [ { name: "sub-app-1", entry: "//localhost:8091", render, activeRule: genActiveRule("/app1"), props: msg }, { name: "sub-app-2", entry: "//localhost:8092", render, activeRule: genActiveRule("/app2"), } ], { beforeLoad: [ app => { console.log("before load", app); } ], // 挂载前回调beforeMount: [ app => { console.log("before mount", app); } ], // 挂载后回调afterUnmount: [ app => { console.log("after unload", app); } ] // 卸载后回调 } );// 设置默认子应用,与 genActiveRule中的参数保持一致setDefaultMountApp("/app1");// 启动start();复制代码
- 修改主应用 index.html 中绑定的 id ,需与 el 绑定 dom 为一致;
- 调整 App.vue 文件,增加渲染子应用的盒子:
<template> <div id="main-root"> <!-- loading --> <div v-if="loading">loading</div> <!-- 子应用盒子 --> <div id="root-view" class="app-view-box" v-html="content"></div> </div> </template> <script> export default { name: "App", props: { loading: Boolean, content: String } }; </script>复制代码
- 创建 vue.config.js 文件,设置 port :
module.exports = { devServer: { port: 8090 } }复制代码
三、配置子应用
- 在主应用同一级目录下快速创建子应用,子应用无需安装 qiankun
- 配置子应用 main.js:
import Vue from 'vue';import VueRouter from 'vue-router';import App from './App.vue';import routes from './router';import './public-path'; Vue.config.productionTip = false;let router = null;let instance = null;function render() { router = new VueRouter({ base: window.__POWERED_BY_QIANKUN__ ? '/app1' : '/', mode: 'history', routes, }); instance = new Vue({ router, render: h => h(App), }).$mount('#app'); }if (!window.__POWERED_BY_QIANKUN__) { render(); }export async function bootstrap() { console.log('vue app bootstraped'); }export async function mount(props) { console.log('props from main app', props); render(); }export async function unmount() { instance.$destroy(); instance = null; router = null; }复制代码
- 配置 vue.config.js
const path = require('path');const { name } = require('./package');function resolve(dir) { return path.join(__dirname, dir); }const port = 8091; // dev portmodule.exports = { /** * You will need to set publicPath if you plan to deploy your site under a sub path, * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/, * then publicPath should be set to "/bar/". * In most cases please use '/' !!! * Detail: https://cli.vuejs.org/config/#publicpath */outputDir: 'dist', assetsDir: 'static', filenameHashing: true, // tweak internal webpack configuration.// see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.mddevServer: { // 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}`, }, }, };复制代码
其中有个需要注意的点:
- 子应用必须支持跨域:由于 qiankun 是通过 fetch 去获取子应用的引入的静态资源的,所以必须要求这些静态资源支持跨域;
- 使用 webpack 静态 publicPath 配置:可以通过两种方式设置,一种是直接在 mian.js 中引入 public-path.js 文件,一种是在开发环境直接修改 vue.config.js:
{ output: {publicPath: `//localhost:${port}`; } }复制代码
public-path.js 内容如下:
if (window.__POWERED_BY_QIANKUN__) { // eslint-disable-next-line no-undef __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ }复制代码
至此,Vue 项目的前端微服务已经简单完成了。
但是在实际的开发过程中,并非如此简单,同时还存在应用间跳转、应用间通信等问题。
代码、文章 持续更新中...