mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 15:04:52 +09:00
Load plugins installed from npm by package name
Plugins installed from npm are listed by package name, but the plugin loader joined that name onto the main and entrypoint paths and imported the result as a file, which resolves relative to the working directory. Every npm installed plugin then failed to load. Resolve these paths from the directory of the plugin's package.json instead.
This commit is contained in:
1 parent
b411c5bef8
commit
6e36c02ade
2 files changed
+46
-3
No files matched your search
@@ -51,8 +51,9 @@ export async function loadPluginInfos(pluginList: Map<string, string>) {
|
||||
|
||||
try {
|
||||
pluginPackage = (await import(pathToFileURL(packagePath).href, { with: { type: "json" }})).default;
|
||||
// pluginPath is a package name for plugins installed from npm, so resolve from the package itself
|
||||
pluginInfo = (await import(
|
||||
pathToFileURL(path.posix.join(pluginPath, pluginPackage.main ?? "index.js")).href
|
||||
pathToFileURL(path.join(path.dirname(packagePath), pluginPackage.main ?? "index.js")).href
|
||||
)).plugin;
|
||||
} catch (err: any) {
|
||||
if (err.code === "InstallationError") {
|
||||
@@ -106,7 +107,7 @@ export async function loadPlugin<
|
||||
return;
|
||||
}
|
||||
|
||||
const module = await import(pathToFileURL(path.posix.join(pluginInfo.requirePath, requirePath)).href);
|
||||
const module = await import(pathToFileURL(path.join(path.dirname(pluginInfo.packagePath), requirePath)).href);
|
||||
const pluginContext: libPlugin.PluginLoadContext<Context> = {
|
||||
...context,
|
||||
plugin: pluginInfo,
|
||||
|
||||
@@ -66,6 +66,43 @@ describe("lib/plugin_loader", function() {
|
||||
{ message: `PluginError: ${brokenMessage}` }
|
||||
);
|
||||
});
|
||||
describe("plugin installed from npm", function() {
|
||||
// Plugins from npm are listed by package name, so they must be resolved like a dependency
|
||||
const packageDir = path.resolve("node_modules", "@clusterio-test", "npm_plugin");
|
||||
before(async function() {
|
||||
await fs.mkdir(path.join(packageDir, "dist"), { recursive: true });
|
||||
await fs.writeFile(path.join(packageDir, "package.json"), JSON.stringify({
|
||||
name: "@clusterio-test/npm_plugin", version: "0.0.2", main: "dist/index.js", type: "module",
|
||||
}));
|
||||
await fs.writeFile(
|
||||
path.join(packageDir, "dist", "index.js"),
|
||||
'export const plugin = { name: "npm_plugin", controllerEntrypoint: "dist/controller.js" };',
|
||||
);
|
||||
await fs.writeFile(
|
||||
path.join(packageDir, "dist", "controller.js"),
|
||||
"export default async function(context) { context.controller.loadedNpmPlugin = true; }",
|
||||
);
|
||||
});
|
||||
after(async function() {
|
||||
await fs.rm(path.dirname(packageDir), { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("should load the plugin and its entrypoints", async function() {
|
||||
const [pluginInfo] = await lib.loadPluginInfos(
|
||||
new Map([["npm_plugin", "@clusterio-test/npm_plugin"]])
|
||||
);
|
||||
assert.equal(pluginInfo.name, "npm_plugin");
|
||||
assert.equal(pluginInfo.npmPackage, "@clusterio-test/npm_plugin");
|
||||
assert.equal(pluginInfo.packagePath, path.join(packageDir, "package.json"));
|
||||
|
||||
const controller = new mock.MockController();
|
||||
await lib.loadPlugin(
|
||||
pluginInfo, "controller", { controller, metrics: {}, logger: new mock.MockLogger() },
|
||||
"ControllerPlugin", BaseControllerPlugin,
|
||||
);
|
||||
assert.equal(controller.loadedNpmPlugin, true);
|
||||
});
|
||||
});
|
||||
it("should reject on invalid plugin", async function() {
|
||||
await assert.rejects(
|
||||
lib.loadPluginInfos(new Map([["invalid", path.resolve(invalidPlugin)]])),
|
||||
@@ -122,7 +159,12 @@ describe("lib/plugin_loader", function() {
|
||||
});
|
||||
|
||||
function info(requirePath, entrypoint = "controller.js") {
|
||||
return { name: "test", requirePath, controllerEntrypoint: entrypoint };
|
||||
return {
|
||||
name: "test",
|
||||
requirePath,
|
||||
packagePath: path.join(requirePath, "package.json"),
|
||||
controllerEntrypoint: entrypoint,
|
||||
};
|
||||
}
|
||||
|
||||
it("should do nothing when the entrypoint is not set", async function() {
|
||||
|
||||
Reference in new issue
Block a user