vue3微前端實戰

微前端接入方案:qiankunjavascript

經常使用api:html

registerMicroApps: 主應用註冊微前端前端

start: 啓動微前端應用vue

主、子應用都爲hash模式改造:

開發環境:

主應用改造:

import { registerMicroApps, start } from 'qiankun';
registerMicroApps(
  [
    {
      // 微前端應用名
      name: 'app1',
      
      // 微前端啓動地址
      entry: '//localhost:8100/',
      
      // 微前端掛載dom
      container: '#app',
      
      // 微前端觸發路由
      activeRule: '#/app1',
      
      // 主應用向子應用傳遞的靜態值
      props: {
        name: 'yuxiaoyu',
      },
    },
  ],
);

start();
複製代碼

子應用改造:

// 入口文件main.js
// 子應用並不用引入qiankun,只要暴露響應的聲明週期鉤子給主應用使用就ok
// 掛載實例
function render(props: any = {}) {
  const { container } = props;
  app = createApp(App);
  app.use(router);
  app.use(store);
  router.isReady().then(() => {
    app.mount(container ? container.querySelector('#container') : '#container');
  });
}

// 微應用在主應用運行時,主應用會在微應用中掛載window.__POWERED_BY_QIANKUN__,能夠用於判斷環境
// 官方提供了下面這個webpack注入publicPath的方法, 開發環境咱們這麼使用,生產改到vue.config.js中,後面再介紹。
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

// 若是是獨立運行 window.__POWERED_BY_QIANKUN__=undefined 直接render
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

// 最後暴露的三個方法是固定的,加載渲染以及銷燬
export async function bootstrap() { }

export async function mount(props: any) {
  render(props);
}
export async function unmount() {
  app.unmount();
  app._container.innerHTML = "";
  app = null;
  
  // 這裏reload的緣由: 由於這個項目微應用和主應用沒有共用導航等信息
  // 至關於一個兩個獨立的頁面,因此就共用的<div id="app"></div>一個節點
  // 在卸載微應用後,爲了再把主應用渲染出來,就從新reload了一遍。
  location.reload();
}
複製代碼
// router改造
const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

// 由於主應用在激活子應用時,有一個activeRule前綴,因此在hash模式下,咱們須要給每一個一級路由都添加activeRule的前綴,主應用爲'#/app1',那麼子應用前咱們就加'/app1'就能夠了。
export default [
  {
    path: '/app1/fujidaohang',
    redirect: '/app1/fujidaohang/zijidaohang',
    component: BothLayout,
    name: 'fujidaohang',
    meta: {
      title: '父級導航',
      navPosition: 'top',
    },
    children: [
      {
        path: 'zijidaohang',
        component: () => import('@/apps/fujidaohang/views/zijidaohang.vue'),
        name: 'zijidaohang',
        meta: {
          title: '子級導航',
          navPosition: '',
        },
      },
    ],
  },
  {
    path: '/app1/course',
    component: Course,
    name: 'course',
    children: [],
  }
];
複製代碼
// vue.config.js改造
const packageName = require('./package.json').name;

module.exports = {
  ...
  
  // 用於主應用識別子應用,固定寫法
  configureWebpack: {
    output: {
      library: 'app1',
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${packageName}`,
    },
  }
}
複製代碼

生產構建部署:

構建部署能夠選擇兩種方式:java

同域名和不一樣域名部署。由於考慮到接口跨域和不用域名部署須要運維資源,Nginx相關的配置,因此咱們選用同域名部署。部署在主應用構建以後的靜態資源目錄裏,這樣前端就能夠處理部署流程,不須要後端及運維的支持。固然也能夠根據須要選用響應的部署方式,官方都有給出詳細的介紹: 如何部署webpack

主應用改造:

// main.js
// 註冊微應用
registerMicroApps(
  [
    {
      name: 'app1',
      
      // 路徑改成部署後,微應用要存放在主應用的目錄,其他不變
      entry: '/static/index.html',
      container: '#app',
      activeRule: '#/app1',
      props: {
        name: 'kuitos',
      },
    },
  ],
);
複製代碼

微應用改造:

// main.js
// 去掉qiankun的__webpack_public_path__注入
// if (window.__POWERED_BY_QIANKUN__) {
// __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
// }

// vue.config.js
module.exports = {
  ...
  
  // 這裏新增打包資源存放路徑,與上面主應用相對應
  publicPath: '/static'
}
複製代碼

主、子應用打包後存放如圖所示,以後就能夠走運維的部署流程了。web

image.png

主、子應用都爲history模式改造:

開發模式:

這裏咱們和hash-dev模式進行對比,只列舉差別的部分。json

// 主應用
// main.js, 註冊微應用有變化
registerMicroApps(
  [
    {
      name: 'app1',
      entry: '//localhost:8101',
      container: '#app',
      
      // 改變點:激活路由由hash模式變爲history模式
      activeRule: '/app1',
      props: {
        name: 'yuxiaoyu',
      },
    },
  ],
);

// router.js 

const router = new VueRouter({

  // 由hash改成history模式
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
});
複製代碼
// 子應用
// router/index.js
const router = createRouter({
  
  // 改成history模式,而且加activeRule前綴
  history: createWebHistory('/app1'),
  routes,
});

// router.js

// 去掉這裏的app1前綴
export default [
  {
    path: '/fujidaohang',
    redirect: '/fujidaohang/zijidaohang',
    component: BothLayout,
    name: 'fujidaohang',
    meta: {
      title: '父級導航',
      navPosition: 'top',
    },
    children: [
      {
        path: 'zijidaohang',
        component: () => import('@/apps/fujidaohang/views/zijidaohang.vue'),
        name: 'zijidaohang',
        meta: {
          title: '子級導航',
          navPosition: '',
        },
      },
    ],
  },
  {
    path: '/course',
    component: Course,
    name: 'course',
    children: [],
  }
];
複製代碼

生產構建部署:

這裏與hash模式改動點是一致的bootstrap

主應用改造:

// main.js
// 註冊微應用
registerMicroApps(
  [
    {
      // 路徑改成部署後,微應用要存放在主應用的目錄,其他不變
      entry: '/static/index.html',
    },
  ],
);
複製代碼

微應用改造:

// main.js
// 去掉qiankun的__webpack_public_path__注入
// if (window.__POWERED_BY_QIANKUN__) {
// __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
// }

// vue.config.js
module.exports = {
  ...
  
  // 這裏新增打包資源存放路徑,與上面主應用相對應
  publicPath: '/static'
}
複製代碼

鑑權

當進入微應用時,咱們鑑定微應用是否登陸時,咱們能夠考慮在微應用作鑑權,也能夠在主應用作鑑權。後端

qiankun裏在註冊微應用時,registerMicroApps提供了第二個參數,lifeCycles- 可選,全局的微應用生命週期鉤子

registerMicroApps(
    [{}], {
    
    // 這裏採用在進入微前端以前進行鑑權,確保進入微前端時,已經登錄。
    beforeLoad: [
      () => {
        if (!vm.$auth.check()) {
            vm.$router.push(vm.$auth.options.loginPath);
            location.reload();
        }
      },
    ],
  },);
複製代碼

樣式隔離

1.主、子應用都是用antd

這裏官方提供了修改antd前綴的方法,如將ant改成dida-ant, 如何確保主應用跟微應用之間的樣式隔離

這裏ant-design-vue文檔裏雖然沒有提供prefixCls的參數,可是可使用的,源碼裏相應的處理。

2.主應用自定義樣式與子應用衝突

這裏咱們能夠採用官方提供的start(options?),將微應用放入瀏覽器所支持的shadow dom中。

start({
  sandbox: {
    // 主應用 & 子應用樣式隔離
    strictStyleIsolation: true, // 放入shadow dom中
  }
});
複製代碼

image.png

這裏咱們能夠看到微前端被放入了shadow-root裏,對於shadow dom能夠經過這裏進行了解。

這樣隔離後,在咱們使用ant design這種外部庫時會有一些問題,例如popup組件,本來實現是掛在document.body中的,咱們將子應用放到了shadow dom中,那就須要將popup也掛進去。ant design官方提供了方法,搜索getPopupContainer;

相關文章
相關標籤/搜索