mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-18 04:04:28 +08:00
fix(plugin): resolve remote entry URLs from document base (#566)
This commit is contained in:
47
src/utils/__tests__/federationUrl.spec.ts
Normal file
47
src/utils/__tests__/federationUrl.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { resolveFederationRemoteUrl } from '@/utils/federationUrl'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
describe('resolveFederationRemoteUrl', () => {
|
||||
const remotePath = '/plugin/file/example/frontend/dist/assets/remoteEntry.js'
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: 'Docker 根路径 HTTP 入口',
|
||||
apiBaseUrl: 'api/v1/',
|
||||
documentBaseUri: 'http://moviepilot.local/',
|
||||
expected: 'http://moviepilot.local/api/v1/plugin/file/example/frontend/dist/assets/remoteEntry.js',
|
||||
},
|
||||
{
|
||||
name: 'Docker 或 local_setup 的无尾斜杠 fallback 入口',
|
||||
apiBaseUrl: 'api/v1/',
|
||||
documentBaseUri: 'http://moviepilot.local/dashboard',
|
||||
expected: 'http://moviepilot.local/api/v1/plugin/file/example/frontend/dist/assets/remoteEntry.js',
|
||||
},
|
||||
{
|
||||
name: 'HTTPS 反向代理入口',
|
||||
apiBaseUrl: 'api/v1/',
|
||||
documentBaseUri: 'https://moviepilot.example.com/dashboard',
|
||||
expected: 'https://moviepilot.example.com/api/v1/plugin/file/example/frontend/dist/assets/remoteEntry.js',
|
||||
},
|
||||
{
|
||||
name: '反向代理子路径入口',
|
||||
apiBaseUrl: 'api/v1/',
|
||||
documentBaseUri: 'https://moviepilot.example.com/mp/',
|
||||
expected: 'https://moviepilot.example.com/mp/api/v1/plugin/file/example/frontend/dist/assets/remoteEntry.js',
|
||||
},
|
||||
{
|
||||
name: '根路径 API 配置',
|
||||
apiBaseUrl: '/api/v1/',
|
||||
documentBaseUri: 'https://moviepilot.example.com/mp/',
|
||||
expected: 'https://moviepilot.example.com/api/v1/plugin/file/example/frontend/dist/assets/remoteEntry.js',
|
||||
},
|
||||
{
|
||||
name: '完整跨域 API 配置',
|
||||
apiBaseUrl: 'https://api.example.com/api/v1',
|
||||
documentBaseUri: 'http://moviepilot.local/dashboard',
|
||||
expected: 'https://api.example.com/api/v1/plugin/file/example/frontend/dist/assets/remoteEntry.js',
|
||||
},
|
||||
])('$name', ({ apiBaseUrl, documentBaseUri, expected }) => {
|
||||
expect(resolveFederationRemoteUrl(remotePath, apiBaseUrl, documentBaseUri)).toBe(expected)
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
import api from '@/api'
|
||||
import { resolveFederationRemoteUrl } from '@/utils/federationUrl'
|
||||
import {
|
||||
__federation_method_setRemote,
|
||||
__federation_method_getRemote,
|
||||
@@ -144,18 +145,7 @@ async function fetchRemoteModules(): Promise<RemoteModule[]> {
|
||||
* @param modules 远程模块列表
|
||||
*/
|
||||
export function injectRemoteModule(module: RemoteModule): void {
|
||||
// 与 API 请求一致:使用 origin + pathname 作为前缀,子路径代理时 pathname 含 /mp 等
|
||||
const baseUrl = new URL(window.location.href)
|
||||
const pathBase = baseUrl.pathname.replace(/\/$/, '') || ''
|
||||
let apiBase = import.meta.env.VITE_API_BASE_URL
|
||||
if (apiBase.startsWith('/')) {
|
||||
apiBase = apiBase.slice(1)
|
||||
}
|
||||
if (apiBase.endsWith('/')) {
|
||||
apiBase = apiBase.slice(0, -1)
|
||||
}
|
||||
const pathWithoutLeadingSlash = module.url.startsWith('/') ? module.url.slice(1) : module.url
|
||||
const remoteEntryUrl = `${baseUrl.origin}${pathBase}/${apiBase}/${pathWithoutLeadingSlash}`
|
||||
const remoteEntryUrl = resolveFederationRemoteUrl(module.url, import.meta.env.VITE_API_BASE_URL, document.baseURI)
|
||||
__federation_method_setRemote(module.id, {
|
||||
url: () => Promise.resolve(remoteEntryUrl),
|
||||
format: 'esm',
|
||||
|
||||
11
src/utils/federationUrl.ts
Normal file
11
src/utils/federationUrl.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 按页面文档基址解析插件联邦入口,使其与相对 API 请求遵循相同的部署路径规则。
|
||||
* 相对 API 基址保留反向代理子路径,根路径或完整 URL 配置则按其显式语义解析。
|
||||
*/
|
||||
export function resolveFederationRemoteUrl(remotePath: string, apiBaseUrl: string, documentBaseUri: string): string {
|
||||
const normalizedApiBase = apiBaseUrl.endsWith('/') ? apiBaseUrl : `${apiBaseUrl}/`
|
||||
const apiUrl = new URL(normalizedApiBase, documentBaseUri)
|
||||
const normalizedRemotePath = remotePath.replace(/^\/+/, '')
|
||||
|
||||
return new URL(normalizedRemotePath, apiUrl).href
|
||||
}
|
||||
Reference in New Issue
Block a user