前端微服务

预加载微服务框架 https://github.com/niuyueyang/weifuku

预加载路由

解释点

  • 子项目按照 vue-cli 3 的 library 模式进行打包,以便后续主项目引用
    注:在 library 模式中,Vue 是外置的。这意味着包中不会有 Vue,即便你在代码中导入了 Vue。如果这个库会通过一个打包器使用,它将尝试通过打包器以依赖的方式加载 Vue;否则就会回退到一个全局的 Vue 变量。
  • 在编译主项目的时候,通过 InsertScriptPlugin 插件将子项目的入口文件 main.js 以 script 标签形式插入到主项目的 html 中
class InsertScriptWebpackPlugin {
  constructor(options = {}) {
    const { files = [] } = options;
    this.files = files;
  }

  apply(compiler) {
    const self = this;
    compiler.hooks.compilation.tap(
      'InsertScriptWebpackPlugin',
      (compilation) => {
        if (compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing) {
          compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tap(
            'InsertScriptWebpackPlugin',
            (htmlPluginData) => {
              const {
                assets: { js },
              } = htmlPluginData;
              js.unshift(...self.files);
            },
          );
        } else {
          console.log('\n');
          console.log(
            '\x1b[41m%s\x1b[0m',
            'Error:',
            '`insert-script-webpack-plugin` dependent on `html-webpack-plugin`',
          );
        }
      },
    );
  }
}

module.exports = InsertScriptWebpackPlugin;

注:务必将子项目的入口文件 main.js 对应的 script 标签放在主项目入口文件 app.js 的 script 标签之上,这是为了确保子项目的入口文件先于主项目的入口文件代码执行,接下来的步骤就会明白为什么这么做。
再注:本地开发环境下项目的入口文件编译后的 main.js 是保存在内存中的,所以磁盘上看不见,但是可以访问。

InsertScriptPlugin 核心代码如下:

compiler.hooks.compilation.tap('InsertScriptWebpackPlugin', (compilation) => {
  compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tap(
    'InsertScriptWebpackPlugin',
    (htmlPluginData) => {
      const {
        assets: { js }
      } = htmlPluginData;
      // 将传入的 js 以 script 标签形式插入到 html 中
      // 注意:需要将子项目的入口文件 main.js 放在主项目入口文件 app.js 之前,因为需要子项目提前将自己的 route list 注册到全局上
      js.unshift(...self.files);
    }
  );
});

  • 主项目的 html 要访问子项目里的编译后的 js / css 等资源,需要进行代理转发
  1. 如果是本地开发时,可以通过 webpack 提供的 proxy,例如
const PROXY = {
  '/app-typescript/': {
    target: 'http://localhost:10241/'
  },
  '/app-javascript/': {
    target: 'http://localhost:10242/'
  },
  '/test/': {
    target: 'http://localhost:10243/'
  }
}
  1. 如果是线上部署时,可以通过 nginx 转发或者将打包后的主项目和子项目放在一个文件夹中按照相对路径引用。
  • 当浏览器解析 html 时,解析并执行到子项目的入口文件 main.js,将子项目的 route list 注册到 Vue.share.routes 上,以便后续主项目将其合并到总的路由中。
    子项目 main.js 代码如下:(为了尽量减少首次主项目页面渲染时加载的资源,子项目的入口文件建议只做路由挂载)
import Vue from 'vue';
import routes from './routes';

const share = (Vue.__share__ = Vue.__share__ || {});
const routesPool = (share.routes = share.routes || {});

// 将子项目的 route list 挂载到 Vue.__share__.routes 上,以便后续主项目将其合并到总的路由中
routesPool[process.env.VUE_APP_NAME] = routes;

  • 继续向下解析 html,解析并执行到主项目 main.js 时,从 Vue.share.routes 获取所有子项目的 route list,合并到总的路由表中,然后初始化一个 vue-router 实例,并传入到 new Vue 内
// 从 Vue.__share__.routes 获取所有子项目的 route list,合并到总的路由表中
const routes = Vue.__share__.routes;

export default new Router({
  routes: Object.values(routes).reduce((acc, prev) => acc.concat(prev), [
    {
      path: '/',
      redirect: '/app-typescript'
    }
  ])
});

另外如果需要使用 vuex,则和 vue-router 的顺序恰好相反(先主项目后子项目):
1.首先在主项目的入口文件中初始化一个 store 实例 new Vuex.Store,然后挂在到 Vue.share.store 上
2.然后在子项目的 App.vue 中获取到 Vue.share.store 并调用 store.registerModule(‘app-x’, store),将子项目的 store 作为子模块注册到 store 上

懒加载微服务框架

框架 https://github.com/niuyueyang/weifuwuyibu

定义

懒加载路由,顾名思义,就是说等到用户点击要进入子项目模块,通过解析即将跳转的路由确定是哪一个子项目,然后再异步去加载该子项目的入口文件 main.js(可以通过 systemjs 或者自己写一个动态创建 script 标签并插入 body 的方法)。加载成功后就可以将子项目的路由动态添加到主项目总的路由里了。

解释

  • 主项目 router.js 文件中定义了在 vue-router 的 beforeEach 钩子去拦截路由,并根据即将跳转的路由分析出需要哪个子项目,然后去异步加载对应子项目入口文件,下面是核心代码:
const cachedModules = new Set();

router.beforeEach(async (to, from, next) => {
  const [, module] = to.path.split('/');

  if (Reflect.has(modules, module)) {
    // 如果已经加载过对应子项目,则无需重复加载,直接跳转即可
    if (!cachedModules.has(module)) {
      const { default: application } = await window.System.import(modules[module])

      if (application && application.routes) {
        // 动态添加子项目的 route-list
        router.addRoutes(application.routes);
      }

      cachedModules.add(module);
      next(to.path);
    } else {
      next();
    }
    return;
  }
});

  • 子项目的入口文件 main.js 仅需要将子项目的 routes 暴露给主项目即可,代码如下:
import routes from './routes';

export default {
  name: 'javascript',
  routes,
  beforeEach(from, to, next) {
    console.log('javascript:', from.path, to.path);
    next();
  },
}

注意:这里除了暴露 routes 方法外,另外又暴露了 beforeEach 方法,其实就是为了支持通过路由守卫对子项目进行页面权限限制,主项目拿到这个子项目的 beforeEach,可以在 vue-router 的 beforeEach 钩子执行,具体代码请参考 async-routes。

除了主项目和子项目的交互方式不同,代理转发子项目资源、vuex store 注册等和上面的预加载路由完全一致。

优缺点

下面谈下这套方案的优缺点:

优点

  1. 子项目可单独打包、单独部署上线,提升了开发和打包的速度

  2. 子项目之间开发互相独立,互不影响,可在不同仓库进行维护,减少的单个项目的规模

  3. 保持单页应用的体验,子项目之间切换不刷新

  4. 改造成本低,对现有项目侵入度较低,业务线迁移成本也较低

  5. 保证整体项目统一一个技术栈

缺点:

主项目和子项目需要共用一个 Vue 实例,所以无法做到某个子项目单独使用最新版 Vue(例如 Vue3)或者 React

部分问题解答

  1. 如果子项目代码更新后,除了打包部署子项目之外,还需要打包部署主项目吗?

    不需要更新部署主项目。这里有个 trick 上文忘记提及,就是子项目打包后的入口文件并没有加上 chunkhash,直接就是 main.js(子项目其他的 js 都有 chunkhash)。也就是说主项目只需要记住子项目的名字,就可以通过 subapp-name/main.js 找到子项目的入口文件,所以子项目打包部署后,主项目并不需要更新任何东西。

  2. 针对第二个问题中子项目入口文件 main.js 不使用 chunkhash 的话,如何防止该文件始终被缓存呢?
    可以在静态资源服务器端针对子项目入口文件设置强制缓存为不缓存,下面是服务器为 nginx 情况的相关配置:
    location / {
    set e x p i r e s t i m e 7 d ; . . . i f ( expires_time 7d; ... if ( expirestime7d;...if(request_uri ~* /(contract|meeting|crm)-app/main.js(?.*)?$) {
    # 针对入口文件设置 expires_time -1,即expire是服务器时间的 -1s,始终过期
    set $expires_time -1;
    }
    expires $expires_time;

    }

参考 https://juejin.im/post/5e5c9bff51882548fe291950

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3前端微服务框架是一种基于Vue.js 3的前端开发框架,它旨在帮助开发者构建可扩展和可维护的微服务应用程序。该框架提供了一些核心功能和特性,使得开发者可以更轻松地将前端应用程序拆分为多个独立的微服务,并通过组合这些微服务来构建完整的应用程序。 以下是Vue 3前端微服务框架的一些特点和功能: 1. 模块化开发:框架支持将前端应用程序拆分为多个独立的模块,每个模块可以独立开发、测试和部署。这种模块化的开发方式可以提高代码的可维护性和可扩展性。 2. 组件化架构:框架采用了组件化的开发方式,开发者可以将应用程序拆分为多个可复用的组件,每个组件负责特定的功能。这种组件化的架构可以提高代码的复用性和可读性。 3. 路由管理:框架提供了路由管理功能,开发者可以通过定义路由来实现不同微服务之间的页面跳转和导航。这样可以使得应用程序具有更好的用户体验和导航功能。 4. 状态管理:框架支持状态管理,开发者可以使用状态管理来管理应用程序的状态。这样可以使得不同微服务之间可以共享和同步状态,提高应用程序的响应性和一致性。 5. 插件系统:框架提供了插件系统,开发者可以通过使用插件来扩展框架的功能。这样可以使得开发者可以根据自己的需求来选择和集成所需的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值