You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何卸载脚本,让Vue组件每次挂载时重新加载?

问题:Module Federation远程组件重新挂载时无法重新加载脚本

需求是实现组件卸载后,再次挂载时能重新加载对应的远程脚本,但当前代码执行后,组件卸载再挂载并不会重新加载目标文件。

Vue组件代码

<template>
  <div id="root">
    <component :is="App" />
  </div>
</template>

<script setup>
import { defineAsyncComponent, ref, onMounted, onUnmounted } from 'vue';

const App = ref(null);
onMounted(() => {
  App.value = defineAsyncComponent(() => import('editor/App'));
});

onUnmounted(() => {
  App.value = null;
});
</script>

Webpack Module Federation配置

const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  configureWebpack: {
    plugins: [
      new ModuleFederationPlugin({
        name: 'consumer',
        filename: 'remoteEntry.js',
        remotes: {
          editor: process.env.FRONTEND_EDITOR_URI,
        },
      }),
    ],
  },
};

解决思路

1. 清除Webpack模块缓存

Webpack会缓存所有异步加载的模块,即使把App设为null,下次import时还是会直接用缓存的模块,不会重新请求脚本。解决办法是在组件卸载时,手动清除对应模块的缓存:

修改Vue组件的onUnmounted钩子:

onUnmounted(() => {
  App.value = null;
  // 清除Webpack对远程组件的缓存
  Object.keys(__webpack_module_cache__).forEach(key => {
    // 根据实际路径调整匹配规则
    if (key.includes('editor/App')) {
      delete __webpack_module_cache__[key];
    }
  });
  // 可选:清除remoteEntry的缓存
  const remoteEntryUrl = process.env.FRONTEND_EDITOR_URI.replace(/^editor@/, '');
  Object.keys(__webpack_module_cache__).forEach(key => {
    if (key.includes(remoteEntryUrl)) {
      delete __webpack_module_cache__[key];
    }
  });
});

这样下次onMounted里执行import('editor/App')时,Webpack会重新发起请求加载脚本。

2. 动态加载RemoteEntry脚本(更彻底的方案)

如果静态配置的remotes无法满足需求,可以改为动态加载remoteEntry,每次挂载组件时都重新加载远程入口脚本,确保拿到最新的资源:

<template>
  <div id="root">
    <component :is="App" v-if="App" />
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const App = ref(null);
const remoteEntryUrl = process.env.FRONTEND_EDITOR_URI.replace(/^editor@/, '');
let remoteScript = null;

async function loadRemoteComponent() {
  // 清理旧资源和缓存
  if (remoteScript) {
    remoteScript.remove();
    remoteScript = null;
    delete window.editor;
    // 清除所有和editor相关的Webpack缓存
    Object.keys(__webpack_module_cache__).forEach(key => {
      if (key.includes('editor')) {
        delete __webpack_module_cache__[key];
      }
    });
  }

  // 动态加载remoteEntry.js
  await new Promise((resolve, reject) => {
    remoteScript = document.createElement('script');
    remoteScript.src = remoteEntryUrl;
    remoteScript.onload = resolve;
    remoteScript.onerror = reject;
    document.body.appendChild(remoteScript);
  });

  // 初始化远程模块的共享作用域
  await window.editor.init(__webpack_share_scopes__.default);
  // 加载远程组件
  const module = await window.editor.get('./App');
  App.value = module.default;
}

onMounted(() => {
  loadRemoteComponent();
});

onUnmounted(() => {
  App.value = null;
  if (remoteScript) {
    remoteScript.remove();
    remoteScript = null;
    delete window.editor;
    Object.keys(__webpack_module_cache__).forEach(key => {
      if (key.includes('editor')) {
        delete __webpack_module_cache__[key];
      }
    });
  }
});
</script>

这种方式完全绕开了静态remotes的缓存,每次挂载都重新拉取remoteEntry和组件脚本,适合需要强制刷新远程组件的场景。

3. 注意事项

  • __webpack_module_cache__是Webpack内部变量,不同版本可能有差异,测试时需确认当前版本兼容性。
  • 动态加载脚本时要添加错误处理,避免组件挂载异常。
  • 如果远程组件有共享依赖,确保共享作用域初始化正确,避免依赖冲突。

内容的提问来源于stack exchange,提问作者Artem Ivanychev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:50:32