最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

每日报道:qiankun 的使用

来源:博客园

qiankun 的使用

1.前言

许多项目搭建的方法不一致,故qiankun改造的方式也不一致,但是从目前的情况看,基本的步骤和些思路还是大抵相同,在改造中遇到的最多问题就是 路径不一致、配置的代理不正确、跨域等,后面有问题也优先往这方面靠近。

参考文档:

乾坤官网:https://qiankun.umijs.org/zh

vite vue3配置:https://www.cnblogs.com/Mr-Rshare/p/16571760.html


(相关资料图)

angular 配置:https://www.cnblogs.com/wangyongping/p/16788537.html

2.主应用

vue2 (公司平台)

这里的配置完全可以参考乾坤官网上来配置,这里我用公司平台举例:

如果子应用存在angular那么首先要安装 zone.js,不用的话就不用安装。

npm i zong.jsnpm i qiankun

修改路由 ,在路由表的根部添加要配置的子应用路径:如flink,后面的*号一定要有。

# src/common/router/index.jsexport const constantRouterMap = [  { path: "/license", component: LicenseComponent, hidden: true },  +{   + path: "/flink/*",   + component: componentsObj.Layout  + },  { path: "*", component: NotFoundComponent, hidden: true },  // ...];export default new Router({  mode: "history",  routes: constantRouterMap});

在要渲染子应用的地方添加id容器

# src/common/views/layout/components/AppMain.vue

设置qiankun的启动

# src/common/views/layout/Layout.vue+ import { start } from "qiankun";export default {  mounted() {    + start();  },  methods: {  }};</script>

设置qiankun的基础配置,如果有anglue项目需要引入zone.js

# src/common/config/sys.jsimport "zone.js";  // 如果有anglue项目,一定要在qiankun的前面引入import {  registerMicroApps,} from "qiankun";...registerMicroApps(  [    {      name: "flink_web",      entry: "//localhost:4200",      container: "#appContainer",      activeRule: "/flink"    },    // {    //   name: "datainsight",    //   entry: "//localhost:5002",    //   container: "#appContainer",    //   activeRule: "/datainsight"    // }  ],  {    beforeLoad: [      app => {        // console.log("before load", app);      }    ],    beforeMount: [      app => {        // console.log("before mount", app);      }    ],    afterUnmount: [      app => {        // console.log("after unload", app);      }    ]  }  // {  //   fetch: request  // });...

配置代理 ,这里路径一定要正确,后面报错的话不好定位到这里

# setting.js"/api/flinkdashbaord/*": {      target: "http://flink.com/api/flinkdashbaord", // 本地测试环境      logLevel: "debug",      changeOrigin: true,      autoRewrite: true,      cookieDomainRewrite: true,      pathRewrite: {        "^/api/flinkdashbaord": ""      } },

3.微应用

vue3 + vite

因为官网里面没有提供方法,且不支持vite, 所以需要在引入一个包,在子应用

npm i vite-plugin-qiankun

在改造后发现路由不匹配的问题,后经过测试发现是history没有在离开时销毁造成,所以要 history.destroy();

修改路由,这里简写,并把路由返回的方式

# src/router/index.tsimport { createRouter } from "vue-router"import routes from "./routes"...let routerIn:any=nullfunction setRouter(history: any) {  routerIn = createRouter({    history,    routes  })  ...  return routerIn}export  {setRouter, routerIn as router}

修改主配置,引入插件 vite-plugin-qiankun

# src/main.ts import {createApp} from "vue"import App from "./App"import {QiankunProps, qiankunWindow, renderWithQiankun} from "vite-plugin-qiankun/dist/helper"import {setRouter} from "@/router";import {createWebHistory} from "vue-router";let app:any = null;let routerIn: any = nulllet historyIn: any = nullfunction render(props:any) {    historyIn = createWebHistory(        qiankunWindow.__POWERED_BY_QIANKUN__? "/dolphinscheduler/":(import.meta.env.MODE === "production" ? "/dolphinscheduler/" : "/")    )    routerIn = setRouter(historyIn)    const { container } = props;    app = createApp(App);    app.use(routerIn);    app.mount(container ? container.querySelector("#dolphinschedulerApp"): "#dolphinschedulerApp");}renderWithQiankun({    mount(_props) {        render(_props);    },    bootstrap() {        console.log("bootstrap");    },    unmount(_props: any) {        app.unmount();        app = null;        routerIn= null;        historyIn.destroy();    },    update: function (props: QiankunProps): void | Promise {        console.log("update");    }});if (!qiankunWindow.__POWERED_BY_QIANKUN__) {    render({container:""});}

修改 vite配置 ,因为vite 不支持qiankun 使用插件后,打包时候要提前配置好 base

# vite.config.ts import {defineConfig,  } from "vite"+ import qiankun from "vite-plugin-qiankun"+ const { name } = require("./package.json");export default defineConfig({  base: "http://dolphinscheduler.com/",  // base: process.env.NODE_ENV === "production" ? "/dolphinscheduler/" : "/",  plugins: [    + qiankun(name, {     +  useDevMode: true,    +  }),    ...  ],  ...  server: {    + headers: {      + "Access-Control-Allow-Origin": "*",    + },    proxy: {      "^/api/inner/dolphinscheduler": {        target: loadEnv("development", "./").VITE_APP_DEV_WEB_URL,        changeOrigin: true      }    }  }})

angular12 + single-spa

angular整体结构有所不同,这里的项目有用到 single-spa 才可以,执行命令

npm i single-spa -Sng add single-spa-angular

执行完后,项目的一部分路径文件也会有所变化,创建 public-path.js 文件,在 main.single-spa.ts 内最上面引入

# public-path.js if (window.__POWERED_BY_QIANKUN__) {  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__}

修改入口文件

# main.single-spa.tsimport "./public-path";import { enableProdMode, NgZone } from "@angular/core";import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";import { Router } from "@angular/router";import { singleSpaAngular, getSingleSpaExtraProviders } from "single-spa-angular";import { AppModule } from "./app/app.module";import { environment } from "./environments/environment";import { singleSpaPropsSubject } from "./single-spa/single-spa-props";if (environment.production) {  enableProdMode();}// enableProdMode();// 微应用单独启动时运行if (!(window as any).__POWERED_BY_QIANKUN__) {  platformBrowserDynamic()    .bootstrapModule(AppModule)    .catch(err => console.error(err));}const lifecycles = singleSpaAngular({  bootstrapFunction: singleSpaProps => {    singleSpaPropsSubject.next(singleSpaProps);    return platformBrowserDynamic(getSingleSpaExtraProviders()).bootstrapModule(AppModule);  },  template: "",  Router,  NgZone: NgZone});export const bootstrap = lifecycles.bootstrap;export const mount = lifecycles.mount;export const unmount = lifecycles.unmount;

控制zone.js 的引入,确保本地和qiankun都能引入

# index.htmlhead标签添加<script src="https://unpkg.com/zone.js" ignore></script>
# polyfills.ts// import "zone.js  把这里引入注释掉

修改路由的配置

# app-routing.module.ts+ import { APP_BASE_HREF } from "@angular/common";@NgModule({  exports: [RouterModule],  imports: [RouterModule.forRoot(routes)],  + providers: [{ provide: APP_BASE_HREF, useValue: (window as any).__POWERED_BY_QIANKUN__ ? "/flink/" : "/" }]})

修改angular配置文件

# extra-webpack.config.jsconst singleSpaAngularWebpack = require("single-spa-angular/lib/webpack").default;const {merge } = require("webpack-merge");const appName = require("./package.json").name;module.exports = (config, options) => {  const singleSpaWebpackConfig = singleSpaAngularWebpack(config, options);  const singleSpaConfig = {    devServer: {      headers: {        "Access-Control-Allow-Origin": "*",      },    },    output: {      library: `${appName}-[name]`,      libraryTarget: "umd",    },    externals: {      "zone.js": "Zone",    },  };  const mergedConfig = merge (    singleSpaWebpackConfig,    singleSpaConfig  );  return mergedConfig;};

如果还有其它报错,基本上是路径匹配,端口NaN等造成

react16.8

一部分的引入的方式可参考官网,可能项目不同,webpack的引入方式不正确,需要单独处理。

修改打包配置文件

# internals/webpack/webpack.prod.babel.jsmodule.exports = require("./webpack.base.babel")({  mode: "production",  output: {    // filename: "[name].[chunkhash].js",    // chunkFilename: "[name].[chunkhash].chunk.js"   + library: `datainsight`,   +  filename: `[name].${timeStamp}.js`,    + libraryTarget: "umd",     jsonpFunction: `webpackJsonp_${name}`  },  ...})

修改引入

# app/app.tsxif (window.__POWERED_BY_QIANKUN__) {  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__}import React from "react"import ReactDOM from "react-dom"import { translationMessages } from "./i18n"...const MOUNT_NODE = document.getElementById("datainsightApp")const render = (messages, props) => {  const { container } = props  ReactDOM.render(                                                                    ,    container ? container.querySelector("#datainsightApp") : MOUNT_NODE  )}if (!window.__POWERED_BY_QIANKUN__) {  if (module.hot) {    module.hot.accept(["./i18n", "containers/App"], () => {      ReactDOM.unmountComponentAtNode(MOUNT_NODE)      render(translationMessages, {})    })  } else {    render(translationMessages, {})  }}export async function bootstrap() {  console.log("react app bootstraped")}export async function mount(props) {  await render(translationMessages, props)}export async function unmount(props) {  const { container } = props;  await ReactDOM.unmountComponentAtNode(container ? container.querySelector("#datainsightApp") : MOUNT_NODE)}if (process.env.NODE_ENV === "production") {  // disable react developer tools in production  if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {    window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0  }}

修改路由

# app/containers/App/index.tsx...  public render() {      const __qiankun__ = window.__POWERED_BY_QIANKUN__    return (      
{/*basename={"/datainsight"} basename={__qiankun__ ? "/datainsight" : "/"}*/}
) }...

vue2

这里不做详细介绍,参考官网

https://qiankun.umijs.org/zh/guide/tutorial#vue-%E5%BE%AE%E5%BA%94%E7%94%A8

4.nginx配置

qiankun 官网:

https://qiankun.umijs.org/zh/cookbook#%E5%9C%BA%E6%99%AF-2%E4%B8%BB%E5%BA%94%E7%94%A8%E5%92%8C%E5%BE%AE%E5%BA%94%E7%94%A8%E9%83%A8%E7%BD%B2%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BD%BF%E7%94%A8-nginx-%E4%BB%A3%E7%90%86%E8%AE%BF%E9%97%AE

通用方式

线上采用同一个服务器,不同的端口实现

server {        listen       86;        server_name  localhost;        location / {            root   /aTinyApp/appbase;            index  index.html index.htm;            try_files $uri $uri/ /index.html;        }        location /applims {            proxy_pass http://localhost:88/;            proxy_set_header Host $host:$server_port;        }        location /appcost {            proxy_pass http://localhost:89/;            proxy_set_header Host $host:$server_port;        }        location /api/ {            proxy_pass http://gateway/;            proxy_set_header X-Real-IP  $remote_addr;            proxy_read_timeout 300;            client_max_body_size 1024m;        }        error_page   500 502 503 504  /50x.html;        location = /50x.html {            root   html;        }    }    server {        listen  88;        server_name  localhost;        location / {            root   /aTinyApp/applims;            index  index.html index.htm;            try_files $uri $uri/ /index.html;        }        location /api/ {            proxy_pass http://gateway/;            proxy_set_header X-Real-IP  $remote_addr;            proxy_read_timeout 300;            client_max_body_size 1024m;        }        error_page   500 502 503 504  /50x.html;        location = /50x.html {            root   html;        }    }    server {        listen  89;        server_name  localhost;        location / {            root   /aTinyApp/appcost;            index  index.html index.htm;            try_files $uri $uri/ /index.html;        }        location /api/ {            proxy_pass http://gateway/;            proxy_set_header X-Real-IP  $remote_addr;            proxy_read_timeout 300;            client_max_body_size 1024m;        }        error_page   500 502 503 504  /50x.html;        location = /50x.html {            root   html;        }    }

本地需要考虑到跨域等因素,做相应处理

server {        listen       80;        server_name  flink.com;        #access_log  logs/host.access.log  main;        location / {            root D:/baseServer/app/flink;            index  index.html index.htm;            try_files $uri $uri/ /index.html;            # 允许 所有头部 所有方法 域             add_header "Access-Control-Allow-Headers" "*";            add_header "Access-Control-Allow-Methods" "*";            add_header "Access-Control-Allow-Origin" "$http_origin";            add_header "Access-Control-Allow-Credentials" "true";        }                location /api/ {    proxy_pass http://172.18.50.187;    }        error_page   500 502 503 504  /50x.html;        location = /50x.html {            root   html;        }           }    

同一域名下部署

多数也是参照乾坤的例子

主应用配置

egisterMicroApps(  [    {      name: "flink-dashboard",      entry: "/child/flinkdashboard/",    // 重点      container: "#appContainer",      activeRule: "/flinkdashboard"      // 重点    },    {      name: "dolphinscheduler",      entry: "/child/dolphinscheduler/",  // 重点      container: "#appContainer",      activeRule: "/dolphinscheduler"     // 重点    },  ],

子应用history配置

historyIn = createWebHistory(          qiankunWindow.__POWERED_BY_QIANKUN__? "/dolphinscheduler/":"/child/dolphinscheduler/")

子应用跟路径 配置

base:"/child/dolphinscheduler/"

服务器目录

└── app/                     # 根文件夹    |    ├── child/                # 存放所有微应用的文件夹    |   ├── flinkdashboard/         // flinkdashboard    |   ├── dolphinscheduler/       // dolphinscheduler    ├── index.html            # 主应用的index.html    ├── css/                  # 主应用的css文件夹    ├── js/                   # 主应用的js文件夹

nginx配置

server {        listen       80;        server_name  app.com;        #access_log  logs/host.access.log  main;        location / {            root D:/baseServer/app;            index  index.html index.htm;            try_files $uri $uri/ /index.html;        }        location /child/flinkdashboard {            root   D:/baseServer/app;            index  index.html index.htm;            try_files $uri $uri/ /child/flinkdashboard/index.html;        }        location /child/dolphinscheduler {            root   D:/baseServer/app;            index  index.html index.htm;            try_files $uri $uri/ /child/dolphinscheduler/index.html;        }                location /api/ {    proxy_pass http://172.18.50.187;    }        error_page   500 502 503 504  /50x.html;        location = /50x.html {            root   html;        }           }         

配置成功后,主应用访问地址不变,单独访问子应用只需要加上 http://xxx.com/child/zi/ 即可。

5.常见问题

多数问题qiankun已经整合,可以从中作为参考:

https://qiankun.umijs.org/zh/faq

a. 如果安装了zone.js 在项目运行中,可能有不相关问题也会发出报错提示,不是angular项目时候可以先关掉引用,方便快速定位问题

b. 项目部署后,vite项目与其他项目切换中,发现路径回退,可能是vite项目的history没有销毁,在乾坤生命周期中销毁。

c. angular项目在执行完 ng add single-spa-angular 后,可能会遇到,端口变成NaN问题,路径不匹配的问题

// 报路径错的时候修改这里# tsconfig.app.json"files":["main.single-spa.ts"]// 端口要一致# angular.json"projects"->"flink"->"architect"->"build"->"options"->"deployUrl":"/""projects"->"flink"->"architect"->"serve"->"options"->"deployUrl":"http://localhost:4200/"

d. 任何项目部署后运行,刷新后子应用变成主应用消失,可以先检查主应用的entry和activeRule是不是配置成一样的了

e. angular项目有一个跟路径:

当出现白屏,路径不匹配,配置了好几种方案都不成功的时候,可以尝试将其注释掉。

f. 目前在vite 和vue3的项目上遇到一个问题,配置都正确,但是访问二级微应用的子路由的时候,将整个页面都渲染成白屏,后改路径等匹配规则都不成功,最后使用的hash 路由模式得以解决,如果要继续使用history 模式,可以尝试从子应用上检查,现在已经定位到是子应用路由渲染上有影响,具体原因还在查找。

。。。

后续待补充

关键词: