diff --git a/vue-widgets/vite.config.mts b/vue-widgets/vite.config.mts index 681fd72c..63cb3c32 100644 --- a/vue-widgets/vite.config.mts +++ b/vue-widgets/vite.config.mts @@ -1,12 +1,86 @@ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js' -import { resolve } from 'path' +import { dirname, resolve } from 'path' + +// Specifiers that must stay external. The bundle is emitted to +// web/comfyui/vue-widgets/, and ComfyUI serves that directory's parent +// (web/comfyui) at /extensions/ComfyUI-Lora-Manager/, so one "../" from the +// bundle reaches web/comfyui modules and three "../../.." reach ComfyUI's +// own runtime scripts at runtime. +// +// scripts/app.js and scripts/api.js are intentionally NOT listed here: they +// are externalized by the keep-runtime-modules-external plugin below, which +// also rewrites the shallower "../../scripts/*" specifiers used by modules +// inlined from web/comfyui/ so every binding dedupes into a single import. +const EXTERNAL_SPECIFIERS = [ + '../loras_widget.js', + '../autocomplete.js', + '../preview_tooltip.js' +] export default defineConfig({ plugins: [ vue(), - cssInjectedByJsPlugin() // Inject CSS into JS for ComfyUI compatibility + cssInjectedByJsPlugin(), // Inject CSS into JS for ComfyUI compatibility + // Keep shared runtime modules external instead of inlining them into + // the bundle. This guards against the inlined-shim bug class (the + // removed active-filters chip ended up writing settings to a dead + // in-memory store this way): + // + // 1. Modules under web/comfyui/ import the repo-root scripts/app.js + // TEST SHIM as "../../scripts/app.js" — a depth that resolves to + // the shim on the build filesystem but 404s at the bundle's + // runtime location. Rewrite to the canonical bundle-depth + // specifier so every app/api binding in the bundle is the REAL + // ComfyUI module. + // 2. web/comfyui/settings.js must never be duplicated into the + // bundle: it registers settings via a module-level side effect + // and owns module state. Externalize it to "../settings.js" so + // the bundle binds to the SAME vanilla module instance that the + // ComfyUI extension loader already loaded. + { + name: 'lora-manager:keep-runtime-modules-external', + enforce: 'pre', + resolveId(source, importer) { + const scriptsMatch = source.match(/^(\.\.\/)+scripts\/(app|api)\.js$/) + if (scriptsMatch) { + return { id: `../../../scripts/${scriptsMatch[2]}.js`, external: true } + } + if ( + importer && + /[\\/]web[\\/]comfyui[\\/]settings\.js$/.test( + resolve(dirname(importer), source) + ) + ) { + return { id: '../settings.js', external: true } + } + return null + }, + }, + // Warning twin of the rewrite above: importing web/comfyui/* from + // widget source inlines that module into the bundle, duplicating any + // module-level side effects/state it owns. The settings.js and + // scripts/app|api.js imports are made safe by the plugin above, but + // review any further such import deliberately. + { + name: 'lora-manager:warn-web-comfyui-imports', + enforce: 'pre', + resolveId(source, importer) { + if ( + importer && + /[\\/]vue-widgets[\\/]src[\\/]/.test(importer) && + /[\\/]web[\\/]comfyui[\\/]/.test(source) + ) { + this.warn( + `[vue-widgets] Inlining web/comfyui module "${source}" into the bundle. ` + + 'settings.js and scripts/app|api.js imports are externalized by this config, ' + + 'but the inlined copy still duplicates module-level side effects — verify that is intended.' + ) + } + return null + }, + }, ], resolve: { alias: { @@ -20,13 +94,7 @@ export default defineConfig({ fileName: 'lora-manager-widgets' }, rollupOptions: { - external: [ - '../../../scripts/app.js', - '../../../scripts/api.js', - '../loras_widget.js', - '../autocomplete.js', - '../preview_tooltip.js' - ], + external: EXTERNAL_SPECIFIERS, output: { dir: '../web/comfyui/vue-widgets', entryFileNames: 'lora-manager-widgets.js', @@ -41,3 +109,4 @@ export default defineConfig({ 'process.env.NODE_ENV': JSON.stringify('production') } }) +