mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-06 08:06:43 +08:00
更新组件声明,移除 LocaleSwitcher 和 ThemeSwitcher,更新 README 文档以增强模块联邦功能的描述,并调整 Vite 配置以支持 ESNext 目标。
This commit is contained in:
@@ -4,6 +4,22 @@
|
|||||||
|
|
||||||
[MoviePilot](https://github.com/jxxghp/MoviePilot) 的前端项目,NodeJS版本:>= `v20.12.1`。
|
[MoviePilot](https://github.com/jxxghp/MoviePilot) 的前端项目,NodeJS版本:>= `v20.12.1`。
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
- 基于 Vue 3 和 Vuetify 3 构建的现代化界面
|
||||||
|
- 使用 Vite 作为构建工具,提供快速的开发体验
|
||||||
|
- 支持多语言(中文/英文)
|
||||||
|
- 完整的插件系统支持,包括远程组件动态加载
|
||||||
|
|
||||||
|
## 模块联邦功能
|
||||||
|
|
||||||
|
MoviePilot 现已支持模块联邦(Module Federation)功能,允许插件开发者创建可动态加载的远程组件,实现更丰富的插件用户界面。
|
||||||
|
|
||||||
|
### 相关文档
|
||||||
|
|
||||||
|
- [模块联邦问题排查指南](docs/federation-troubleshooting.md) - 常见问题和解决方案
|
||||||
|
- [插件远程组件示例](examples/plugin-component/) - 开发插件组件的完整示例项目
|
||||||
|
|
||||||
## 推荐的IDE设置
|
## 推荐的IDE设置
|
||||||
|
|
||||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (并禁用 Vetur).
|
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (并禁用 Vetur).
|
||||||
|
|||||||
+25
-9
@@ -2,39 +2,55 @@
|
|||||||
|
|
||||||
*[中文](README.md) | English*
|
*[中文](README.md) | English*
|
||||||
|
|
||||||
Frontend project for [MoviePilot](https://github.com/jxxghp/MoviePilot), NodeJS version: >= `v20.12.1`.
|
Frontend project for [MoviePilot](https://github.com/jxxghp/MoviePilot), NodeJS version required: >= `v20.12.1`.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Modern interface built with Vue 3 and Vuetify 3
|
||||||
|
- Fast development experience with Vite build tool
|
||||||
|
- Multi-language support (Chinese/English)
|
||||||
|
- Complete plugin system with dynamic remote component loading
|
||||||
|
|
||||||
|
## Module Federation
|
||||||
|
|
||||||
|
MoviePilot now supports Module Federation, allowing plugin developers to create dynamically loadable remote components for richer plugin user interfaces.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- [Module Federation Troubleshooting Guide](docs/federation-troubleshooting.md) - Common issues and solutions
|
||||||
|
- [Plugin Remote Component Example](examples/plugin-component/) - Complete example project for developing plugin components
|
||||||
|
|
||||||
## Recommended IDE Setup
|
## Recommended IDE Setup
|
||||||
|
|
||||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (disable Vetur).
|
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (disable Vetur).
|
||||||
|
|
||||||
## Vite Configuration
|
## Configure Vite
|
||||||
|
|
||||||
Please refer to [Vite Configuration Reference](https://vitejs.dev/config/).
|
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||||
|
|
||||||
## Installation
|
## Install Dependencies
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn
|
yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
### Development
|
### Development Server
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn dev
|
yarn dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build
|
### Build for Production
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn build
|
yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Production Deployment
|
### Static Deployment
|
||||||
|
|
||||||
1. Use `nginx` or other web servers to host the `dist` static files. See `public/nginx.conf` for nginx configuration reference.
|
1. Host the `dist` static files using a web server like `nginx`. Refer to `public/nginx.conf` for nginx configuration.
|
||||||
|
|
||||||
2. Use `node` command to run `service.js` directly. It listens on port `3000` by default. Set the environment variable `NGINX_PORT` to adjust the port.
|
2. Alternatively, run the `service.js` directly with the `node` command. It listens on port `3000` by default. Set the `NGINX_PORT` environment variable to adjust the port.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
node dist/service.js
|
node dist/service.js
|
||||||
|
|||||||
Vendored
-2
@@ -12,13 +12,11 @@ declare module 'vue' {
|
|||||||
ErrorHeader: typeof import('./src/@core/components/ErrorHeader.vue')['default']
|
ErrorHeader: typeof import('./src/@core/components/ErrorHeader.vue')['default']
|
||||||
ExistIcon: typeof import('./src/@core/components/ExistIcon.vue')['default']
|
ExistIcon: typeof import('./src/@core/components/ExistIcon.vue')['default']
|
||||||
LoadingBanner: typeof import('./src/@core/components/LoadingBanner.vue')['default']
|
LoadingBanner: typeof import('./src/@core/components/LoadingBanner.vue')['default']
|
||||||
LocaleSwitcher: typeof import('./src/@core/components/LocaleSwitcher.vue')['default']
|
|
||||||
MoreBtn: typeof import('./src/@core/components/MoreBtn.vue')['default']
|
MoreBtn: typeof import('./src/@core/components/MoreBtn.vue')['default']
|
||||||
PageContentTitle: typeof import('./src/@core/components/PageContentTitle.vue')['default']
|
PageContentTitle: typeof import('./src/@core/components/PageContentTitle.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
ScrollToTopBtn: typeof import('./src/@core/components/ScrollToTopBtn.vue')['default']
|
ScrollToTopBtn: typeof import('./src/@core/components/ScrollToTopBtn.vue')['default']
|
||||||
StatIcon: typeof import('./src/@core/components/StatIcon.vue')['default']
|
StatIcon: typeof import('./src/@core/components/StatIcon.vue')['default']
|
||||||
ThemeSwitcher: typeof import('./src/@core/components/ThemeSwitcher.vue')['default']
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
# MoviePilot 模块联邦问题排查指南
|
||||||
|
|
||||||
|
本文档提供了针对 MoviePilot 项目中使用模块联邦时可能遇到的常见问题及解决方案。
|
||||||
|
|
||||||
|
关联阅读后端插件开发文档:[第三方插件开发说明](https://github.com/jxxghp/MoviePilot-Plugins/blob/main/README.md)
|
||||||
|
|
||||||
|
## 常见错误
|
||||||
|
|
||||||
|
### 1. "Module name 'vue' does not resolve to a valid URL"
|
||||||
|
|
||||||
|
**原因**:远程组件无法正确解析共享依赖的 URL,通常是因为共享依赖配置不正确。
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
|
||||||
|
1. 在 **插件组件项目** 的 `vite.config.js` 中正确配置共享依赖:
|
||||||
|
|
||||||
|
```js
|
||||||
|
federation({
|
||||||
|
// ...
|
||||||
|
shared: {
|
||||||
|
vue: {
|
||||||
|
singleton: true,
|
||||||
|
requiredVersion: false // 关闭版本检查
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 在 **主应用** 的 `vite.config.ts` 中确保共享依赖配置正确:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
federation({
|
||||||
|
name: 'host',
|
||||||
|
remotes: {},
|
||||||
|
shared: ['vue', 'vuetify']
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. "Top-level await is not available in the configured target environment"
|
||||||
|
|
||||||
|
**原因**:模块联邦使用了顶层 await,但目标构建环境不支持此功能。
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
|
||||||
|
在 **主应用** 和 **插件组件项目** 的构建配置中添加 `target: 'esnext'`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
build: {
|
||||||
|
target: 'esnext', // 支持顶层await
|
||||||
|
// 其他配置...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. "TypeError: Failed to fetch dynamically imported module"
|
||||||
|
|
||||||
|
**原因**:远程组件 JS 文件无法被正确加载,可能是路径错误或网络问题。
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
|
||||||
|
1. 检查网络请求是否成功(状态码200)
|
||||||
|
2. 确认组件 URL 是否正确
|
||||||
|
3. 确保服务器允许访问该 JS 文件(CORS 配置)
|
||||||
|
4. 检查插件后端是否正确提供了静态文件服务
|
||||||
|
|
||||||
|
### 4. 组件加载后渲染为空白或出现错误
|
||||||
|
|
||||||
|
**原因**:组件内部代码错误或与主应用不兼容。
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
|
||||||
|
1. 检查浏览器控制台错误信息
|
||||||
|
2. 确保组件代码没有语法错误
|
||||||
|
3. 避免在组件中使用主应用未提供的依赖
|
||||||
|
4. 确保所有路径(如图片、API请求URL等)都是正确的
|
||||||
|
|
||||||
|
## 调试技巧
|
||||||
|
|
||||||
|
### 1. 启用详细日志
|
||||||
|
|
||||||
|
在浏览器控制台中设置:
|
||||||
|
|
||||||
|
```js
|
||||||
|
localStorage.setItem('debug', 'vite:*')
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 分析网络请求
|
||||||
|
|
||||||
|
1. 打开浏览器开发者工具
|
||||||
|
2. 转到 Network 标签页
|
||||||
|
3. 确认远程组件 JS 文件请求是否成功
|
||||||
|
4. 分析响应内容是否为有效的 JavaScript
|
||||||
|
|
||||||
|
### 3. 隔离测试远程组件
|
||||||
|
|
||||||
|
创建一个独立的简单页面来测试插件组件,排除主应用的干扰因素。
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 插件组件项目配置
|
||||||
|
|
||||||
|
```js
|
||||||
|
// vite.config.js
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import federation from '@originjs/vite-plugin-federation'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
federation({
|
||||||
|
name: 'remoteApp',
|
||||||
|
filename: 'remoteEntry.js',
|
||||||
|
exposes: {
|
||||||
|
'./PluginComponent': './src/App.vue',
|
||||||
|
},
|
||||||
|
shared: {
|
||||||
|
vue: {
|
||||||
|
singleton: true,
|
||||||
|
requiredVersion: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
build: {
|
||||||
|
target: 'esnext',
|
||||||
|
minify: false, // 开发阶段禁用最小化,方便调试
|
||||||
|
cssCodeSplit: false,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
minifyInternalExports: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插件组件代码
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="plugin-container">
|
||||||
|
<!-- 组件内容 -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
// 向主应用发送事件
|
||||||
|
const emit = defineEmits(['action'])
|
||||||
|
|
||||||
|
// 初始化逻辑...
|
||||||
|
|
||||||
|
// 通知主应用
|
||||||
|
function notifyHost() {
|
||||||
|
emit('action')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 显式依赖声明
|
||||||
|
|
||||||
|
在插件组件的 `package.json` 中准确声明所有依赖:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^3.3.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@originjs/vite-plugin-federation": "^1.3.5",
|
||||||
|
"@vitejs/plugin-vue": "^4.4.0",
|
||||||
|
"vite": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其他资源
|
||||||
|
|
||||||
|
- [Vite 模块联邦插件文档](https://github.com/originjs/vite-plugin-federation)
|
||||||
|
- [Vite 官方文档](https://vitejs.dev/guide/build.html)
|
||||||
|
- [Origin.js 模块联邦示例](https://github.com/originjs/vite-plugin-federation/tree/main/packages/examples)
|
||||||
|
- [MoviePilot 插件组件示例](../examples/plugin-component/)
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
# MoviePilot 插件远程组件示例
|
||||||
|
|
||||||
|
这是 MoviePilot 插件远程组件的示例项目,展示了如何正确配置和开发与主应用兼容的远程组件。
|
||||||
|
|
||||||
|
## 开发环境准备
|
||||||
|
|
||||||
|
1. 安装依赖:
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
# 或
|
||||||
|
yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 开发模式运行:
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# 或
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### vite.config.js
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import federation from '@originjs/vite-plugin-federation'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
federation({
|
||||||
|
name: 'remoteApp',
|
||||||
|
filename: 'remoteEntry.js',
|
||||||
|
exposes: {
|
||||||
|
'./PluginComponent': './src/App.vue', // 暴露组件
|
||||||
|
},
|
||||||
|
shared: {
|
||||||
|
vue: {
|
||||||
|
singleton: true,
|
||||||
|
requiredVersion: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
build: {
|
||||||
|
target: 'esnext', // 支持顶层await
|
||||||
|
minify: false,
|
||||||
|
cssCodeSplit: false,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
minifyInternalExports: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 组件开发
|
||||||
|
|
||||||
|
主组件 (src/App.vue) 需要遵循以下规则:
|
||||||
|
- 使用 Vue 3 组合式 API
|
||||||
|
- 注册 `action` 事件用于与主应用通信
|
||||||
|
- 避免直接使用 Vue Router 等全局依赖
|
||||||
|
|
||||||
|
示例组件结构:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="plugin-component">
|
||||||
|
<h2>{{ title }}</h2>
|
||||||
|
<div v-if="loading">加载中...</div>
|
||||||
|
<div v-else>
|
||||||
|
<!-- 组件内容 -->
|
||||||
|
<pre>{{ data }}</pre>
|
||||||
|
<button @click="refreshData">刷新</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
// 组件状态
|
||||||
|
const title = ref('插件示例')
|
||||||
|
const loading = ref(true)
|
||||||
|
const data = ref(null)
|
||||||
|
|
||||||
|
// 向主应用发送事件
|
||||||
|
const emit = defineEmits(['action'])
|
||||||
|
|
||||||
|
// 刷新数据
|
||||||
|
async function refreshData() {
|
||||||
|
loading.value = true
|
||||||
|
// API 调用...
|
||||||
|
loading.value = false
|
||||||
|
// 通知主应用
|
||||||
|
emit('action')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
onMounted(() => {
|
||||||
|
refreshData()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建生产版本
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
# 或
|
||||||
|
yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建后的 `dist/remoteEntry.js` 是远程组件的入口文件,需要配置到后端让 MoviePilot 能够访问。
|
||||||
|
|
||||||
|
## 排查常见问题
|
||||||
|
|
||||||
|
### 顶层 await 报错
|
||||||
|
|
||||||
|
确保在 `vite.config.js` 中设置 `build.target` 为 `'esnext'`。
|
||||||
|
|
||||||
|
### 共享依赖加载失败
|
||||||
|
|
||||||
|
确保正确配置共享依赖:
|
||||||
|
```js
|
||||||
|
shared: {
|
||||||
|
vue: {
|
||||||
|
singleton: true,
|
||||||
|
requiredVersion: false // 关闭版本检查
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 组件无法加载
|
||||||
|
|
||||||
|
1. 检查网络请求是否成功
|
||||||
|
2. 确认 JS 文件可以被正确访问
|
||||||
|
3. 查看浏览器控制台是否有详细错误信息
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>MoviePilot 插件组件示例</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "moviepilot-plugin-component",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^3.3.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@originjs/vite-plugin-federation": "^1.3.5",
|
||||||
|
"@vitejs/plugin-vue": "^4.4.0",
|
||||||
|
"vite": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div class="plugin-component pa-4">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>{{ title }}</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-progress-circular v-if="loading" indeterminate color="primary"></v-progress-circular>
|
||||||
|
<div v-else>
|
||||||
|
<v-alert v-if="error" type="error" class="mb-4">{{ error }}</v-alert>
|
||||||
|
<v-simple-table v-if="data && data.stats">
|
||||||
|
<template v-slot:default>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>类型</th>
|
||||||
|
<th>数量</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(value, key) in data.stats" :key="key">
|
||||||
|
<td>{{ key }}</td>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</template>
|
||||||
|
</v-simple-table>
|
||||||
|
<div v-if="data">
|
||||||
|
<div><strong>状态:</strong> {{ data.status }}</div>
|
||||||
|
<div><strong>最后更新:</strong> {{ data.last_updated }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>无数据</div>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="primary" @click="refreshData"> 刷新 </v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
// 组件状态
|
||||||
|
const title = ref('插件数据示例')
|
||||||
|
const loading = ref(true)
|
||||||
|
const data = ref(null)
|
||||||
|
const error = ref(null)
|
||||||
|
|
||||||
|
// 向主应用发送事件
|
||||||
|
const emit = defineEmits(['action'])
|
||||||
|
|
||||||
|
// 获取和刷新数据
|
||||||
|
async function refreshData() {
|
||||||
|
loading.value = true
|
||||||
|
error.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 模拟API调用 - 实际开发中应使用 fetch 调用真实API
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
data.value = {
|
||||||
|
status: 'running',
|
||||||
|
stats: {
|
||||||
|
'电影': Math.floor(Math.random() * 100) + 50,
|
||||||
|
'电视剧': Math.floor(Math.random() * 100) + 30,
|
||||||
|
'动漫': Math.floor(Math.random() * 100) + 20,
|
||||||
|
'纪录片': Math.floor(Math.random() * 100) + 10,
|
||||||
|
'综艺': Math.floor(Math.random() * 100) + 5,
|
||||||
|
},
|
||||||
|
last_updated: new Date().toLocaleString(),
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('获取数据失败:', err)
|
||||||
|
error.value = err.message || '获取数据失败'
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
// 通知主应用组件已更新
|
||||||
|
emit('action')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时加载数据
|
||||||
|
onMounted(() => {
|
||||||
|
refreshData()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.plugin-component {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
app.mount('#app')
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import federation from '@originjs/vite-plugin-federation'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
federation({
|
||||||
|
name: 'remoteApp',
|
||||||
|
filename: 'remoteEntry.js',
|
||||||
|
exposes: {
|
||||||
|
'./PluginComponent': './src/App.vue', // 暴露组件
|
||||||
|
},
|
||||||
|
shared: {
|
||||||
|
vue: {
|
||||||
|
singleton: true,
|
||||||
|
requiredVersion: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
build: {
|
||||||
|
target: 'esnext', // 支持顶层await
|
||||||
|
minify: false,
|
||||||
|
cssCodeSplit: false,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
minifyInternalExports: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
+3
-3
@@ -34,9 +34,8 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
federation({
|
federation({
|
||||||
name: 'host',
|
name: 'host',
|
||||||
remotes: {
|
remotes: {},
|
||||||
// 这里我们会动态添加远程组件,所以不预设remotes
|
exposes: {},
|
||||||
},
|
|
||||||
shared: ['vue', 'vuetify'],
|
shared: ['vue', 'vuetify'],
|
||||||
}),
|
}),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
@@ -162,6 +161,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
target: 'esnext',
|
||||||
minify: 'terser',
|
minify: 'terser',
|
||||||
terserOptions: {
|
terserOptions: {
|
||||||
compress: {
|
compress: {
|
||||||
|
|||||||
Reference in New Issue
Block a user