Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qiankun 微前端应用实践与部署(三) #24

Open
jwchan1996 opened this issue Aug 14, 2020 · 8 comments
Open

qiankun 微前端应用实践与部署(三) #24

jwchan1996 opened this issue Aug 14, 2020 · 8 comments

Comments

@jwchan1996
Copy link
Owner

jwchan1996 commented Aug 14, 2020

qiankun 微前端应用实践与部署(三)

微前端架构下,主应用有自己的路由模块,同时主应用支持以微前端的方式嵌入业务模块(子应用),如何实现呢?

关于路由

qiankun 在主应用初始化会自动监听路由的变化去匹配注册好的子应用路由活动规则,同时 vue 路由也会监听路由变化。

因为主应用有自己的业务模块,需要支持页面刷新,所以采用 hash 路由模式。qiankun 官方 demo 使用的是 history 路由模式。

那么,采用 hash 路由模式的话,主应用路由会有 /#/ 的前缀,比如主应用的 resource 组件路由:

http://localhost:8889/#/resource

假设 history 路由模式下子应用的注册信息为:

{
  name: 'live',
  entry: '//localhost:7102',
  container: '#subapp-viewport',
  activeRule: '/live',
}

此时 qiankun 只有命中 urlhttp://localhost:8889/live 才会加载子应用。

此处假设使用的路由切换代码为:

this.$router.push({
  path: '/live'
})

所以现在切换的 urlhttp://localhost:8889/#/live,显然不能匹配 /live,所以加载子应用失败。我们需要修改一下子应用注册的 activeRule,使得匹配 hash 路由模式。

为了区分开主应用的自身模块与子应用的路由区别,子应用的路由增加 /micro 前缀,比如 /micro/live 是子应用的路由。

那么 hash 路由模式下子应用的注册信息变成:

{
  name: 'live',
  entry: '//localhost:7102',
  container: '#subapp-viewport',
  activeRule: '/#/micro/live',
}

这样的话,主应用路由切换后的 url 就能命中子应用的 activeRule 了。

同时,子应用也需要将路由模式设置为 hash 模式,否则,会出现在子应用切换自身路由时,改变主应用 hash 路由的情况。比如子应用切换自身路由 /about,此时 url 会变成 http://localhost:8889/about/#/micro/live,导致路由命中失败。我们期望的 urlhttp://localhost:8889/#/micro/live/about

所以,为了兼容主应用的 hash 模式路由,子应用也需要设置为 hash 模式的路由,最终结果是实现子应用路由与子应用注册在主应用的 activeRule 的一致性。

下面会分别对主应用与子应用进行配置。

配置子应用路由

子应用是常规 vue 项目,需要做调整的的是路由配置文件 /router/index.js 以及入口文件 main.js

// router/index.js

let prefix = ''

// 判断是 qiankun 环境则增加路由前缀
if(window.__POWERED_BY_QIANKUN__){
  prefix = '/micro/live'
}

const routes = [
  {
    path: prefix + '/',
    name: 'home',
    component: Home,
  },
  {
    path: prefix +'/about',
    name: 'about',
    component: About
  },
]
// main.js

let router = null;
let instance = null;

function render(props = {}) {
  const { container } = props;
  router = new VueRouter({
    // 默认为 hash 路由模式
    // base: window.__POWERED_BY_QIANKUN__ ? '/micro/live' : '/',
    // mode: 'history',
    routes,
  })

  // 判断 qiankun 环境则进行路由拦截,判断跳转路由是否有 /micro 开头前缀,没有则加上
  if(window.__POWERED_BY_QIANKUN__){
    router.beforeEach((to, from, next) => {
      if(!to.path.includes('/micro')){
        next({
          path: '/micro/live' + to.path
        })
      }else{
        next()
      }
    })
  }

  instance = new Vue({
    router,
    store,
    render: h => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

配置主应用路由

主应用需要修改的是子应用注册的路由匹配规则,因为主应用采用的是 hash 路由模式,qiankun 需要命中路由的话,activeRule 需要带上 /#/ 前缀。

// App.vue

const apps = [
  {
    name: 'live',
    entry: '//localhost:7101',
    container: '#subapp-viewport',
    activeRule: '/#/micro/live',
  }
]

registerMicroApps(apps, 
  {
    beforeLoad: [
      app => {
        console.log('[LifeCycle] before load %c%s', 'color: green;', app.name);
      },
    ],
    beforeMount: [
      app => {
        console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name);
      },
    ],
    afterUnmount: [
      app => {
        console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name);
      },
    ],
  },
)
// router/index.js

// httpRoutes 非必要,主要用于匹配 vue 应用路由,与路由通配符 {path: '*'} 一起使用
// 因为如果 vue 路由没有匹配,默认是加载 Home 组件的
// 这样 vue 路由视图会与子应用共存,不符合业务需求
//
// 当前 httpRoutes 的路由配置是没有设置 path 对应的组件,所以匹配的路由视图必为空
//
// 如果不设置路由通配符,则 httpRoutes 不需要配置
const httpRoutes = [
  {
    path: '/micro/live',
    name: 'Live'
    // 没有配置 component,则 router-view 不会加载组件
  },
  {
    path: '/micro/live/:microRoute',
    name: 'Live*'
    // 没有配置 component,则 router-view 不会加载组件
  }
]

const router = new VueRouter({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
    },
    ...httpRoutes,
    {
      path: '*',
      component: Home
    }
  ]
})

url 变化时,首先主应用进入的是 qiankun 的路由匹配规则,匹配到 /#/micro/live 时,会加载子应用,同时主应用的 vue 路由匹配到路由后不会加载路由组件,这样就达到只显示子应用而 vue 路由组件不显示的目的。

当子应用内部的 <router-link to="/about"> 被点击时,首先子应用跳转路由前会加上 /micro/live 前缀,实际上是 /micro/live/about,匹配到 about 路由,然后在主应用的 vue 路由中匹配到 /micro/live/:microRoute,同样不会加载组件。

本文参考:前端微服务(qiankun)哈希路由实践

往期系列文章

qiankun 微前端应用实践与部署

qiankun 微前端应用实践与部署(二)

qiankun 微前端应用实践与部署(三)

@ideapad460
Copy link

搜索到这里了,我尝试了一下,发现子应用里面确实可以跳转,但是router会报重定向? 错误信息Redirected when going from "/vue" to "/test" via a navigation guard

@jwchan1996
Copy link
Owner Author

搜索到这里了,我尝试了一下,发现子应用里面确实可以跳转,但是router会报重定向? 错误信息Redirected when going from "/vue" to "/test" via a navigation guard

这个你可能要检查一下路由跳转的逻辑有没有问题了~

@ideapad460
Copy link

搜索到这里了,我尝试了一下,发现子应用里面确实可以跳转,但是router会报重定向? 错误信息Redirected when going from "/vue" to "/test" via a navigation guard

这个你可能要检查一下路由跳转的逻辑有没有问题了~
子应用很简单,就2个页面一个/ 和 /test,用$router.push('/')和$router.push('/test')相互跳转,其实我就是想尝试兼容子项目$router.push(/xx)不用改动。$router.push('/vue') $router.push('/vue/test')这样相互跳转是没问题的,不会报重定向。

@jwchan1996
Copy link
Owner Author

搜索到这里了,我尝试了一下,发现子应用里面确实可以跳转,但是router会报重定向? 错误信息Redirected when going from "/vue" to "/test" via a navigation guard

这个你可能要检查一下路由跳转的逻辑有没有问题了~
子应用很简单,就2个页面一个/ 和 /test,用$router.push('/')和$router.push('/test')相互跳转,其实我就是想尝试兼容子项目$router.push(/xx)不用改动。$router.push('/vue') $router.push('/vue/test')这样相互跳转是没问题的,不会报重定向。

emmm,文章这种方式子应用需要稍微设置一下路由守卫,来保证被主应用发现 😲。

@joden2014
Copy link

请问一下,子应用跳到另外一个子应用的某个二级路由下,该怎么配置

@jwchan1996
Copy link
Owner Author

请问一下,子应用跳到另外一个子应用的某个二级路由下,该怎么配置

你的子应用切换配好了吗,配好了直接在 A 子应用跳到 B 子应用二级路由就好了,主应用会解析 activeRule 加载对应的 B 子应用,B 子应用会自己跳到二级路由的~

@jwchan1996
Copy link
Owner Author

请问一下,子应用跳到另外一个子应用的某个二级路由下,该怎么配置

或者用 qiankun 的通信机制,子应用通知主应用,让主应用做统一的路由切换

@joden2014
Copy link

请问一下,子应用跳到另外一个子应用的某个二级路由下,该怎么配置

或者用 qiankun 的通信机制,子应用通知主应用,让主应用做统一的路由切换
好的,我都试试,谢谢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants