项目背景说明
-
后台管理部分使用的技术栈是Vue2,前台可视化部分使用的技术栈是Vue3
-
前台可视化项目不是独立存在,而是和后台管理项目共享同一个登录页面
微前端的好处
微前端是一种前端架构模式,它将大型单体应用程序分解为小的、松散耦合的部分,每个部分都可以独立开发、测试和部署。微前端的好处如下:
-
增强团队独立性
-
提高可维护性
-
提高性能
总之,微前端使开发人员可以更容易地构建、维护和扩展大型单体应用程序,从而提高了应用程序的质量和可靠性
乾坤方案改造
qiankun - qiankun
主应用改造(后台管理)
安装乾坤
npm i qiankun
新增配置文件
import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
{
name: 'hmzs-big-screen', // 子应用名称
entry: '//localhost:5173', // 子应用运行服务地址(就是npm run dev时的那个地址)
container: '#container', // 挂载容器(id=container)
activeRule: '/big-screen' // 激活路由(在哪个路由下加载子应用,需要和子应用的路由名称对应)
}
])
start()
入口文件启动
// 启动微前端配置
import './registerMicroApp'
配置子应用渲染的位置
<template>
<div id="app">
<router-view />
<!-- 子应用挂载节点 -->
<div id="container" />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
子应用改造(前台可视化)
说明: qiankun默认不支持vite项目作为子应用,需要借助 vite-qiankun
插件进行支持
配置vite-qiankun插件
npm i vite-plugin-qiankun -D
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
base: '/',
plugins: [
vue(),
// 这里的名称要和主应用改造是配置项中的name保持一致
qiankun('hmzs-big-screen', {
useDevMode: true
})
],
server: {
// 防止开发阶段的assets 静态资源加载问题
origin: '//localhost:5173'
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
}
}
})
2- 入口文件改造
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
import './styles/common.scss'
// 使用乾坤渲染
renderWithQiankun({
// 挂载时
mount (props) {
console.log('mount')
render(props)
},
bootstrap () {
console.log('bootstrap')
},
unmount (props) {
console.log('unmount', props)
},
})
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render({})
}
function render (props = {}) {
const { container } = props
const app = createApp(App)
app.use(router)
app.mount(container ? container.querySelector("#app") : "#app")
}
大屏按钮跳转
<div class="avatar-wrapper">
<el-button size="small" plain
@click="$router.push('/big-screen')">可视化大屏</el-button>
<!-- 用户名称 -->
<span class="name">黑马管理员</span>
</div>
微前端配置易错点
1. 保证子应用已经运行
-
测试时需要保证子应用项目已经run了起来,因为主应用需要从子应用的服务拉取资源
-
子应用run的服务地址要和主应用中的
entry
选项要严格保持一致(注意端口号)
2. 准备好挂载容器
作为子应用的挂载节点 也就是 container
容器要准备好,否则没有挂载的位置
3. 开发环境修复静态资源的路径
子应用里需要配置一下server选项的origin选项,否则加载assets文件夹中的资源会默认寻找主应用下的assets文件夹
server: {
// 防止开发阶段的assets 静态资源加载问题
origin: '//localhost:5173'
}
乾坤基础原理说明(直接观看拓展视频)
1. 基础运行原理
-
监听路由变化
-
匹配子应用
-
加载子应用
-
渲染子应用
2. 核心代码实现
// 用来加载子应用html并解析
import importHTML from 'import-html-entry'
// 重新路由
function rewriteRouter () {
// 针对 go/back
window.addEventListener('popstate', () => {
loadMicroApp()
})
// 针对pushState
const rawPushState = window.history.pushState
window.history.pushState = async (...rest) => {
rawPushState.apply(window.history, rest)
console.log('监听到 pushState 方法')
// 加载子应用
loadMicroApp()
}
}
// 加载子应用资源
let _activeMicroApp = null
function loadMicroApp () {
// 1. 匹配激活路由 并加载子应用html
const path = window.location.pathname
const microApps = getMicroApp()
const microAppConfig = microApps.find(app => app.activeRule === path)
_activeMicroApp = _activeMicroApp || microAppConfig
console.log('当前配置', microAppConfig)
if (microAppConfig) {
// 挂载
importHTML(microAppConfig.entry).then(async res => {
// 2. 获取模版
const template = res.template
const container = document.querySelector(microAppConfig.container)
container.innerHTML = template
// 2. 获取脚本并执行
await res.execScripts()
window.__qiankunMount()
})
} else {
// 卸载
const container = document.querySelector(_activeMicroApp.container)
container.innerHTML = ''
_activeMicroApp = null
window.__qiankunUnMount()
}
}
// 注册子应用配置
let microApps = []
function registerMicroApp (configArr) {
microApps = configArr
}
function getMicroApp () {
return microApps
}
// 启动方法
function start () {
rewriteRouter()
}
// 导出通用方法
export {
registerMicroApp,
start
}
3. 测试使用
主应用配置
// 注册微应用配置
registerMicroApp([
{
name: 'big-screen',
entry: '//127.0.0.1:5500/',
container: '#container',
activeRule: '/big-screen'
}
])
start()
子应用配置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我是子应用</title>
<style>
#root {
width: 500px;
height: 400px;
background-color: royalblue;
color: #fff;
}
</style>
</head>
<body>
<div id="root">
<button id="btn">toggleColor</button>
</div>
<script>
const btn = document.querySelector('#btn')
const root = document.querySelector('#root')
btn.addEventListener('click', () => {
root.style.backgroundColor = 'red'
})
// 模拟生命周期函数
function mount () {
console.log('mount by 乾坤')
}
function unMount () {
console.log('unMount by 乾坤')
}
window.__qiankunMount = mount
window.__qiankunUnMount = unMount
</script>
</body>
</html>
实际上线的流程说明
说明:前端需要做的事情就是配合发布
-
确保提交的分支正确,分支代码里没有非常明显的错误,如代码冲突
-
因为部署平台要执行打包命令,这个打包命令是前端提供的,这里要对接好,并且打包时的优化要前端自己做
配置环境变量
认识环境变量
概念:同一个“变量”的值可以根据不同的环境自动切换与环境相对应的值,这样的变量就称之为环境变量
场景:项目上线时,我们的接口基地址发生了变化:由(https://api-hmzs.itheima.net/v1)
变成了(https://api-hmzs.itheima.net/api)
如果适配开发阶段和上线之后的不同的接口基地址呢?答案就是使用环境变量,它可以做到在开发环境时接口走接口A,在上线之后走接口B。
环境变量的定义和使用
定义位置和运行机制
对应环境 | 文件 | 说明 |
---|---|---|
开发环境 | .env.development | 当运行vue-cli-service serve |
的时候会以此文件为配置文件,这个文件中可以定义针对开发环境的环境变量 | ||
生产环境 | .env.production | 当运行vue-cli-service build |
的时候会以此文件为配置文件,这个文件中可以定义针对生产环境的环境变量 |
定义环境变量
定义环境变量采用 key = value
的语法进行定义,其中key表示环境变量名称 value表示环境变量值
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = 'https://api-hmzs.itheima.net/v1'
使用环境变量
使用环境变量采用固定的前缀 process.env.环境变量名
,环境变量名要与定义时的保持一致
process.env.VUE_APP_BASE_API
配置开发和生产环境下的baseURL
# just a flag
ENV = 'development'
VUE_APP_BASE_URL = 'https://api-hmzs.itheima.net/v1'
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_URL= 'https://api-hmzs.itheima.net/api'
客户端环境变量的注意事项
-
客户端代码其实就是我们的
src目录
,如果在这个目录下使用环境变量,只能识别NODE_ENV
BASE_URL
和以VUE_APP_
打头的环境变量,其它变量不可识别,非客户端代码没有此要求。其中NODE_ENV
可以自定义覆盖, BASE_URL 覆盖不了 -
为避免记忆负担,在业务中自定义环境变量的时候,推荐采用严格的
VUE_APP
变量前缀打头
微前端项目部署(了解)
服务器环境准备
我们在本地使用Node准备好了两台服务器:
-
serverforadmin为服务器A,是后台管理项目部署的位置,服务地址为
http://localhost:8086
-
serverforbigscreen为服务B,是前台可视化项目部署位置, 服务地址为
http://localhost:8089
-
每一个服务中都有一个
public文件夹
,它是静态服务文件夹,是放置我们打包之后的代码的 -
对俩个项目分别进行打包,然后把生成的dist目录下的文件放到对应的服务器的public文件夹中
根据环境切换加载子应用的地址
子应用大屏项目在开发时的服务地址为 http://localhost:5173/big-screen
,在上线之后变成了http://localhost:5173/big-screen
,为了适配上线之后的解析路径,我们根据当年所处的环境适配一下加载子应用的地址 process.env.NODE_ENV 可以拿到当前运行的环境,是生产还是开发 development为开发环境。
import { registerMicroApps, start } from 'qiankun'
const isDev = process.env.NODE_ENV === 'development'
registerMicroApps([
{
name: 'hmzs-big-screen',
entry: `${isDev ? '//localhost:5173' : '//localhost:8089'}`,
container: '#container',
activeRule: '/big-screen'
}
])
start()
更改子应用的base配置
vite.config.js中的配置项里有一个base配置,它决定了项目启动时的静态资源,比如js,css从哪个服务器下去获取,因为上线之后,子应用大屏项目的服务器地址变成了 http://localhost:8089
,所以把base配置为 http://localhost:8089。
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
base: 'http://localhost:8089/',
plugins: [vue(), qiankun('hmzs-big-screen', {
useDevMode: true
})],
server: {
// 解决开发环境下的静态资源访问问题
origin: '//127.0.0.1:5173'
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
}
}
})
更改子应用的路由
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory()
})
export default router
打包独立部署到服务器
在俩个项目中分别执行打包命令,生成打包文件之后,把打包文件手动拷贝到对应的服务器的public文件夹里 执行 node app.js
启动对应的服务器。