Archived
fix(plugins): make manifests deployment relative
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { loadExternalPlugins } from "./external";
|
||||
import { loadExternalPlugins, resolvePluginModuleUrl } from "./external";
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal("document", { baseURI: "https://pi.example.test/" });
|
||||
@@ -18,4 +18,35 @@ describe("external plugin manifests", () => {
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith("https://pi.example.test/pi-web-plugins/manifest.json", { cache: "no-store" });
|
||||
});
|
||||
|
||||
it("loads manifest-relative modules from a nested deployment", async () => {
|
||||
const manifestUrl = "https://pi.example.test/test/ai/pi-web-plugins/manifest.json";
|
||||
const fetchMock = vi.fn(() => Promise.resolve(new Response(JSON.stringify({
|
||||
plugins: [{ id: "info", module: "./info/pi-web-plugin.js?v=1", machineSpecific: false }],
|
||||
}))));
|
||||
const moduleLoader = vi.fn(() => Promise.resolve({
|
||||
default: { apiVersion: 1, name: "Info", activate: () => ({ contributions: {} }) },
|
||||
}));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const registrations = await loadExternalPlugins(manifestUrl, { moduleLoader });
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(manifestUrl, { cache: "no-store" });
|
||||
expect(moduleLoader).toHaveBeenCalledWith("https://pi.example.test/test/ai/pi-web-plugins/info/pi-web-plugin.js?v=1");
|
||||
expect(registrations).toMatchObject([{ id: "info", machineSpecific: false, plugin: { apiVersion: 1, name: "Info" } }]);
|
||||
});
|
||||
|
||||
it("treats root-style modules from existing manifests as application-root paths", () => {
|
||||
const rootManifestUrl = "https://pi.example.test/pi-web-plugins/manifest.json";
|
||||
const nestedManifestUrl = "https://pi.example.test/test/ai/pi-web-plugins/manifest.json";
|
||||
|
||||
expect(resolvePluginModuleUrl("/pi-web-plugins/info/pi-web-plugin.js?v=1", rootManifestUrl, {
|
||||
viteBaseUrl: "/",
|
||||
documentBaseUrl: "https://pi.example.test/",
|
||||
})).toBe("https://pi.example.test/pi-web-plugins/info/pi-web-plugin.js?v=1");
|
||||
expect(resolvePluginModuleUrl("/pi-web-plugins/info/pi-web-plugin.js?v=1", nestedManifestUrl, {
|
||||
viteBaseUrl: "./",
|
||||
documentBaseUrl: "https://pi.example.test/test/ai/",
|
||||
})).toBe("https://pi.example.test/test/ai/pi-web-plugins/info/pi-web-plugin.js?v=1");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { machineScopedPluginId } from "../../../shared/machinePluginIds";
|
||||
import { resolveAppUrl } from "../appUrl";
|
||||
import { resolveAppUrl, type AppUrlContext } from "../appUrl";
|
||||
import type { PiWebPlugin, PiWebPluginRegistration } from "./types";
|
||||
|
||||
export interface PluginManifestEntry {
|
||||
@@ -15,6 +15,7 @@ interface PluginManifest {
|
||||
export interface LoadExternalPluginsOptions {
|
||||
machineId?: string;
|
||||
shouldLoadPlugin?: (entry: PluginManifestEntry) => boolean;
|
||||
moduleLoader?: (moduleUrl: string) => Promise<unknown>;
|
||||
}
|
||||
|
||||
export async function loadExternalPlugins(manifestUrl = "pi-web-plugins/manifest.json", options: LoadExternalPluginsOptions = {}): Promise<PiWebPluginRegistration[]> {
|
||||
@@ -26,8 +27,8 @@ export async function loadExternalPlugins(manifestUrl = "pi-web-plugins/manifest
|
||||
for (const entry of manifest.plugins) {
|
||||
if (options.shouldLoadPlugin?.(entry) === false) continue;
|
||||
try {
|
||||
const moduleUrl = new URL(entry.module, resolvedManifestUrl).toString();
|
||||
const module: unknown = await import(/* @vite-ignore */ moduleUrl);
|
||||
const moduleUrl = resolvePluginModuleUrl(entry.module, resolvedManifestUrl);
|
||||
const module = await (options.moduleLoader ?? importPluginModule)(moduleUrl);
|
||||
const plugin = parsePluginModule(module, moduleUrl);
|
||||
registrations.push({
|
||||
id: options.machineId === undefined ? entry.id : machineScopedPluginId(options.machineId, entry.id),
|
||||
@@ -42,6 +43,15 @@ export async function loadExternalPlugins(manifestUrl = "pi-web-plugins/manifest
|
||||
return registrations;
|
||||
}
|
||||
|
||||
export function resolvePluginModuleUrl(moduleReference: string, manifestUrl: string, appUrlContext?: AppUrlContext): string {
|
||||
if (!moduleReference.startsWith("/")) return new URL(moduleReference, manifestUrl).toString();
|
||||
return appUrlContext === undefined ? resolveAppUrl(moduleReference) : resolveAppUrl(moduleReference, appUrlContext);
|
||||
}
|
||||
|
||||
async function importPluginModule(moduleUrl: string): Promise<unknown> {
|
||||
return import(/* @vite-ignore */ moduleUrl);
|
||||
}
|
||||
|
||||
async function fetchPluginManifest(manifestUrl: string): Promise<PluginManifest | undefined> {
|
||||
const response = await fetch(manifestUrl, { cache: "no-store" });
|
||||
if (response.status === 404) return undefined;
|
||||
|
||||
Reference in New Issue
Block a user