From cd8fe9782a9e992527f7adee81f46d8154b8d586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=83=9C?= <2318857637@qq.com> Date: Tue, 28 Jul 2026 11:31:25 +0800 Subject: [PATCH] fix: support multiple appendTo entries --- docs/guide/vite-plugin.md | 13 +++++- packages/vite/__tests__/append-to.test.ts | 48 +++++++++++++++++++++++ packages/vite/src/vite.ts | 39 +++++++++++++----- 3 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 packages/vite/__tests__/append-to.test.ts diff --git a/docs/guide/vite-plugin.md b/docs/guide/vite-plugin.md index 6626b4730..979870efd 100644 --- a/docs/guide/vite-plugin.md +++ b/docs/guide/vite-plugin.md @@ -46,13 +46,13 @@ export default defineConfig({ ```ts interface VitePluginVueDevToolsOptions { /** - * append an import to the module id ending with `appendTo` instead of adding a script into body + * append an import to the module id matching `appendTo` instead of adding a script into body * useful for projects that do not use html file as an entry * * WARNING: only set this if you know exactly what it does. * @default '' */ - appendTo?: string | RegExp + appendTo?: string | RegExp | (string | RegExp)[] /** * Enable vue component inspector @@ -69,3 +69,12 @@ interface VitePluginVueDevToolsOptions { launchEditor?: 'appcode' | 'atom' | 'atom-beta' | 'brackets' | 'clion' | 'code' | 'code-insiders' | 'codium' | 'emacs' | 'idea' | 'notepad++' | 'pycharm' | 'phpstorm' | 'rubymine' | 'sublime' | 'vim' | 'visualstudio' | 'webstorm' | 'rider' | string } ``` + +```ts [vite.config.ts] +vueDevTools({ + appendTo: [ + 'resources/js/app.js', + 'resources/js/admin.js', + ], +}) +``` diff --git a/packages/vite/__tests__/append-to.test.ts b/packages/vite/__tests__/append-to.test.ts new file mode 100644 index 000000000..37b1214d7 --- /dev/null +++ b/packages/vite/__tests__/append-to.test.ts @@ -0,0 +1,48 @@ +import type { Plugin } from 'vite' +import { describe, expect, it } from 'vitest' +import VitePluginVueDevTools from '../src/vite' + +function getPlugin(options: Parameters[0]) { + const plugins = VitePluginVueDevTools(options) as Plugin[] + const plugin = plugins.find(plugin => plugin && typeof plugin === 'object' && plugin.name === 'vite-plugin-vue-devtools') + + if (!plugin || typeof plugin.transform !== 'function') + throw new Error('Expected vite-plugin-vue-devtools transform hook') + + return plugin +} + +function transform(plugin: Plugin, id: string) { + const code = 'createApp(App).mount("#app")' + const result = plugin.transform!.call(plugin, code, id, {}) + + return typeof result === 'string' ? result : code +} + +describe('appendTo', () => { + it('matches any configured entry file', () => { + const plugin = getPlugin({ + appendTo: [ + 'resources/js/app.js', + 'resources/js/admin.js', + ], + }) + + expect(transform(plugin, '/project/resources/js/app.js')).toContain('virtual:vue-devtools-path:overlay.js') + expect(transform(plugin, '/project/resources/js/app.js')).toContain('virtual:vue-inspector-path:load.js') + expect(transform(plugin, '/project/resources/js/admin.js')).toContain('virtual:vue-devtools-path:overlay.js') + expect(transform(plugin, '/project/resources/js/other.js')).toBe('createApp(App).mount("#app")') + }) + + it('keeps inspector injection disabled when component inspector is off', () => { + const plugin = getPlugin({ + appendTo: ['resources/js/app.js'], + componentInspector: false, + }) + + const result = transform(plugin, '/project/resources/js/app.js') + + expect(result).toContain('virtual:vue-devtools-path:overlay.js') + expect(result).not.toContain('virtual:vue-inspector-path:load.js') + }) +}) diff --git a/packages/vite/src/vite.ts b/packages/vite/src/vite.ts index 3153094a9..9aa3e85e6 100644 --- a/packages/vite/src/vite.ts +++ b/packages/vite/src/vite.ts @@ -30,15 +30,17 @@ function normalizeComboKeyPrint(toggleComboKey: string) { const devtoolsNextResourceSymbol = '?__vue-devtools-next-resource' +type AppendToTarget = string | RegExp + export interface VitePluginVueDevToolsOptions { /** - * append an import to the module id ending with `appendTo` instead of adding a script into body + * append an import to the module id matching `appendTo` instead of adding a script into body * useful for projects that do not use html file as an entry * * WARNING: only set this if you know exactly what it does. * @default '' */ - appendTo?: string | RegExp + appendTo?: AppendToTarget | AppendToTarget[] /** * Enable vue component inspector @@ -80,6 +82,22 @@ function mergeOptions(options: VitePluginVueDevToolsOptions): VitePluginVueDevTo return Object.assign({}, defaultOptions, options) } +function normalizeAppendTo(appendTo: VitePluginVueDevToolsOptions['appendTo']) { + if (!appendTo) + return [] + + return (Array.isArray(appendTo) ? appendTo : [appendTo]).filter(Boolean) +} + +function matchesAppendTo(filename: string, appendTo: VitePluginVueDevToolsOptions['appendTo']) { + return normalizeAppendTo(appendTo).some((target) => { + if (typeof target === 'string') + return filename.endsWith(target) + + return target.test(filename) + }) +} + export default function VitePluginVueDevTools(options?: VitePluginVueDevToolsOptions): PluginOption { const vueDevtoolsPath = getVueDevtoolsPath() const inspect = Inspect({ @@ -87,6 +105,7 @@ export default function VitePluginVueDevTools(options?: VitePluginVueDevToolsOpt }) const pluginOptions = mergeOptions(options ?? {}) + const hasAppendToTarget = normalizeAppendTo(pluginOptions.appendTo).length > 0 let config: ResolvedConfig @@ -174,17 +193,19 @@ export default function VitePluginVueDevTools(options?: VitePluginVueDevToolsOpt const { appendTo } = pluginOptions const [filename] = id.split('?', 2) - if (appendTo - && ( - (typeof appendTo === 'string' && filename.endsWith(appendTo)) - || (appendTo instanceof RegExp && appendTo.test(filename)))) { - code = `import 'virtual:vue-devtools-path:overlay.js';\n${code}` + if (matchesAppendTo(filename, appendTo)) { + const imports = [ + `import 'virtual:vue-devtools-path:overlay.js';`, + pluginOptions.componentInspector && `import 'virtual:vue-inspector-path:load.js';`, + ].filter(Boolean).join('\n') + + code = `${imports}\n${code}` } return code }, transformIndexHtml(html) { - if (pluginOptions.appendTo) + if (hasAppendToTarget) return return { @@ -224,7 +245,7 @@ export default function VitePluginVueDevTools(options?: VitePluginVueDevToolsOpt ...typeof pluginOptions.componentInspector === 'boolean' ? {} : pluginOptions.componentInspector, - appendTo: pluginOptions.appendTo || 'manually', + appendTo: hasAppendToTarget ? 'manually' : pluginOptions.appendTo || 'manually', }) as PluginOption, plugin, ].filter(Boolean)