vue + webpack + ModuleFederation的dev serve 方案(动态加载资源)

使用模块联邦简单搭建的项目在开发的时候需要将所有模块进行启动,才能保证项目正常访问,这无疑是很麻烦的,且很消耗电脑资源的一种方式,所以会考虑是否只启动开发的应用,其他应用加载静态资源。接下来分享我使用的 dev serve 方案。

远程模块加载

webpack 提供通过 urlpromise 两种方式来进行加载,接下来介绍下这两种方式是如何使用的。

url方式加载远程模块

webpack 配置如下

webpack.config.js
js 复制代码
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      remotes:{
          app:"http://xxx/remoteEntry.js"
      }
    }),
  ],
};

这么配置会有一个问题,就是在打包部署后,又单独更新的app模块,当浏览器在更新前访问过,已经有 http://xxx/remoteEntry.js 的缓存,就会导致加载不到新更新的app,必须强制清缓存。所以需要保证 http://xxx/remoteEntry.js 不缓存,每次都加载最新的。

优点 :代码中配置简单
缺点:需要修改服务器配置(nginx/cdn),当模块过多,模块的入口文件不进行缓存,会导致页面初始化慢一点

promise方式加载远程模块(我使用的方式)

之所以要考虑使用promise的方式加载远程模块,就是既要 保证线上运行时能够加载到最新的模块代码,又要使用浏览器的缓存机制最大的提升页面访问速度。

模块加载方法
js 复制代码
window.__LOAD_MODULE_PROMISE__ = (module) => {
  return (resolve, reject)=>{
    if(!window.__APP_VERSIONS__) window.__APP_VERSIONS__ = {};
    if(!window.__APP_VERSIONS__[module]) window.__APP_VERSIONS__[module] = Date.now();
    import((window.location.origin)+"/app/"+module+"/remoteEntry.js?_v="+ window.__APP_VERSIONS__[module]).then(resolve).catch(reject);
  }
}
webpack.config.js
js 复制代码
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      remotes:{
          app:"promise new Promise(window.__LOAD_MODULE_PROMISE__('app'))"
      }
    }),
  ],
};

可以看到,在模块加载的时候,在加载路径上会拼接模块的版本,来保证模块更新后,浏览器也会加载到最新版本的模块代码。全局的模块版本配置会随着模块的更新而同步更新。

主代理服务

主代理服务是一个简单的代理服务,没有业务代码,其中主要是代理逻辑的配置,我使用的代理规则如下:

  1. 访问dev-server服务
  2. 访问本地模块打包后的静态代码
  3. 访问远程开发环境部署的模块代码
  4. 报错

实现以上规则的话需要做如下工作:

模块静态资源

将模块打包后的静态资源存放在主代理服务中,在代理启动后,即使不启动任何一个模块服务,也可以访问项目。

模块dev-serve配置

动态端口

dev-server中的端口不静态写死,在启动的服务的时候动态获取到一个空闲的端口,进行启动。

服务广播

dev-server支持 bonjour,使用 bonjour 可以实现服务发现的逻辑,让主代理服务自动发现正在运行的模块服务及对应的服务端口,方便进行代理转发

webpack.config.js
js 复制代码
module.exports = {
    devServer: {
      bonjour: {
        type: "app", // app | container 自己定义的容器或应用,和模块联邦无关
        name: "app-a"
      },
      ...
    }
}
proxy

使用bonjour进行监听服务启动,做对应的代理注册/取消代理

js 复制代码
const bonjourClient = require('bonjour')();
const appBrowser = bonjourClient.find({type: 'app'})
appBrowser.on('up',  function(service){
  //...
  // const {type, name, port} = service
});
appBrowser.on('down',  function(service){
  //...
});

const containerBrowser = bonjourClient.find({type: 'container'})
containerBrowser.on('up',  function(service){
  //...
});
containerBrowser.on('down',  function(service){
  //...
});

代理服务中还有对对静态文件的代理,以及对远程服务的代理,这两块就不一一举例了,实现时主要就是用 express + http-proxy-middleware 来实现的,使用cli-table3 做了下终端代理状态展示。

相关推荐
无巧不成书021835 分钟前
Windows PowerShell执行策略详解:从npm报错到完美解决
前端·windows·npm·powershell执行策略·执行策略·npm.ps1·脚本报错
Z兽兽7 小时前
React@18+Vite项目配置env文件
前端·react.js·前端框架
SuniaWang7 小时前
《Spring AI + 大模型全栈实战》学习手册系列 · 专题六:《Vue3 前端开发实战:打造企业级 RAG 问答界面》
java·前端·人工智能·spring boot·后端·spring·架构
A_nanda8 小时前
根据AI提示排查vue前端项目
前端·javascript·vue.js
happymaker06268 小时前
web前端学习日记——DAY05(定位、浮动、视频音频播放)
前端·学习·音视频
~无忧花开~8 小时前
React状态管理完全指南
开发语言·前端·javascript·react.js·前端框架
LegendNoTitle9 小时前
计算机三级等级考试 网络技术 选择题考点详细梳理
服务器·前端·经验分享·笔记·php
@大迁世界9 小时前
1.什么是 ReactJS?
前端·javascript·react.js·前端框架·ecmascript
BJ-Giser10 小时前
Cesium 基于EZ-Tree的植被效果
前端·可视化·cesium
王码码203511 小时前
Flutter for OpenHarmony:Flutter 三方库 algoliasearch 毫秒级云端搜索体验(云原生搜索引擎)
android·前端·git·flutter·搜索引擎·云原生·harmonyos