1. 程式人生 > 其它 >ant-design-pro使用qiankun微服務詳解

ant-design-pro使用qiankun微服務詳解

微服務現在挺火的,優點也很明顯 如果有多個應用都有相同頁面時,就可以使用微服務,可以避免重複寫程式碼 在網上搜了下,很多例子都是基於官方文件的例子,官方文件:https://umijs.org/zh-CN/plugins/plugin-qiankun.比較簡單,實際使用場景會有特殊情況 我根據自己專案的情況總結了一下使用方法 我們兩個專案都是ant-design-pro的,我這裡的例子也用的ant-design-pro專案生成的, githup地址:https://github.com/ant-design/ant-design-pro 微服務需要有主應用和子應用 一個子應用可以配置多個相關聯的主應用,配置方法都是一樣的
這是我的專案,一個主應用,一個子應用 首先,主應用和子應用都要安裝yarn add @umijs/plugin-qiankun -D

主應用配置

1. config.ts配置

2. app.tsx配置,這個entry,就是子應用的地址,可以寫成變數形式,區分本地和線上環境 3. 修改document.ejs檔案,可以解決頁面一直載入問題

4. 修改routes檔案

5. 配置proxy.tx介面代理.因為在主應用,請求的地址是主應用的,要代理回子應用的請求地址,如果已經有類似/api這種字首,要注意主應用和子應用區分,不要用相同的字首

子應用配置 1. config.ts配置
  qiankun: {
    slave: {},
  }
2. app.tsx配置.子應用可以通過生命週期函式拿到主應用傳遞的引數.如果子應用本身是有選單,麵包屑等,應該要區別,在主應用不顯示,否則會重複
let isMenu = true
// 設定一個變數,判斷是否需要展示layout // ProLayout 支援的api https://procomponents.ant.design/components/layout export const layout: RunTimeLayoutConfig = ({ initialState }) => { console.log(initialState) const prop = {} if (!isMenu) { // 如果是載入在主應用中,不展示選單和頭部 prop.menuRender = false prop.headerRender = false
prop.contentStyle = { margin: 0 } } return { rightContentRender: () => <RightContent />, disableContentMargin: false, waterMarkProps: { content: initialState?.currentUser?.name, }, footerRender: () => <Footer />, headerContentRender: () => <ProBreadcrumb />, breadcrumbRender: (routers = []) => [ { path: '/', breadcrumbName: '主頁', }, ...routers, ], onPageChange: () => { const { location } = history; // 如果沒有登入,重定向到 login if (!initialState?.currentUser && location.pathname !== loginPath) { history.push(loginPath); } }, links: isDev ? [ <Link to="/umi/plugin/openapi" target="_blank"> <LinkOutlined /> <span>OpenAPI 文件</span> </Link>, <Link to="/~docs"> <BookOutlined /> <span>業務元件文件</span> </Link>, ] : [], menuHeaderRender: undefined, // 自定義 403 頁面 // unAccessible: <div>unAccessible</div>, ...prop, ...initialState?.settings, }; }; export const qiankun = { // 應用載入之前 async bootstrap(props: any) { console.log('app1 bootstrap', props); if (props) { isMenu = props.isMenu const logins = async() => { await login({ ...props.accountInfo }) } logins() } }, // 應用 render 之前觸發 async mount(props: any) { console.log('app1 mount', props); }, // 應用解除安裝之後觸發 async unmount(props: any) { console.log('app1 unmount', props); }, }
3.routes.ts檔案,正常配置路由就可以了
...
{
    name: 'Form表單',
    icon: 'form',
    path: '/form',
    routes: [
      {
        path: '/form',
        redirect: '/form/add'
      },
      {
        name: 'form表單',
        icon: 'table',
        path: '/form/add',
        component: './product/addProduct',
      },
      {
        name: 'debonceselect',
        icon: 'table',
        path: '/form/debonceselect',
        component: './form/debounce',
      },
      {
        name: 'upload上傳',
        icon: 'table',
        path: '/form/upload',
        component: './form/upload',
      },
      {
        name: 'child詳情頁',
        icon: 'table',
        path: '/form/detail', // 主應用配置時路由要和子應用一致
        component: './form/detail',
      },
      {
        name: 'child詳情頁2',
        icon: 'table',
        path: '/form/detail2',
        component: './form/detail2',
      }
    ],
  },
4. proxy.ts檔案
export default {
  dev: {
    '/childapi/api/': {
      target: 'http://localhost:8091',
      changeOrigin: true,
      pathRewrite: { '^/childapi': '' },
    },
  },
  test: {
    '/api/': {
      target: 'https://preview.pro.ant.design',
      changeOrigin: true,
      pathRewrite: { '^': '' },
    },
  },
  pre: {
    '/api/': {
      target: 'your pre url',
      changeOrigin: true,
      pathRewrite: { '^': '' },
    },
  },
};
執行效果 主應用頁面:

子應用頁面:

幾個專案實際要解決的問題
1. 子應用登入態問題 如果子應用不需要登入,只是檢視可以忽略這個問題 如果主應用和子應用都有自己的登入態.如果不做任何處理,想要在主應用執行子應用,必須要同時執行子應用,並且子應用要登入,這樣不太合理 一般處理,主應用傳遞token,在子應用請求時加上這個token
let token = ''
const middleware: OnionMiddleware = async (ctx, next) => {
  const {
    req: { url },
  } = ctx

  ctx.req.options.headers = { // 在請求頭加入傳遞的token
    token,
  }

  await next()

  if (ctx.res.responseCode !== '000000') {
    if (!(ctx.res && ctx.res.size)) throw { ...ctx.res, url }
  }
}

export const qiankun = {
  // 應用載入之前
  async bootstrap(props: any) {
    if (props) {
      token = props.token
    }
  },
  // 應用 render 之前觸發
  async mount(props: any) {
    console.log('app1 mount', props)
  },
  // 應用解除安裝之後觸發
  async unmount(props: any) {
    console.log('app1 unmount', props)
  },
}

export const request: RequestConfig = {
  prefix: URL_PREFIX,
  method: 'POST',
  middlewares: [middleware],
  credentials: 'include',
  errorHandler,
}
我這個例子因為用的官方的專案,直接模擬了下,呼叫了子應用的登入介面
export const qiankun = {
  // 應用載入之前
  async bootstrap(props: any) {
    console.log('app1 bootstrap', props);
    if (props) {
      isMenu = props.isMenu
      const logins = async() => { // 呼叫登入介面
        await login({ ...props.accountInfo }) // 傳遞賬戶資訊過來
      }
      logins()
    }
  },
  // 應用 render 之前觸發
  async mount(props: any) {
    console.log('app1 mount', props);
  },
  // 應用解除安裝之後觸發
  async unmount(props: any) {
    console.log('app1 unmount', props);
  },
}
這樣不用開啟子應用也能載入子應用頁面了 2. 子應用執行時,會自動新增字首 因為qiankun框架的程式碼切割,子應用執行時會根據package.json裡的name加入一個字首.如果不想要可以在config.ts裡配置base: '/'.我這裡是換了一個字首名稱

3. 子應用路由匹配問題.為了主應用的路由地址和子應用一致,配置路由時microAppProps的base傳了'' 這樣會導致子應用頁面載入錯誤或登入態失效時,頁面顯示404頁面.因為現在是精確的路由匹配,沒有登入會重定向到登入頁,這樣就會找不到頁面.一般設定好登入態不會有這個問題,不過想要完善點,可以寫上錯誤路由跳轉到登入頁面,或者提示重新整理頁面等 githup程式碼地址, 主應用:https://github.com/shengbid/antpro-parent 子應用:https://github.com/shengbid/antpro-child 如果遇到跟著文件配置,專案啟動報錯問題,可能是專案執行問題,可以嘗試重啟,刪包重灌.在加入qiankun元件前,可以備份程式碼,配置執行好後再加入程式碼中, 以免出現程式碼執行不了,恢復不了情況o(╯□╰)o
微服務其實有很多功能,不過目前也只用了些簡單的功能.如果有其他業務場景,可以留言,共同學習進步呀(*^▽^*)