Микро интерфейсный фреймворк Qiankun Project Combat (1) - локальная разработка

внешний интерфейс
Микро интерфейсный фреймворк Qiankun Project Combat (1) - локальная разработка

Всем привет, я Сяо Хей.

Компания использует vue в качестве технологического стека и недавно столкнулась с необходимостью перенести функциональные модули исходной системы управления фоном в новую систему управления фоном. Изначально это было не слишком сложно, просто копировал и вставлял и модифицировал, но там столько ям, что я сразу впал в медитацию:

1. В новом фоне используется vue3, а в исходном фоне — vue2.

2. Новый фон имеет собственный набор схем управления правами входа в систему, а старый фон также имеет

3. Поскольку разница между vue3 и vue2 все еще относительно велика, vue3 эквивалентен перезаписи всего vue.Хотя он обратно совместим, скопировать и вставить его напрямую нереально (в основном потому, что я пытался скопировать модуль в прошлом.Красный цвет devtools ужасает)

Что делать, переписать модуль, написанный на vue2, на vue3 (удушающий)? Когда я собирался печатать на клавиатуре со слезами на глазах, я подумал о связанных статьях о микроинтерфейсе, которые я читал раньше.Почему бы мне не попробовать это, и тогда микроинтерфейс официально шагнул на яме

Что такое микрофронтенд?

Согласно Интернету и пониманию Сяо Хэя, микроинтерфейс应用分割,独立运行,独立部署, оригинальный метод концентрации всех функций в одном проекте трансформируется в функцию, которая разделена на основной проект и несколько подпроектов в соответствии с бизнесом, каждый подпроект отвечает за свои функции и имеет возможность общаться с другие подпроекты и основной проект, Для достижения более подробной и легкой в ​​управлении цели. В общем, микрофронтенды

Полное приложение разделено на основное приложение и одно или несколько микроприложений, которые независимы друг от друга и могут взаимодействовать друг с другом.

Как реализовать микрофронтенд?

Соблюдайте вышеуказанные условия, проще всего придумать iframe, вставьте два простейших iframe и его код связи ниже.

// parent.html
<div>我是parent</div>
<button id="parentBtn">parent btn</button>
<iframe src="./child.html" id="frame"></iframe>

<script>  
function parentFunc(msg) {    
  console.log("parent 的方法:", msg)  
}  

var btn = document.querySelector("#parentBtn")  
btn.addEventListener('click', function() {    
  console.log("我是parent的button")    
  console.log("我调用了:")    
  document.getElementById('frame').contentWindow.childFunc('parent');  
})
</script>

// child.html
<div>我是child</div>
<button id="childBtn">child btn</button>
<script>  
function childFunc(msg) {    
  console.log("child 的方法:", msg)  
}  

var btn = document.querySelector("#childBtn")  
btn.addEventListener('click', function() {    
  console.log("我是child的button")    
  console.log("我调用了:")    
  parent.window.parentFunc('child');   
})
</script>

Вышеупомянутые два фрагмента кода помещаются на локальный сервер следующим образом.

Затем нажмите две кнопки, вы можете общаться друг с другом и передавать параметры

Вышеуказанные два html должны быть запущены в среде с доменным именем, иначе будет сообщено об ошибке

Конечно, в этой миграции проекта я не использовал iframe для преобразования напрямую, а стоял на плечах гигантов, для преобразования я использовал микроинтерфейсный фреймворк под названием qiankun, потому что я не могу вставить код компании, я его создам ниже Проект vue3 и проект vue2, чтобы примерно восстановить то, как я преобразовал проект компании, и как заполнить ямы, с которыми я столкнулся

Микроинтерфейсный фреймворк qiankun

сначала вставитьофициальный сайт Цянькунь, вы можете сначала взглянуть на его введение и связанный с ним API.

Во-первых, используйте официальные леса vue для создания базового фонового интерфейса vue3 и базового фонового интерфейса vue2.Обратите внимание, что, поскольку vue3 упакован и использует vite, фреймворк qiankun не может использовать vue3 в качестве микроприложения, здесь наше основное приложение это vue3, микро-приложение vue2, то же самое, что я преобразовал Два проекта имеют одинаковую структуру, как показано ниже.

Для удобства всех вставьте адрес склада шаблона, который я построил

шаблон vue3:git ee.com/Jim PP/v UE3-…(Основное приложение, главное приложение должно установить qiankun)

шаблон vue2:git ee.com/Jim PP/v UE2-…(Микро приложение)

Вышеупомянутая ветка master — это проект, который может работать самостоятельно до преобразования, а ветка dev — это проект после окончательного преобразования.Конечно, также возможно построить его от начала до конца, но необходимо обеспечить что оба репозитория имеют функции маршрутизатора, хранилища и перехвата входа в систему.

Оба шаблона имеют этот интерфейс

1. Интерфейс входа

Кхм, это немного потрепанно, пожалуйста, не бейте меня, чтобы показать это, ха-ха

2. Левое меню и интерфейс просмотра маршрутизатора

Что ж, приступим к трансформации двух проектов на базе qiankun framework

Основное приложение запускает qiankun

Здесь я использую registerMicroApps официального сайта qiankun для регистрации микроприложений.

Создайте новую папку micros в папке src основного приложения и создайте новую в папке micros.index.js,app.js

// index.js
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import {  
  registerMicroApps,  
  addGlobalUncaughtErrorHandler,  
  start,
} from "qiankun";// 微应用注册信息
import apps from "./app";

registerMicroApps(apps, {  
  beforeLoad: (app) => {    
    // 加载微应用前,加载进度条    
    NProgress.start();    
    console.log("before load", app.name);    
    return Promise.resolve();  
  },  
  afterMount: (app) => {    
    // 加载微应用前,进度条加载完成    
    NProgress.done();    
    console.log("after mount", app.name);    
    return Promise.resolve();  
  },
});

addGlobalUncaughtErrorHandler((event) => {  
  console.error(event);  
  const { message: msg } = event  
  if (msg && msg.includes("died in status LOADING_SOURCE_CODE")) {    
  console.error("微应用加载失败,请检查应用是否可运行");  
  }
});
export default start;

первыйyarn add nprogressУстановлена ​​библиотека nprogress для отображения индикатора выполнения при загрузке микроприложения, здесь используется несколько официальных API.

  1. registerMicroApps: Содержит два параметра, первый параметр — некоторая регистрационная информация микроприложения, а второй параметр — глобальная ловушка жизненного цикла микроприложения.

  2. addGlobalUncaughtErrorHandler: глобальный обработчик необработанных исключений, этот API также можно использовать для перехвата ошибок, когда микроприложение сообщает об ошибке.

  3. start: метод, который мы используем для запуска qiankun, включая параметр, использование конкретного параметра подробно не описывается.

Чтобы просмотреть приведенный выше подробный API, нажмитездесь

// app.js

const apps = [  
  {    
    name: "vue-micro-app",    
    entry: "//localhost:8081",    
    container: "#micro-container",    
    activeRule: "#/vue2-micro-app",  
  },
];
export default apps;

app.js экспортирует вышеупомянутыйregisterMicroAppsПервый параметр - это массив объектов, где каждое поле функционирует следующим образом:

  1. name: Имя микроприложения, которое должно соответствовать этому имени при последующей модификации микроприложения

  2. entry: доменное имя и порт работающего микроприложения, я использую локальный порт 8081

  3. container: для запуска микроприложения требуется dom-контейнер, который является идентификатором dom-контейнера, и должна быть возможность использовать класс

  4. activeRule: активировать правило для запуска микроприложения, когда оно обнаружит, что URL-адрес содержит значение activeRule, микроприложение будет запущено.

После добавления двух вышеуказанных js возвращаемся к main.js, текущий main.js должен быть таким

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/assets/main.css'

createApp(App).use(store).use(router).mount('#app')

Преобразование также очень простое, поместите микро в вышеindex.jsимпортировать и запуститьstart函数ты закончил

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/assets/main.css'
import start from '@/micros'


createApp(App).use(store).use(router).mount('#app')

start()

Обновите браузер и обнаружите, что основное приложение ничем не отличается от того, что было до трансформации!

Основное приложение добавляет контейнер микроприложений и меню микроприложений.

Текущая структура кода меню основного приложения выглядит следующим образом.

<div class="nav" v-if="token">    
  <div class="menu">      
    <router-link to="/">Parent Home</router-link>    
  </div>    
  <div class="menu">      
    <router-link to="/about">Parent About</router-link>    
  </div>
</div>

Теперь добавим два меню, соответствующие домашнему и о подприложении.

<div class="nav" v-if="token">    
  <div class="menu">      
    <router-link to="/">Parent Home</router-link>    
  </div>    
  <div class="menu">      
    <router-link to="/about">Parent About</router-link>    
  </div>
    <!--- 新添加 --->
  <div class="menu">      
    <router-link to="/vue2-micro-app">Child Home</router-link>    
   </div>    
  <div class="menu">      
    <router-link to="/vue2-micro-app/about">Child About</router-link>    
   </div>
</div>

<div class="container">   
  <div class="header" v-if="token">Child Header</div>   
  <div class="router-view">      
    <router-view />      
    <!-- 新添加,微应用的容器 -->      
    <div id="micro-container"></div>   
  </div>
</div>

Я считаю, что вы тоже нашли это, есть больше выше вapp.jsизactiveRuleСоответствующее значение в поле (с удаленным #), потому что #/vue2-micro-app — это условие, запускающее запуск микро-приложения.

Это нужно для того, чтобы обновить наше микро-приложение, затем щелкните меню «Детский дом», вы найдете две ошибки.

Первый — отчет об ошибках между доменами, потому что наше основное приложение работает на порту 8080, а микроприложение — на порту 8081. Хорошо использовать nginx в качестве прокси позже.

Вторая ошибка связана с тем, что наше микро-приложение не трансформировалось, так чего же вы ждете, поторопитесь и трансформируйте микро-приложение

Трансформация микроприложений

На официальном сайте написано, запись микроприложения надо экспортироватьbootstrap,mount,unmountТри хука жизненного цикла для вызова основного приложения в нужное время

Это main.js до трансформации микроприложения.

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/assets/main.css'
Vue.config.productionTip = false
new Vue({  
  router,  
  store,  
  render: h => h(App)
}).$mount('#app')

Преобразим main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/assets/main.css'
Vue.config.productionTip = false

// 新增:用于保存vue实例
let instance = null; 

// 新增:动态设置 webpack publicPath,防止资源加载出错
if (window.__POWERED_BY_QIANKUN__) {  
  // eslint-disable-next-line no-undef  
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

/** * 新增: * 渲染函数 * 两种情况:主应用生命周期钩子中运行 / 微应用单独启动时运行 */
function render() {  
// 挂载应用  
  instance = new Vue({    
  router,    
  store,    
  render: (h) => h(App),  
}).$mount("#micro-app");}


/** 
* 新增: 
* bootstrap 只会在微应用初始化的时候调用一次,
  下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。 
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。 
*/
export async function bootstrap() {  
  console.log("VueMicroApp bootstraped");
}

/** 
* 新增: 
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法 
*/
export async function mount(props) {  
  console.log("VueMicroApp mount", props);  
  render(props);
}
/** 
* 新增: 
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例 
*/
export async function unmount() {  
  console.log("VueMicroApp unmount");  
  instance.$destroy();  
  instance = null;
}

// 新增:独立运行时,直接挂载应用
if (!window.__POWERED_BY_QIANKUN__) {  
  render();
}

// 这是原本启动的代码
// new Vue({
//   router,
//   store,
//   render: h => h(App)
// }).$mount('#app')

Обратите внимание, что в методе рендеринга я изменил параметр после $mount на#micro-app, это делается для того, чтобы различать корневой идентификатор index.html в основном приложении и микроприложении, поэтому index.html общей папки в микроприложении также следует изменить на микроприложение.

Затем необходимо преобразовать конфигурацию веб-пакета и добавить корневой каталог микроприложения.vue.config.jsдокумент

const path = require("path");

module.exports = {
  devServer: {
    // 监听端口
    port: 8081,
    // 关闭主机检查,使微应用可以被 fetch
    disableHostCheck: true,
    // 配置跨域请求头,解决开发环境的跨域问题
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
  },
  configureWebpack: {
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "src"),
      },
    },
    output: {
      // 微应用的包名,这里与主应用中注册的微应用名称一致
      library: "vue-micro-app",
      // 将你的 library 暴露为所有的模块定义下都可运行的方式
      libraryTarget: "umd",
      // 按需加载相关,设置为 webpackJsonp_VueMicroApp 即可
      jsonpFunction: `webpackJsonp_vue-micro-app`,
    },
  },
};

Затем нам нужно изменить нашу маршрутизацию

if (window.__POWERED_BY_QIANKUN__) {  
  microPath = '/vue2-micro-app'
}

const routes = [
  {    
    path: microPath + '/login',    
    name: 'login',    
    component: Login  
  },  
  {    
    path: microPath + '/',    
    redirect: microPath + '/home'  
  },  
  {    
    path: microPath + '/home',    
    name: 'Home',    
    component: Home  
  },  
  {    
    path: microPath + '/about',    
    name: 'About',
    component: () => import( /* webpackChunkName: "about" */ '../views/About.vue')  
  }
]

router.beforeEach((to, from, next) => {  
  if (to.path !== (microPath + '/login')) {    
    if (store.state.token) {      
      next()    
    } else {      
      next(microPath + '/login')    
    }  
  } 
  else {    
    next()  
  }
})

Основное изменение в маршрутизации заключается в том, что к каждому пути добавляется переменная microPath, чтобы определить, был ли он изменен микроинтерфейсом. Соответствующая защита маршрутизации также должна добавлять переменную microPath. - скачки входа в приложение.

Наконец, перезапустите наше микро-приложение, а затем перейдите в наше основное приложение и нажмите меню «Детский дом».Если не случайно, вы получите тот же интерфейс, что и мой скриншот ниже.

Да, у вас получилось! Проект vue2 успешно встроен в vue3.

Тем не менее, вы также заметили, что я уже вошел в систему один раз, почему я должен войти в систему снова, поэтому в следующий раз мы должны использовать связь для решения этой проблемы.

Основное приложение и микросхема Micro App

Связь между приложениями, которую мы хотим использоватьqiankunобрамленныйinitGlobalState和MicroAppStateActionsapi, соответствующий API вводится следующим образом:

setGlobalState:настраиватьglobalState- Когда установлено новое значение, будет выполняться внутренний浅检查, если отмеченоglobalStateКогда происходит изменение, запускается уведомление, чтобы уведомить всех观察者функция.

onGlobalStateChange:регистр观察者функция - ответglobalStateизменение, вglobalStateИнициировать это, когда происходит изменение观察者функция.

offGlobalStateChange:Отмена观察者функция - экземпляр больше не отвечаетglobalStateРазнообразие.

Итак, давайте снова преобразуем два проекта, первый — это micros/index.js основного приложения.

import {  
registerMicroApps,  
addGlobalUncaughtErrorHandler,  
start,  
initGlobalState // 新增
} from "qiankun";

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

export {  actions }

Вышеуказанные добавленные и экспортированные действия, затем перейдите в login.vue

import { actions } from "@/micros"; //新增

const login = () => {      
  if (username.value && password.value) {  
    store.commit("setToken", "123456");        
    // 新增
    actions.setGlobalState({globalToken: "123456"});        
    router.push({path: "/"});
  }
};

Введены действия и добавлен метод action.setGlobalState.

Затем main.js подприложения

function render(props) {  
  console.log("子应用render的参数", props) 
  // 新增 
  props.onGlobalStateChange((state, prevState) => {    
    // state: 变更后的状态; prev 变更前的状态    
    console.log("通信状态发生改变:", state, prevState);    
    // 这里监听到globalToken变化再更新store
    store.commit('setToken', '123456')  }, true); 
   // 挂载应用  
  instance = new Vue({    
    router,    
    store,    
    render: (h) => h(App),  
  }).$mount("#micro-app");}

В методе рендеринга мы добавляем onGlobalStateChange, а второму параметру присваиваем значение true, чтобы при запуске микроприложения мы могли сразу увидеть только что установленный globalToken: 123456

Что ж, преобразование завершено, мы обновляем и снова входим в основное приложение, а затем нажимаем меню микроприложения, вы можете видеть, что микроприложению больше не нужно входить в систему, как показано ниже.

Вроде проблема еще есть, как отображается меню микроприложения? ? ?

Не бойтесь, последний шаг, пусть он будет решен за вас, дорогая, идея состоит в том, чтобы использовать его в микро-приложениях.window.__POWERED_BY_QIANKUN__Чтобы судить, было ли оно запущено через qiankun, если да, то давайте напишем переменную и используем v-if, чтобы скрыть меню и заголовок микроприложения, не будет ли это сделано?

Выше приведено все содержание первой локальной разработки актуального фреймворка qiankun.Общая структура очень похожа на миграцию проекта, которую я сделал.Другие мелкие детали не затронуты.На самом деле в этой главе есть огромная яма. следующая статья«Микро-интерфейсный фреймворк проекта qiankun боевой (2) — выход на яму и развертывание»Возьмут все, чтобы развернуть упакованный проект и рассказать всем, где эта гигантская яма

использованная литература

Учебное пособие Mingyuan cloud по qiankun

официальный сайт цинкун