首页 > 自考资讯 > 高考百科

微前端开发(Vue)(vue 微前端技术选型)

小条 2024-10-01

templatediv class='zibo-custom-web' div id='zibo-custom-web' class='app-view-box'/div/div/templatescriptexport default {};/scriptstyle lang='scss'scoped.zibo- custom-web{position:relative;}/style的id属性必须是唯一的,最终的子应用内容将挂载在这里。

ContainerOther.vue代码更改:

!-- 主视图层-- div class='avue-view-contain' v-show='!isSearch' keep-alive router-view class='avue-view keep-alive' v-if='$route. meta.keepAlive isActiveRoute' v-show='!showAppVueHash' //keep-alive router-view class='avue-view' v-if='!$route.meta.keepAlive isActiveRoute' v-show='!showAppVueHash' /AppVueHash v-show='showAppVueHash' //divjs 代码:

import router from '@/router/router';import store from '@/store';import AppVueHash from '@/views/AppVueHash.vue';import {loadMicroApp} from 'qiankun';//子项目路由前缀const isChildRoute=path=website.childRoute.some(item=path.startsWith(item));const apps=[ { name: '/zibo-custom-web', entry: window.configs.VUE_APP_ZIBO_CUSTOM_URL, container: '#zibo-custom-web' , props: { data: { store, router } }, Sandbox: { strictStyleIsolation: true //开启样式隔离} }];//控制手动加载微应用ctrlMicroApp(path){ if (isChildRoute(path)) { this .showAppVueHash=true ; this.$nextTick(()={ //手动加载if(!this.mounted){ this.loadApps=apps.map(item=loadMicroApp(item)) this.mounted=true; } }) ; this .showAppVueHash=false; }这里的容器属性值必须与AppVueHash.vue组件的id值匹配。

根据URL地址判断是否为子应用。如果是子应用程序,则隐藏子应用程序容器并仅加载主应用程序的路由器视图。

首次加载ContainerOther 或路由更改时手动加载微应用。

mount() { this.init(); setTheme(this.themeName); this.ctrlMicroApp(this.$route.path) }, watch: { $route(val) { this.ctrlMicroApp(val.path);}, tagList (newVal,oldVal){ 让starting=''; const childRoute=website.childRoute.forEach((n,i)={ if(ichildRoute.length-1){starts+=`^${n}|`; }else{starts+=`^${n}`; } }) const patt=new RegExp(`${starts}`); //子应用程序选项卡之前已存在const=oldVal.some(item={ return patt) .test (item.value) }); //已添加子应用程序选项卡const=newVal.some(item={ return patt.test(item.value); }); { this .loadApps.forEach;={ app.unmount(); }) } 如果要监控选项卡更改,则需要卸载子应用程序。

3. qiankun子项目zibo-custom-web

将文件public-path.js 添加到src 目录。 if (window.__POWERED_BY_QIANKUN__) { //eslint-disable-next-line no-undef __webpack_public_path__=window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ } 更改Index.html 的项目初始化容器。避免使用#app以避免与其他项目发生冲突。要修改入口文件main.js,我们建议编写一个小的驼峰式div id='appVueHash'/div。 //-------- ---启动子应用的微前端-----let router=null;let instance=null; function render({ data={} ,container }={ }) { router=new VueRouter({route, }); instance=new Vue({ router, store, data(){ return {parentRouter: data.router,parentVuex: data .store, } }, render: h( App), } ).$mount(container?container.querySelector('#appVueHash') : '#appVueHash');}if (!window.__POWERED_BY_QIANKUN__) { render();} //测试全局变量污染console.log('window .a',window.a)导出异步函数bootstrap() { console.log('vue app bootstraped');}导出异步函数mount(props) { console.log('来自主框架的props', props .data) ; render(props);} 异步函数导出{instance.$destroy();}//----- - -----子应用微前端-

------------------  主要改动是:引入修改 publicPath 的文件和export 三个生命周期。   注意: webpack 的 publicPath 值只能在入口文件修改,之所以单独写到一个文件并在入口文件最开始引入,是因为这样做可以让下面所有的代码都能使用这个。路由文件需要 export 路由数据,而不是实例化的路由对象,路由的钩子函数也需要移到入口文件。在 mount 生命周期,可以拿到父项目传递过来的数据,router 用于跳转到主项目/其他子项目的路由,store 是父项目的实例化的 Vuex(也可以传递其他数据过来)。修改打包配置 vue.config.js:const { name } = require("./package");module.exports = { outputDir: "../sass-base-web/cicd-config/test/zibo-custom-web", devServer: { port: 9010, // 关闭主机检查,使微应用可以被 fetch disableHostCheck: true, // 配置跨域请求头,解决开发环境的跨域问题 headers: { "Access-Control-Allow-Origin": "*", }, proxy: { "/api": { //本地服务接口地址 target: "http://192.168.10.112:10067", //cas ws: true, pathRewrite: { "^/api": "/", }, }, }, }, // 以下配置可以修复一些字体文件加载路径问题 chainWebpack: (config) => { //忽略的打包文件 config.externals({ vue: "Vue", "vue-router": "VueRouter", vuex: "Vuex", axios: "axios", "element-ui": "ELEMENT", }); config .plugin('html') .tap(args => { args[0].name = name; return args }); config.module .rule("fonts") .test(/.(ttf|otf|eot|woff|woff2)$/) .use("url-loader") .loader("url-loader") .tap((options) => ({ name: "/fonts/[name].[hash:8].[ext]" })) .end(); }, // 自定义webpack配置 configureWebpack: { output: { library: `${name}-[name]`, // 微应用的包名,这里与主应用中注册的微应用名称一致 libraryTarget: "umd", // 把子应用打包成 umd 库格式 jsonpFunction: `webpackJsonp_${name}`, //webpack打包之后保存在window中的key,各个子应用不一致 }, },};  这里主要就两个配置,一个是允许跨域,另一个是打包成 umd 格式。为什么要打包成 umd 格式呢?是为了让 qiankun 拿到其 export 的生命周期函数。   注意: 这个 name 默认从 package.json 获取,可以自定义,只要和父项目注册时的 name 保持一致即可。   vue.config.js中 outputDir: "../sass-base-web/cicd-config/test/zibo-custom-web",  这里我子应用项目编译后会将打包文件打包到sass-base-web项目中的zibo-custom-web下。 路由动态加载  需要给子项目所有的路由都添加一个前缀,子项目的路由跳转如果之前使用的是 path 也需要修改,用name 跳转则不用。   avue-router.js: const oRouter = { path: "/zibo-custom-web", name: "RouterView", component(resolve) { require(["@/components/RouterView.vue"], resolve); }, children: [ { path: path, component(resolve) { require([`../${component}.vue`], resolve); }, name: name, meta: meta, }, ], }; aRouter.push(oRouter);4. 状态管理,主应用和微应用之间的通信   qiankun 通过 initGlobalState: 定义全局状态,并返回通信方法,建议在主应用使用,微应用通过props 获取通信方法;   onGlobalStateChange: 在当前应用监听全局状态,有变更触发 callback;   setGlobalState: 按一级属性设置全局状态,微应用中只能修改已存在的一级属性; 换句话说只能修改主用于预先定义的属性,后面添加的属性无效。   官方例子:发布-订阅的设计模式:   主应用: import { initGlobalState, MicroAppStateActions } from 'qiankun';// 初始化 stateconst actions: MicroAppStateActions = initGlobalState(state);actions.onGlobalStateChange((state, prev) => { // state: 变更后的状态; prev 变更前的状态 console.log(state, prev);});actions.setGlobalState(state);actions.offGlobalStateChange();  子应用: // 从生命周期 mount 中获取通信方法,使用方式和 master 一致export function mount(props) { props.onGlobalStateChange((state, prev) => { // state: 变更后的状态; prev 变更前的状态 console.log(state, prev); }); props.setGlobalState(state); }  如果主应用和子应用都是vue技术栈,可以在子应用中把数据传递给子应用,例如store。 props: { data: { store, router } }, 5. 各应用之间的独立仓库以及聚合管理   实际开发中项目存储在公司仓库中,以 gitLab 为例, 当子应用一多,全部放在一个仓库下面, 这时候就显得很臃肿了,也很庞大,大大的增加了维护成本,和开发效率; 我们可以通过 sh 脚本, 初始只需要克隆主仓库代码, 然后通过 sh 脚本去一键拉取所有子应用代码。   这里我将单独创建一个用来编译和打包的主仓库项目sass-base-web,仓库地址:http://192.168.1.102/zouqiongjun/sass-base-web.git。   项目根目录下,新建 script/clone-all.sh 文件,内容如下: # 子服务 gitLab 地址SUB_SERVICE_GIT=('http://192.168.1.102/zouqiongjun/big-data-web.git' 'http://192.168.1.102/zouqiongjun/zibo-custom-web.git')SUB_SERVICE_NAME=('big-data-web' 'zibo-custom-web')# 子服务if [ ! -d "sub-service" ]; then echo '创建sub-service目录...' mkdir sub-servicefiecho '进入sub-service目录...'cd sub-service# 遍历克隆微服务for i in ${!SUB_SERVICE_NAME[@]}do if [ ! -d ${SUB_SERVICE_NAME[$i]} ]; then echo '克隆微服务项目'${SUB_SERVICE_NAME[$i]} git clone ${SUB_SERVICE_GIT[$i]} fidone echo '脚本结束...'# 克隆完成  当我们启动主项目的时候,如果想要使用所有子应用的功能,子应用,需要一个一个启动,这样无论是开发还是编译都十分不便。   考虑到国内使用npm装包可能会由于网络的原因安装失败,可以让npm使用国内淘宝镜像。   执行命令:npm config set registry https://registry.npm.taobao.org。   在这个主仓库项目里面,我们只需要安装一个npm-run-all插件。   运行:yarn add npm-run-all -D或者npm i -D。   该项目下只有一个package.json文件,用于配置编译和打包命令,代码如下: { "name": "sass-big-data-web", "version": "1.0.0", "description": "`qiankun`来实现`vue`技术栈的前端微服务", "main": "index.js", "scripts": { "clone:all": "bash ./scripts/clone-all.sh", "install:zibo": "cd ./sub-service/zibo-custom-web && npm install", "install:main": "cd ./sub-service/big-data-web && npm install", "install-all": "npm-run-all install:*", "start:zibo": "cd ./sub-service/zibo-custom-web && npm run serve ",", "start:main": "cd ./sub-service/big-data-web && npm run serve", "start-all": "npm-run-all --parallel start:*", "serve-all": "npm-run-all --parallel start:*", "build:zibo": "cd ./sub-service/zibo-custom-web && npm run build", "build:main": "cd ./sub-service/big-data-web && npm run build", "build-all": "npm-run-all --parallel build:*" }, "repository": { "type": "git", "url": "http://192.168.1.102/zouqiongjun/sass-big-data-web.git" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "npm-run-all": "^4.1.5" }}  要执行yarn clone:all,需要用到bash,跳转到sass-base-web目录,右键鼠标打开Git bash窗口,如下图所示: 19256e52f6d1435e961c5b467ad36539~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728325619&x-signature=s2FCF4upvu9EEPGbliEd1SR7rlg%3D  这样当我们把各个代码仓库的代码都拉取到sub-service这个目录下面来,如下图所示: 05dc5d69d9b34d86b8fef7244c101162~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728325619&x-signature=NnuTQAxlmr3XzHCO%2BO6R5%2FezP9o%3D  代码拉取完成后, 紧接着就是下载各个项目的依赖及运行。   运行npm run serve-all则可以自动执行package.json中配置的命令,这个命令最终会执行以下三个执行命令: "start:zibo": "cd ../zibo-custom-web && npm run serve ", "start:main": "cd ../big-data-web && npm run serve",  这样就不需要我们自己一个一个单独的去运行各个项目了。   总体运行步骤: 第一步 clone 主应用, 然后依次执行 yarn clone:all --> yarn install-all --> yarn start-all 即可运行整个项目。   build-all:可以编译整个项目。   sub-service目录,将其添加到.gitignore当中,因为在sass-base-web项目当中,我们只需要配置和编译及打包用,并不需要真正的将所有子应用的代码都提交到sass-base-web项目中,各子应用都有自己私有的仓库。 6. 子项目开发的一些注意事项   (1)所有的资源(图片/音视频等)都应该放到src 目录,不要放在 public 或者static。资源放 src 目录,会经过 webpack 处理,能统一注入 publicPath。否则在主项目中会404。   (2)避免 css 污染。组件内样式的 css-scoped是必须的。   (3)给 body 、 document 等绑定的事件,请在unmount 周期清除   (4)谨慎使用 position:fixed   在父项目中,这个定位未必准确,应尽量避免使用,确有相对于浏览器窗口定位需求,可以用position: sticky,但是会有兼容性问题(IE不支持)。   常见问题见官网:https://qiankun.umijs.org/zh/faq 7. 部署 1. 常规部署   主应用和微应用都是独立开发和部署,即它们都属于不同的仓库和服务。   场景:主应用和微应用部署到同一个服务器(同一个IP和端口)   如果服务器数量有限,或不能跨域等原因需要把主应用和微应用部署到一起。通常的做法是主应用部署在一级目录,微应用部署在二/三级目录。   若微应用想部署在非根目录,在微应用打包之前需要做两件事: 必须配置 webpack 构建时的 publicPath 为目录名称,更多信息请看 webpack 官方说明 和vue-cli3 的官方说明。history 路由的微应用需要设置 base ,值为目录名称,用于独立访问时使用。  部署之后注意三点: activeRule 不能和微应用的真实访问路径一样,否则在主应用页面刷新会直接变成微应用页面。微应用的真实访问路径就是微应用的 entry,entry 可以为相对路径。微应用的 entry 路径最后面的 / 不可省略,否则 publicPath 会设置错误,例如子项的访问路径是 http://localhost:8080/app1,那么 entry 就是 http://localhost:8080/app1/。  通过配置 nginx 端口到目录的转发。须要对外开放子利用对应的端口,将编译好的利用文件放到对应的配置目录。   跳转到sass-base-web目录,执行npm run build-all,会自动执行所有build:开头的命令: "build:zibo": "cd ../zibo-custom-web && npm run build", "build:control": "cd ../control-center && npm run build", "build:main": "cd ../big-data-web && npm run build", "build-all": "npm-run-all --parallel build:*"  zibo-custom-web目录结构如下图所示: 625b988f35f84b44b4b68e92941d9920~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728325619&x-signature=PcijN%2Firfzm4fb%2Fh2k2gtpDw1IM%3D  这里是子应用和主应用部署在同一台服务器上,且IP和端口相同,nginx不需要额外设置。   如果子应用和主应用部署在同一台服务器上, 但是端口不同,需要修改vue.config.js中的outputDir,这个是打包编译后代码存放的路径,这个不做配置,默认会将代码编译打包到当前根目录下,并生成一个dist目录用于存放编译后的代码,如下图所示: de7d8d23c2734866a7fea174c53fdab0~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728325619&x-signature=rxfM6dd7HJIA9mOa4UmyDCqcDk8%3D修改nginx.conf配置: #gzip on; upstream gateway { server 192.168.31.136:32067;} # 主应用 server { listen 32043; server_name web; root /dist; # 关闭端口重定向 # port_in_redirect off; #charset koi8-r; access_log /var/log/nginx/nginx.log; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location ^~/api/ { proxy_read_timeout 600s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; rewrite ^/api/(.*)$ /$1 break; proxy_pass http://gateway; } } # 子应用 server { listen 9010; server_name cus_web; # 子应用编译后的代码路径 root /zibo-custom-web; # 允许跨域 add_header Access-Control-Allow-Origin *; # 关闭端口重定向 # port_in_redirect off; # charset koi8-r; access_log /var/log/nginx/nginx.log; location ^~/zibo-custom-web/ { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location ^~/api/ { proxy_read_timeout 600s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; rewrite ^/api/(.*)$ /$1 break; proxy_pass http://gateway; } }2. docker nginx 配置   此处 nginx 主要作用是用于端口目录转发,并配置主应用访问子应用的跨域问题。   使用 docker 配置部署 nginx: # docker-compose.ymlversion: '3.1'services: nginx: restart: always image: nginx container_name: nginx ports: - 8888:80 - 8889:8889 - 7100:7100 - 7101:7101 volumes: - /app/volumes/nginx/nginx.conf:/etc/nginx/nginx.conf - /app/volumes/nginx/html:/usr/share/nginx/html - /app/micro/portal:/app/micro/portal - /app/micro/app1:/app/micro/app1 - /app/micro/app2:/app/micro/app2  将编译后的主应用以及子应用放到对应的数据卷挂载目录即可,如主应用 /app/micro/portal。  同理,也需要将配置好的 nginx.conf 文件放到指定的数据卷挂载目录,使用 docker-compose up -d 启动即可。   nginx 端口目录转发配置: # nginx.confuser nginx;worker_processes 1;error_log /var/log/nginx/error.log warn;pid /var/run/nginx.pid;events { worker_connections 1024;}http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; server { listen 8889; server_name 192.168.2.192; location / { root /app/micro/portal; index index.html; try_files $uri $uri/ /index.html; } } server { listen 7100; server_name 192.168.2.192; # 配置跨域访问,此处是通配符,严格生产环境的话可以指定为主应用 192.168.2.192:8889 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; location / { root /app/micro/app1; index index.html; try_files $uri $uri/ /index.html; } } server { listen 7101; server_name 192.168.2.192; # 配置跨域访问,此处是通配符,严格生产环境的话可以指定为主应用 192.168.2.192:8889 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; location / { root /app/micro/app2; index index.html; try_files $uri $uri/ /index.html; } }}  部署到生产,需要修改big-data-web/public/util/config.js中的VUE_APP_ZIBO_CUSTOM_URL配置项: (function() { window.configs = { VUE_APP_CASLOGINURL: "http://192.168.1.99:32080/cas", //cas登录地址 VUE_APP_REDIRECTURL: "http://192.168.51.61:8888/big-data/", //前端部署地址 VUE_APP_SOCKET: "ws://192.168.31.136:32061", //websocket地址' VUE_APP_AMAPURLPREFIX: "https://webapi.amap.com", //高德地图地址 VUE_APP_ZIBO_CUSTOM_URL:"http://localhost:9010",//自定义微应用地址 //================================================ VUE_APP_AMAPKEY: "xxxxxx" //高德key };})();   这里config.js是为了配置文件外置,不需要编译。 8. 总结   尽管qiankun框架支持各个子应用使用不同的技术框架,但是都需要子应用做相应的改造,而且在其它技术栈中总是会时不时的出现各种难以预料的错误,一旦出现问题,都需要我们去改造代码。所以如果都是vue技术栈,建议使用qiankun做微前端。   如果是第三方公司的项目接入进来,由于他们的代码不受我们控制,需要酌情考虑是否用iframe。   参考文献:qiankun 微前端方案实践及总结 版权声明:本文转载于网络,版权归作者所有,如果侵权,请联系本站编辑删除

猜你喜欢