qiankun項目實踐和優化(React+Vue)

前言

qiankun微服務,將多個不一樣技術棧的系統(React,Vue,Angular,jQuery)等聚合成一個系統,各個系統又能各自獨立部署運行,適用於大型團隊和大型前端項目。javascript

實現功能:

  • 引入多技術棧(React + Vue)
  • 後臺管理系統(Ant Design Pro)多標籤頁在qiankun環境緩存的實踐
  • 依賴共享 --- 主子應用公共的包react,react-dom,moment,antd等)的共享
  • 資源公用 --- 共用的工具util, 組件,配置在多個項目同步

基於qiankun微服務的在線預覽:php

點擊預覽效果 css

獲取項目源碼前端

項目架構

項目 技術棧 端口 訪問地址
主項目(main-react) Ant Design Pro 5000 http://qiankun.fancystore.cn
子項目1(app1-react) Ant Design Pro 5001 http://app1.fancystore.cn
子項目2(app2-react) Ant Design Pro 5002 http://app2.fancystore.cn
子項目3(app3-vue) Vue Element Template 5003 http://app3.fancystore.cn
公共資源庫(qiankun-common) TypeScript https://github.com/czero1995/qiankun-common

項目改造

1. 主應用(基座)

1.1 安裝qiankun

npm install @umi/qiankun --save   
   or
   yarn add @umi/qiankun --save

1.2 註冊子應用

// 在config/config.ts加入
    qiankun: {
      master: {
        apps: [
           {
              name:'app1',
              entry: process.env.NODE_ENV === 'production' ? '//app1.fancystore.cn' : '//localhost:5001',
            },
            {
              name:'app2',
              entry: process.env.NODE_ENV === 'production' ? '//app2.fancystore.cn:' : '//localhost:5002',
            },
            {
              name:'app3',
              entry: process.env.NODE_ENV === 'production' ? '//app3.fancystore.cn:' : '//localhost:5003',
            },
        ],
        sandbox: true,  //是否啓用沙箱
        prefetch: true, //是否啓用prefetch特性
      }
    }

1.3 修改根節點

// src/pages/document.ejs
    id=root-master

1.4 新建子應用裝載佈局MicroAppLayout

// src/layouts/MicroAppLayout
    import BasicLayout from '@ant-design/pro-layout';
    import { KeepAlive, Provider } from 'react-keep-alive';
    import { MicroAppWithMemoHistory } from 'umi';
    import allRoutes from '../../config/routes';

    function MicroAppLayout(props) {
      let targetMicro = ''
      const transRoutes = (routes, pathname) => {
        routes.map(item => {
          if (item.routes) {
            return transRoutes(item.routes, pathname)
          }
          if (item.path === pathname) {
            targetMicro = item.microName
          }
        })
        return targetMicro
      }
      return <Provider>
        <KeepAlive name={props.location.pathname}>
          {
            targetMicro ? <MicroAppWithMemoHistory name={transRoutes(allRoutes[0].routes, props.location.pathname)} url={props.location.pathname} /> :
              <BasicLayout></BasicLayout>
          }
        </KeepAlive>
      </Provider>
    }

    export default MicroAppLayout;

1.5 在src目錄下新建app.ts,判斷若是是子應用,須要用MicroAppLayout裝載

// src/app.ts
    import LoadingComponent from '@/components/PageLoading';
    import { dynamic } from 'umi';
    const transRoutes = (routes) => {
      routes.forEach(item => {
        if(item.routes){
          return transRoutes(item.routes)
        }
        if(item.microName){
          item.component = dynamic({
            loader: (a) => import(/* webpackChunkName: 'layouts__MicroAppLayout' */ '@/layouts/MicroAppLayout'),
            loading: LoadingComponent,
          })
        }
      })
    }

    export function patchRoutes({ routes }) {
      transRoutes(routes[0].routes)
    }

### 2. 子應用React(Ant Desin Pro)vue

#### 2.1 安裝qiankunjava

npm install @umi/qiankun --save   
    or
    yarn add @umi/qiankun --save

#### 2.2 子項目註冊qiankun,在config/config.ts加入react

qiankun: {
        slave: {}
    }

#### 2.3 修改根節點 src/pages/document.ejswebpack

id=root-slave

#### 2.4 在src目錄下新建app.ts,導出相應的生命週期鉤子,子項目須要去區分好是qiankun環境仍是當前環境,若是是qiankun環境,使用空白的模板(src/layouts/BlankLayout),若是是當前環境,使用默認的模板(src/layouts/BasicLayout),這樣能內嵌到qiankun環境下運行也能獨立開發部署git

const isQiankun = window.__POWERED_BY_QIANKUN__

    export const qiankun = {
        // 應用加載以前
        async bootstrap(props) {
          console.log('app1 bootstrap', props);
        },
        // 應用 render 以前觸發
        async mount(props) {
          console.log('app1 mount', props);
        },
        // 應用卸載以後觸發
        async unmount(props) {
          console.log('app1 unmount', props);
        },
      };

      export async function patchRoutes({routes}) {
        if(isQiankun){
          routes[0]['component'] = require('@/layouts/BlankLayout').default
        }
      }

3. 子應用Vue(Vue-Element-Template)

3.1 在vue.config.js下的configureWebpack中加入

output: {
      // 把子應用打包成 umd 庫格式(必須)
      library: `${name}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${name}`,
     }

3.2 在vue.config.js下的devServer中加入:

headers: {
          "Access-Control-Allow-Origin": "*",
          "Access-Control-Allow-Methods": "*",
          "Access-Control-Allow-Headers": "*"
     }

3.3 在main.js中暴露qiankun的生命週期:

let install = null;
    function render(props) {
      install = new Vue({
        router,
        store,
        render: h => h(App)
      }).$mount('#app3')
    }
    if (window.__POWERED_BY_QIANKUN__) {
      __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
    } else {
      render();
    }
    export async function bootstrap(props) {
    }
    export async function mount(props) {
      render(props);
    }
    export async function unmount(props) {
      install.$destroy();
      install = null
    }

項目總結

  1. 主應用裝載子應用有兩種形式 使用路由綁定的方式 和 使用 <MicroApp '/> 組件的方式,若是要支持Ant Design Pro多標籤頁,須要使用 <MicroApp '/> 這種形式,由於動態的顯示插入Tab,綁定死路由的話會形成qiankun加載不到對應的頁面。
  2. Ant Design Pro多標籤頁,點擊標籤頁的展現不一樣的應用頁面會致使被銷燬,內容數據被初始化和丟失,在src/layouts/MicroAppLayout下:github

    引入 react-keep-alive 包
    主應用須使用  MicroAppWithMemoHistory,  若使用 MicroApp 無效果。
  3. qiankun環境下頁面跳轉404

    在qiankun環境下,全部的路由改動都會涉會觸發qiankun的路由監聽,須要對環境作出判斷:
    export const qiankunJump = (url:string,name='頁面名稱',params = null) =>{
          window.__POWERED_BY_QIANKUN__ ? history.pushState(params,name,url): umiHistory.push(url)
    }
    qiankunJump('/xxx')
  4. qiankun external會報 Cannot read property 'createContext' of undefind

    子項目是umi項目,只要配置了externals就會出錯,須要更改exteranls的寫法,去掉window
     externals: {
          'react': 'window.React',
          'react-dom': 'window.ReactDOM',
      } => 
      externals: {
              react: 'React',
              'react-dom': 'ReactDOM',
      }

項目優化

1. 依賴共享

若是主子應用使用的是相同的庫或者包(react,react-dom,moment等),能夠用externals的方式來引入,減小加載重複包致使資源浪費. 
 
 qiankun將子項目的外鏈script標籤內容請求完後,會記錄到一個全局變量中,下次再次使用,他會先從這個全局變量中取。這樣就會實現內容的複用,只要保證兩個連接的Url一致便可
const fetchScript = scriptUrl => scriptCache[scriptUrl] || (scriptCache[scriptUrl] = fetch(scriptUrl).then(response => response.text()));

因此只要子項目配置了webpack的externals,這些公共依賴在同一臺服務器上,就能夠實現子項目的公共依賴的按需引入,一個項目使用了以後,另外一個項目再也不重複加載,能夠直接複用這個文件。

2.資源共用

解決資源共用的問題,能夠提升項目的維護性,否則多個系統共用的組件或者工具維護起來很費力。

1. 經常使用的就是發佈成npm包,各個項目去安裝更新包。本地調試能夠用npm link。但反覆的更新包也是比較繁瑣。

2. 還有一種方式是用git庫引入, 在package.json的依賴中加入 
"qiankun-common": "git+https://git@github.com:czero1995/qiankun-common.git"
使用
import { commonUtil } from 'qiankun-common';
util.qiankunJump('/xxx')

### 項目啓動

1. 進入main-react
    npm install
    npm run start
2. 進入app1-react
    npm install
    npm run start
3. 進入app2-react
    npm install
    npm run start
4. 進入app3-react
    npm install
    npm run dev

### 項目部署

  1. 子應用Nginx須要配上跨域請求頭:

    add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Allow-Credentials true;
      add_header Cache-Control no-cache;
  2. Nginx開啓gzip壓縮:

    gzip  on;
      gzip_min_length 200;
      gzip_buffers 4 16k;
      gzip_comp_level 9;
      gzip_vary on;
      gzip_disable "MSIE [1-6]\.";
      gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json;
相關文章
相關標籤/搜索