From 119c81c770d58cca0a810b41ec26a12de1dc68a2 Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Sat, 31 Oct 2026 23:23:32 +0100 Subject: [PATCH] Serve the web interface from source with --dev-plugin With --dev-plugin and no --dev the page kept the production import map, while the development server gave the plugin its own copies of the shared modules. The plugin then failed to load with "Attempt to import duplicate copy of @clusterio/lib". Use the development server's web interface and import map whenever it runs, so the plugin and the web interface share the same modules. --- docs/contributing.md | 1 + packages/controller/src/Controller.ts | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index a206de81..5a7b718a 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -123,6 +123,7 @@ For web development on the controller there are also the following flags: `--dev` - Serve the `web_ui` package from source through Vite's development server with hot module replacement. `--dev-plugin [name]` - Serve the web module for the given plugin from source the same way. +This also serves the `web_ui` package from source, as the plugin has to share its modules with it. These options can be combined and multiple plugins can be actived for dev mode. Keep in mind if you're working on external plugins the `--dev-plugin` option is likely to only work if the plugin is placed inside the `external_plugins` directory and its dependencies are installed with pnpm as part of the clusterio repository workspace. diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index bbd2286d..914f2930 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -420,7 +420,7 @@ export default class Controller { this.app.use(this.devServer.middlewares); } - if (!args.dev) { + if (!this.devServer) { let manifestPath = path.join(import.meta.dirname, "..", "..", "web", "manifest.json"); let manifest = await Controller.loadJsonObject(manifestPath); @@ -527,14 +527,14 @@ export default class Controller { }, plugins: [webUiVite.clusterioDevPlugins(pluginDirs)], }); - if (args.dev) { - this.app.locals.webBundle = { - main: this.devServer.config.plugins.find(p => p.name === "clusterio:app")!.api.entry, - imports: Object.fromEntries(webUiVite.sharedModules.map( - name => [name, webUiVite.devSharedUrl(name)] - )), - }; - } + // Plugins served from source import the shared modules from the development server, the web + // interface has to use the same copies, so it is served from source as well with --dev-plugin. + this.app.locals.webBundle = { + main: this.devServer.config.plugins.find(p => p.name === "clusterio:app")!.api.entry, + imports: Object.fromEntries(webUiVite.sharedModules.map( + name => [name, webUiVite.devSharedUrl(name)] + )), + }; this.app.locals.devServer = this.devServer; }