Files
MoviePilot-Frontend/docs/module-federation-guide.md

6.5 KiB
Raw Blame History

MoviePilot前端远程模块开发指南

1. 概述

MoviePilot前端采用模块联邦(Module Federation)技术实现插件的动态加载和集成。本文档详细说明如何开发符合要求的远程模块以便在MoviePilot中作为插件使用。

2. 技术要求

  • Node.js 16+
  • Vue 3
  • Vite 4+
  • TypeScript 5+

3. 核心概念

每个插件需要提供三个标准组件:

组件名称 文件名 用途
Page Page.js 插件详情页面
Config Config.js 插件配置页面
Dashboard Dashboard.js 仪表板组件

4. 快速开始

创建项目

# 创建项目
npm create vite@latest my-plugin -- --template vue-ts

# 进入项目目录
cd my-plugin

# 安装依赖
npm install

# 安装模块联邦插件
npm install @originjs/vite-plugin-federation --save-dev

# 安装Vuetify(可选)
npm install vuetify

配置vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import federation from '@originjs/vite-plugin-federation'

export default defineConfig({
  plugins: [
    vue(),
    federation({
      name: 'my_plugin',  // 插件名称建议与插件ID保持一致
      filename: 'remoteEntry.js',
      exposes: {
        './Page': './src/components/Page.vue',
        './Config': './src/components/Config.vue',
        './Dashboard': './src/components/Dashboard.vue',
      },
      shared: {
        vue: { requiredVersion: false },
        vuetify: { requiredVersion: false }
      }
    })
  ],
  build: {
    target: 'esnext',   // 必须设置为esnext以支持顶层await
    minify: false,      // 开发阶段建议关闭混淆
    cssCodeSplit: false,
    rollupOptions: {
      output: {
        format: 'esm',  // 必须使用ESM格式
        entryFileNames: '[name].js',
        chunkFileNames: '[name].js',
      }
    }
  }
})

5. 组件开发规范

5.1 Page组件详情页面

<script setup lang="ts">
// 自定义事件,用于通知主应用刷新数据
const emit = defineEmits(['action'])

// 页面逻辑代码...

// 通知主应用刷新数据
function notifyRefresh() {
  emit('action')
}
</script>

<template>
  <div class="plugin-page">
    <!-- 插件详情页面内容 -->
    <v-btn @click="notifyRefresh">刷新数据</v-btn>
  </div>
</template>

5.2 Config组件配置页面

<script setup lang="ts">
// 接收初始配置
const props = defineProps({
  initialConfig: {
    type: Object,
    default: () => ({})
  }
})

// 配置数据
const config = ref({...props.initialConfig})

// 自定义事件,用于保存配置
const emit = defineEmits(['save'])

// 保存配置
function saveConfig() {
  emit('save', config.value)
}
</script>

<template>
  <div class="plugin-config">
    <!-- 配置表单 -->
    <v-text-field v-model="config.someField" label="配置项"></v-text-field>
    
    <!-- 保存按钮 -->
    <v-btn color="primary" @click="saveConfig">保存配置</v-btn>
  </div>
</template>

5.3 Dashboard组件仪表板

<script setup lang="ts">
// 接收配置和刷新控制
const props = defineProps({
  config: {
    type: Object,
    default: () => ({})
  },
  allowRefresh: {
    type: Boolean,
    default: true
  }
})

// 仪表板逻辑...
</script>

<template>
  <div class="dashboard-widget">
    <!-- 仪表板内容 -->
    <v-card>
      <v-card-title>{{ config.title || '仪表板组件' }}</v-card-title>
      <v-card-text>
        <!-- 组件内容 -->
      </v-card-text>
    </v-card>
  </div>
</template>

6. 构建和部署

构建项目

npm run build

输出文件

构建后会在dist目录生成以下核心文件:

  • remoteEntry.js - 模块联邦入口文件
  • Page.js - 详情页面组件
  • Config.js - 配置页面组件
  • Dashboard.js - 仪表板组件

部署要求

这些文件需要部署到后端并通过以下URL可访问

  • /api/v1/plugin/file/{插件ID}/dist/remoteEntry.js
  • /api/v1/plugin/file/{插件ID}/dist/Page.js
  • /api/v1/plugin/file/{插件ID}/dist/Config.js
  • /api/v1/plugin/file/{插件ID}/dist/Dashboard.js

7. 后端API要求

7.1 注册远程组件API

后端需要实现以下API用于注册远程组件已公共实现插件按第三方插件开发要求实现get_form_fileget_page_fileget_dashboard_file即可):

GET /api/plugins/remotes

返回结构:

[
  {
    "id": "my-plugin",              // 插件ID必需
    "url": "/custom/path/to/plugin" // 自定义组件路径,可选
  },
  {
    "id": "another-plugin"          // 使用默认路径
  }
]

7.2 组件访问路径

指定了url后使用:

  • {url}/remoteEntry.js
  • {url}/Page.js
  • {url}/Config.js
  • {url}/Dashboard.js

8. 调试与排错

常见问题

  1. 模块无法加载

    • 检查网络请求是否成功状态码200
    • 确认文件路径是否正确
    • 检查CORS跨域设置
  2. 模块加载但组件不显示

    • 检查控制台错误信息
    • 确认组件是否正确导出
    • 验证共享依赖配置
  3. "Module name 'vue' does not resolve to a valid URL"

    • 检查shared配置是否正确
    • 设置requiredVersion: false尝试解决
  4. "Top-level await is not available"

    • 确保build.target设置为esnext

9. 高级配置

9.1 CSS隔离

为防止样式冲突建议使用CSS Modules或scoped样式

<style scoped>
/* 组件样式 */
</style>

9.2 共享更多依赖

如果您的插件需要共享更多依赖可以扩展shared配置

shared: {
  vue: { requiredVersion: false },
  vuetify: { requiredVersion: false },
  '@vueuse/core': { requiredVersion: false },
  pinia: { requiredVersion: false }
}

9.3 开发环境测试

开发期间可以使用以下配置在本地测试:

// vite.config.ts
export default defineConfig({
  server: {
    port: 5001,   // 使用不同于主应用的端口
    cors: true,   // 启用CORS
    origin: 'http://localhost:5001'
  }
})

10. 示例代码

完整的示例插件代码可在以下仓库获取:

https://github.com/example/moviepilot-plugin-example (示例链接,实际链接需替换)

11. 参考资料


如有问题请提交Issue。