Why Your Vue JS Chrome Extension Is Not Detecting the Local Server App
The Vue DevTools Chrome extension requires a development build of Vue that exposes window.__VUE_DEVTOOLS_GLOBAL_HOOK__, which is stripped from production builds and blocked in restricted environments.
When developing Vue applications locally, you expect the Vue DevTools Chrome extension to automatically detect your app and display component trees. However, if your Vue JS Chrome extension is not detecting the application running on your local server, the issue typically stems from how Vue injects the global devtools hook during runtime. This handshake mechanism, implemented in the Vue core source code, serves as the bridge between your app and the browser extension.
How Vue DevTools Detection Works
The detection process relies on a global hook injected into the page that the Chrome extension polls for. When present, the extension establishes a connection to track component trees, state changes, and performance events.
Renderer Bootstrap in runtime-core
When a renderer is created, Vue checks environment flags __DEV__ or __FEATURE_PROD_DEVTOOLS__. If either is true, it calls setDevtoolsHook with the global hook value found on window (target.__VUE_DEVTOOLS_GLOBAL_HOOK__).
// packages/runtime-core/src/renderer.ts
// … line 551‑555
const target = getGlobalThis()
target.__VUE__ = true
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__, target)
}
https://github.com/vuejs/core/blob/main/packages/runtime-core/src/renderer.ts#L551-L555
Hook Registration and Event Buffering
The setDevtoolsHook function in packages/runtime-core/src/devtools.ts stores the incoming hook in a module-level variable and creates a replay buffer for events that occur before the extension injects its hook.
// packages/runtime-core/src/devtools.ts
export function setDevtoolsHook(hook: DevtoolsHook, target: any): void {
devtools = hook
if (devtools) {
devtools.enabled = true
buffer.forEach(({ event, args }) => devtools.emit(event, ...args))
buffer = []
} else { /* … handle late injection … */ }
}
https://github.com/vuejs/core/blob/main/packages/runtime-core/src/devtools.ts#L52-L73
Common Reasons Your Vue JS Chrome Extension Is Not Detecting the App
Several environmental and build factors can prevent the global hook from being established, breaking the connection between your local server and the Chrome extension.
Production Build Restrictions
When you use vue.global.prod.js or run vite build --mode production, the compile-time flag __DEV__ is set to false and __FEATURE_PROD_DEVTOOLS__ is disabled. Consequently, the renderer bootstrap code that calls setDevtoolsHook is tree-shaken out of the bundle. Without window.__VUE_DEVTOOLS_GLOBAL_HOOK__, the extension cannot detect the application.
Server-Side Rendering and Non-Browser Environments
In SSR contexts or test environments using jsdom, Vue explicitly guards against injecting the devtools hook. The framework checks typeof window !== 'undefined' && window.HTMLElement && !window.navigator?.userAgent?.includes('jsdom') before establishing the hook. If this guard fails—as it does in Node.js or simulated DOM environments—the Chrome extension remains unaware of the Vue instance.
Content Security Policy Blocks
The Vue DevTools extension injects a script tag into the page to establish communication. A restrictive Content Security Policy header such as script-src 'self' blocks this inline injection, preventing the extension from registering its hook and leaving window.__VUE_DEVTOOLS_GLOBAL_HOOK__ undefined.
Runtime-Only Build Limitations
If you import from @vue/runtime-core directly instead of the full vue package or vue/runtime-dom, you bypass the DOM-specific devtools initialization. The runtime-core package lacks the browser-targeted hook registration logic found in the full build, so the extension cannot attach to your application.
How to Enable Vue DevTools on Your Local Server
Follow these steps to ensure your local development environment exposes the necessary hook for the Chrome extension.
-
Serve a development build. Import Vue from the ESM browser development bundle that includes
__DEV__flags.<script type="module"> import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js' createApp({ /* ... */ }).mount('#app') </script> -
Verify Vite or webpack mode. Ensure your bundler runs in development mode.
# Vite development server (correct) npm run dev # Production build (devtools disabled) npm run build -
Check the global hook. Open your browser console and verify the hook exists.
console.log('Vue DevTools hook →', window.__VUE_DEVTOOLS_GLOBAL_HOOK__)If this returns
undefined, you are using a production build or a restricted environment. -
Adjust CSP headers. If your local server uses strict CSP headers, temporarily relax them to allow the extension’s script injection.
Content-Security-Policy: script-src 'self' 'unsafe-eval' chrome-extension://* -
Use the full Vue package. Ensure you are importing from
vuerather than@vue/runtime-coreto include DOM-specific devtools logic.
Code Examples for Debugging Detection Issues
Minimal HTML App That Works with DevTools
This example imports the development ESM build and logs the hook status.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue DevTools Demo</title>
</head>
<body>
<div id="app">{{ message }}</div>
<script type="module">
// Import the dev (non‑minified) build
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
const App = {
data() {
return { message: 'Hello from Vue DevTools!' }
}
}
createApp(App).mount('#app')
// Quick sanity check
console.log('DevTools hook →', window.__VUE_DEVTOOLS_GLOBAL_HOOK__)
</script>
</body>
</html>
Vite Configuration for Development Mode
Force Vite to resolve the ESM bundler development build.
// vite.config.js
export default {
// No explicit mode → Vite dev server runs in development mode
plugins: [],
resolve: {
alias: {
// Force Vite to use the ESM dev build during dev
vue: 'vue/dist/vue.esm-bundler.js'
}
}
}
Run the development server:
npm run dev # Dev server → DevTools can detect the app
Programmatic Hook Detection
Use this utility to warn when the hook is missing.
function ensureDevtoolsHook() {
if (!window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
console.warn(
'Vue DevTools hook not detected. You may be using a production build or a restricted environment.'
)
}
}
ensureDevtoolsHook()
Summary
- The Vue DevTools Chrome extension detects applications by polling for
window.__VUE_DEVTOOLS_GLOBAL_HOOK__, which Vue injects during renderer initialization in development builds. - In
packages/runtime-core/src/renderer.ts, Vue checks__DEV__or__FEATURE_PROD_DEVTOOLS__before callingsetDevtoolsHookto establish the global hook. - Production builds (
vite build,vue.global.prod.js) disable this hook injection, preventing detection. - SSR, jsdom environments, strict CSP headers, and the runtime-only build (
@vue/runtime-core) also block hook registration. - To fix detection, serve the development ESM build, verify
window.__VUE_DEVTOOLS_GLOBAL_HOOK__exists in the console, and ensure your bundler runs in development mode.
Frequently Asked Questions
Why does the Vue DevTools extension work on some sites but not my localhost?
Production websites often deploy minified production builds where __DEV__ is false and __FEATURE_PROD_DEVTOOLS__ is disabled, stripping the hook injection code from packages/runtime-core/src/renderer.ts. Your localhost may also be serving a production build or using a runtime-only package that lacks the DOM-specific devtools initialization required for the Chrome extension to connect.
How do I check if my Vue app is exposing the devtools hook?
Open your browser’s developer console on the page running your Vue app and execute console.log(window.__VUE_DEVTOOLS_GLOBAL_HOOK__). If it returns an object with methods like emit and on, the hook is present and the extension should detect your app. If it returns undefined, you are likely using a production build or a restricted environment that prevents hook injection according to the Vue core source code.
Can I use Vue DevTools with a production build on my local server?
By default, no. Production builds disable the devtools hook injection in packages/runtime-core/src/renderer.ts because both __DEV__ and __FEATURE_PROD_DEVTOOLS__ are false. However, you can enable detection in production by building Vue from source with the __FEATURE_PROD_DEVTOOLS__ flag enabled, though this is not recommended for performance and security reasons.
Why does the extension fail when I use @vue/runtime-core directly?
The @vue/runtime-core package contains the core reactivity and component logic but lacks the browser-specific devtools integration found in vue/runtime-dom. The hook registration in packages/runtime-core/src/renderer.ts relies on a global target (window) that is properly set up in the full browser build. Importing from vue or vue/dist/vue.esm-browser.js ensures you receive the DOM-aware build that initializes the devtools hook correctly.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →