From 0f8c4e8838700404a8b90898152c5f3d61b8ddee Mon Sep 17 00:00:00 2001 From: opowell Date: Wed, 19 Aug 2020 17:34:24 +0200 Subject: [PATCH 1/7] docs: fix typo in README.md (#1242) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 67aba0e80..07ca6e27b 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This is only necessary when you want to build the extension yourself from source 4. Open the Chrome extension page (currently under Menu > More Tools > Extensions) 5. Check "developer mode" on the top-right corner 6. Click the "load unpacked" button on the left, and choose the folder: `vue-devtools/packages/shell-chrome/` -7. Alternatilvely to step 3, you can also use `yarn dev:chrome` to build & watch the unpacked extension +7. Alternatively to step 3, you can also use `yarn dev:chrome` to build & watch the unpacked extension ### Development From 6d8fee4d058716fe72825c9ae22cf831ef8f5172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo=20Here=C3=B1=C3=BA?= Date: Wed, 19 Aug 2020 12:36:22 -0300 Subject: [PATCH 2/7] docs: fixed typo and enhance readability in README (#1162) * Fixed typo on line 38 * semantic proposal on line 27 * plus minor formatting proposals * docs: improve phrasing Co-authored-by: Ben Hong --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 07ca6e27b..34f949660 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ To enable this feature, follow [this guide](./docs/open-in-editor.md). ### Manual Installation -This is only necessary when you want to build the extension yourself from source to get not-yet-released features. +This is only necessary when you want to build the extension with the source repo to get not-yet-released features. **Make sure you are using Node 6+ and NPM 3+** @@ -32,7 +32,7 @@ This is only necessary when you want to build the extension yourself from source 2. `cd vue-devtools` the newly created folder 2. run `yarn install` 3. then run `yarn run build` -4. Open the Chrome extension page (currently under Menu > More Tools > Extensions) +4. Open the Chrome extension page (currently under `Menu` > `More Tools` > `Extensions`) 5. Check "developer mode" on the top-right corner 6. Click the "load unpacked" button on the left, and choose the folder: `vue-devtools/packages/shell-chrome/` 7. Alternatively to step 3, you can also use `yarn dev:chrome` to build & watch the unpacked extension From 900f2be6f256f6ce4ffce9a8f3ed62fa17099c7a Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Fri, 29 Jan 2021 12:02:48 +0100 Subject: [PATCH 3/7] fix(security): toast vulnerable to XSS attack, closes #1353 --- .../shell-chrome/src/devtools-background.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/shell-chrome/src/devtools-background.js b/packages/shell-chrome/src/devtools-background.js index 17b87ec98..4437dadc4 100644 --- a/packages/shell-chrome/src/devtools-background.js +++ b/packages/shell-chrome/src/devtools-background.js @@ -46,7 +46,7 @@ chrome.runtime.onMessage.addListener(request => { if (request === 'vue-panel-load') { onPanelLoad() } else if (request.vueToast) { - toast(request.vueToast.message, request.vueToast.type) + toast(request.vueToast) } else if (request.vueContextMenu) { onContextMenu(request.vueContextMenu) } @@ -65,10 +65,10 @@ function onContextMenu ({ id }) { if (typeof res !== 'undefined' && res) { panelAction(() => { chrome.runtime.sendMessage('vue-get-context-menu-target') - }, 'Open Vue devtools to see component details') + }, 'open-devtools') } else { pendingAction = null - toast('No Vue component was found', 'warn') + toast('component-not-found') } }) } @@ -113,7 +113,16 @@ function onPanelHidden () { // Toasts -function toast (message, type = 'normal') { +const toastMessages = { + 'open-devtools': { message: 'Open Vue devtools to see component details', type: 'normal' }, + 'component-not-found': { message: 'No Vue component was found', type: 'warn' } +} + +function toast (id) { + if (!Object.keys().includes(id)) return + + const { message, type } = toastMessages[id] + const src = `(function() { __VUE_DEVTOOLS_TOAST__(\`${message}\`, '${type}'); })()` From 7075a1273b720417379e36a0726546b90b38c825 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Fri, 29 Jan 2021 12:14:43 +0100 Subject: [PATCH 4/7] chore: v5.3.4 --- package.json | 2 +- packages/shell-chrome/manifest.json | 4 ++-- packages/shell-electron/package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 220acb779..37b45e619 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-devtools", - "version": "5.3.3", + "version": "5.3.4", "description": "devtools for Vue.js!", "private": true, "workspaces": [ diff --git a/packages/shell-chrome/manifest.json b/packages/shell-chrome/manifest.json index 905bee0c1..3237aaa5e 100644 --- a/packages/shell-chrome/manifest.json +++ b/packages/shell-chrome/manifest.json @@ -1,7 +1,7 @@ { "name": "Vue.js devtools", - "version": "5.3.3", - "version_name": "5.3.3", + "version": "5.3.4", + "version_name": "5.3.4", "description": "Chrome and Firefox DevTools extension for debugging Vue.js applications.", "manifest_version": 2, "icons": { diff --git a/packages/shell-electron/package.json b/packages/shell-electron/package.json index 74b463f9a..8dc74457a 100644 --- a/packages/shell-electron/package.json +++ b/packages/shell-electron/package.json @@ -1,6 +1,6 @@ { "name": "@vue/devtools", - "version": "5.3.3", + "version": "5.3.4", "description": "StandAlone vue-devtools", "repository": { "url": "https://github.com/vuejs/vue-devtools.git", From 38684af4e9039ff615a4edbc1d3fc75a074c8766 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Sun, 4 Feb 2024 15:31:44 +0100 Subject: [PATCH 5/7] refactor: migrate to manifest v3 based on #2136 --- packages/shell-chrome/manifest.json | 45 ++++++---- packages/shell-chrome/src/detector-exec.js | 85 ++++++++++++++++++ packages/shell-chrome/src/detector.js | 77 ++-------------- packages/shell-chrome/src/hook-exec.js | 3 + packages/shell-chrome/src/hook.js | 22 ++--- .../src/{background.js => service-worker.js} | 89 ++++++++++--------- packages/shell-chrome/webpack.config.js | 6 +- 7 files changed, 181 insertions(+), 146 deletions(-) create mode 100644 packages/shell-chrome/src/detector-exec.js create mode 100644 packages/shell-chrome/src/hook-exec.js rename packages/shell-chrome/src/{background.js => service-worker.js} (51%) diff --git a/packages/shell-chrome/manifest.json b/packages/shell-chrome/manifest.json index 3237aaa5e..a74bdabac 100644 --- a/packages/shell-chrome/manifest.json +++ b/packages/shell-chrome/manifest.json @@ -2,14 +2,14 @@ "name": "Vue.js devtools", "version": "5.3.4", "version_name": "5.3.4", - "description": "Chrome and Firefox DevTools extension for debugging Vue.js applications.", - "manifest_version": 2, + "description": "DevTools extension for debugging Vue.js applications. This is version 5.", + "manifest_version": 3, "icons": { "16": "icons/16.png", "48": "icons/48.png", "128": "icons/128.png" }, - "browser_action": { + "action": { "default_icon": { "16": "icons/16-gray.png", "48": "icons/48-gray.png", @@ -19,23 +19,31 @@ "default_popup": "popups/not-found.html" }, "web_accessible_resources": [ - "devtools.html", - "devtools-background.html", - "build/backend.js" + { + "resources": [ + "devtools.html", + "devtools-background.html", + "build/backend.js", + "build/proxy.js", + "build/hook-exec.js", + "build/detector-exec.js" + ], + "matches": [ + "" + ], + "extension_ids": [] + } ], "devtools_page": "devtools-background.html", "background": { - "scripts": [ - "build/background.js" - ], - "persistent": false + "service_worker": "build/service-worker.js" }, "permissions": [ - "http://*/*", - "https://*/*", - "file:///*", - "contextMenus", - "storage" + "storage", + "scripting" + ], + "host_permissions": [ + "" ], "content_scripts": [ { @@ -56,5 +64,8 @@ ], "run_at": "document_idle" } - ] -} \ No newline at end of file + ], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'" + } +} diff --git a/packages/shell-chrome/src/detector-exec.js b/packages/shell-chrome/src/detector-exec.js new file mode 100644 index 000000000..113e6d718 --- /dev/null +++ b/packages/shell-chrome/src/detector-exec.js @@ -0,0 +1,85 @@ +import { installToast } from '@back/toast' + +function sendMessage (message) { + window.postMessage({ + key: '_vue-devtools-send-message', + message, + }) +} + +function detect () { + let delay = 1000 + let detectRemainingTries = 10 + + function runDetect () { + // Method 1: Check Nuxt.js + const nuxtDetected = !!(window.__NUXT__ || window.$nuxt) + + if (nuxtDetected) { + let Vue + + if (window.$nuxt) { + Vue = window.$nuxt.$root && window.$nuxt.$root.constructor + } + + sendMessage({ + devtoolsEnabled: (/* Vue 2 */ Vue && Vue.config.devtools) || + (/* Vue 3.2.14+ */ window.__VUE_DEVTOOLS_GLOBAL_HOOK__ && window.__VUE_DEVTOOLS_GLOBAL_HOOK__.enabled), + vueDetected: true, + nuxtDetected: true, + }, '*') + + return + } + + // Method 2: Check Vue 3 + const vueDetected = !!(window.__VUE__) + if (vueDetected) { + sendMessage({ + devtoolsEnabled: /* Vue 3.2.14+ */ window.__VUE_DEVTOOLS_GLOBAL_HOOK__ && window.__VUE_DEVTOOLS_GLOBAL_HOOK__.enabled, + vueDetected: true, + }, '*') + + return + } + + // Method 3: Scan all elements inside document + const all = document.querySelectorAll('*') + let el + for (let i = 0; i < all.length; i++) { + if (all[i].__vue__) { + el = all[i] + break + } + } + if (el) { + let Vue = Object.getPrototypeOf(el.__vue__).constructor + while (Vue.super) { + Vue = Vue.super + } + sendMessage({ + devtoolsEnabled: Vue.config.devtools, + vueDetected: true, + }, '*') + return + } + + if (detectRemainingTries > 0) { + detectRemainingTries-- + setTimeout(() => { + runDetect() + }, delay) + delay *= 5 + } + } + + setTimeout(() => { + runDetect() + }, 100) +} + +// inject the hook +if (document instanceof HTMLDocument) { + detect() + installToast(window) +} diff --git a/packages/shell-chrome/src/detector.js b/packages/shell-chrome/src/detector.js index ae79e75fb..124897daf 100644 --- a/packages/shell-chrome/src/detector.js +++ b/packages/shell-chrome/src/detector.js @@ -1,71 +1,12 @@ -import { installToast } from '@back/toast' -import { isFirefox } from '@utils/env' - -window.addEventListener('message', e => { - if (e.source === window && e.data.vueDetected) { - chrome.runtime.sendMessage(e.data) +window.addEventListener('message', function (event) { + if (event.data.key === '_vue-devtools-send-message') { + chrome.runtime.sendMessage(event.data.message) } -}) - -function detect (win) { - setTimeout(() => { - // Method 1: Check Nuxt.js - const nuxtDetected = Boolean(window.__NUXT__ || window.$nuxt) - - if (nuxtDetected) { - let Vue - - if (window.$nuxt) { - Vue = window.$nuxt.$root.constructor - } - - win.postMessage({ - devtoolsEnabled: Vue && Vue.config.devtools, - vueDetected: true, - nuxtDetected: true - }, '*') - - return - } +}, false) - // Method 2: Scan all elements inside document - const all = document.querySelectorAll('*') - let el - for (let i = 0; i < all.length; i++) { - if (all[i].__vue__) { - el = all[i] - break - } - } - if (el) { - let Vue = Object.getPrototypeOf(el.__vue__).constructor - while (Vue.super) { - Vue = Vue.super - } - win.postMessage({ - devtoolsEnabled: Vue.config.devtools, - vueDetected: true - }, '*') - } - }, 100) -} - -// inject the hook -if (document instanceof HTMLDocument) { - installScript(detect) - installScript(installToast) -} - -function installScript (fn) { - const source = ';(' + fn.toString() + ')(window)' - - if (isFirefox) { - // eslint-disable-next-line no-eval - window.eval(source) // in Firefox, this evaluates on the content window - } else { - const script = document.createElement('script') - script.textContent = source - document.documentElement.appendChild(script) - script.parentNode.removeChild(script) - } +const script = document.createElement('script') +script.src = chrome.runtime.getURL('build/detector-exec.js') +script.onload = () => { + script.remove() } +;(document.head || document.documentElement).appendChild(script) diff --git a/packages/shell-chrome/src/hook-exec.js b/packages/shell-chrome/src/hook-exec.js new file mode 100644 index 000000000..7549d0f16 --- /dev/null +++ b/packages/shell-chrome/src/hook-exec.js @@ -0,0 +1,3 @@ +import { installHook } from '@back/hook' + +installHook(window) diff --git a/packages/shell-chrome/src/hook.js b/packages/shell-chrome/src/hook.js index 722b53cc5..16269d7e3 100644 --- a/packages/shell-chrome/src/hook.js +++ b/packages/shell-chrome/src/hook.js @@ -1,18 +1,6 @@ -// This script is injected into every page. -import { installHook } from '@back/hook' -import { isFirefox } from '@utils/env' - -// inject the hook -if (document instanceof HTMLDocument) { - const source = ';(' + installHook.toString() + ')(window)' - - if (isFirefox) { - // eslint-disable-next-line no-eval - window.eval(source) // in Firefox, this evaluates on the content window - } else { - const script = document.createElement('script') - script.textContent = source - document.documentElement.appendChild(script) - script.parentNode.removeChild(script) - } +const script = document.createElement('script') +script.src = chrome.runtime.getURL('build/hook-exec.js') +script.onload = () => { + script.remove() } +;(document.head || document.documentElement).appendChild(script) diff --git a/packages/shell-chrome/src/background.js b/packages/shell-chrome/src/service-worker.js similarity index 51% rename from packages/shell-chrome/src/background.js rename to packages/shell-chrome/src/service-worker.js index 04ad5f80e..a36f20b2b 100644 --- a/packages/shell-chrome/src/background.js +++ b/packages/shell-chrome/src/service-worker.js @@ -18,7 +18,7 @@ chrome.runtime.onConnect.addListener(port => { if (!ports[tab]) { ports[tab] = { devtools: null, - backend: null + backend: null, } } ports[tab][name] = port @@ -33,13 +33,17 @@ function isNumeric (str) { } function installProxy (tabId) { - chrome.tabs.executeScript(tabId, { - file: '/build/proxy.js' + chrome.scripting.executeScript({ + target: { tabId }, + files: ['build/proxy.js'], }, function (res) { if (!res) { ports[tabId].devtools.postMessage('proxy-fail') } else { - console.log('injected proxy to tab ' + tabId) + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.log('injected proxy to tab ' + tabId) + } } }) } @@ -48,76 +52,77 @@ function doublePipe (id, one, two) { one.onMessage.addListener(lOne) function lOne (message) { if (message.event === 'log') { + // eslint-disable-next-line no-console return console.log('tab ' + id, message.payload) } - console.log('devtools -> backend', message) + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.log('%cdevtools -> backend', 'color:#888;', message) + } two.postMessage(message) } two.onMessage.addListener(lTwo) function lTwo (message) { if (message.event === 'log') { + // eslint-disable-next-line no-console return console.log('tab ' + id, message.payload) } - console.log('backend -> devtools', message) + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.log('%cbackend -> devtools', 'color:#888;', message) + } one.postMessage(message) } function shutdown () { - console.log('tab ' + id + ' disconnected.') + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.log('tab ' + id + ' disconnected.') + } one.onMessage.removeListener(lOne) two.onMessage.removeListener(lTwo) one.disconnect() two.disconnect() ports[id] = null - updateContextMenuItem() } one.onDisconnect.addListener(shutdown) two.onDisconnect.addListener(shutdown) - console.log('tab ' + id + ' connected.') - updateContextMenuItem() + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.log('tab ' + id + ' connected.') + } } chrome.runtime.onMessage.addListener((req, sender) => { if (sender.tab && req.vueDetected) { const suffix = req.nuxtDetected ? '.nuxt' : '' - chrome.browserAction.setIcon({ + chrome.action.setIcon({ tabId: sender.tab.id, path: { - 16: `icons/16${suffix}.png`, - 48: `icons/48${suffix}.png`, - 128: `icons/128${suffix}.png` - } + 16: chrome.runtime.getURL(`icons/16${suffix}.png`), + 48: chrome.runtime.getURL(`icons/48${suffix}.png`), + 128: chrome.runtime.getURL(`icons/128${suffix}.png`), + }, + }, () => { + // noop }) - chrome.browserAction.setPopup({ + chrome.action.setPopup({ tabId: sender.tab.id, - popup: req.devtoolsEnabled ? `popups/enabled${suffix}.html` : `popups/disabled${suffix}.html` + popup: chrome.runtime.getURL(req.devtoolsEnabled ? `popups/enabled${suffix}.html` : `popups/disabled${suffix}.html`), + }, () => { + // noop }) } -}) - -// Right-click inspect context menu entry -let activeTabId -chrome.tabs.onActivated.addListener(({ tabId }) => { - activeTabId = tabId - updateContextMenuItem() -}) -function updateContextMenuItem () { - chrome.contextMenus.removeAll(() => { - if (ports[activeTabId]) { - chrome.contextMenus.create({ - id: 'vue-inspect-instance', - title: 'Inspect Vue component', - contexts: ['all'] + if (req.action === 'vue-take-screenshot' && sender.envType === 'devtools_child') { + browser.tabs.captureVisibleTab({ + format: 'png', + }).then(dataUrl => { + browser.runtime.sendMessage({ + action: 'vue-screenshot-result', + id: req.id, + dataUrl, }) - } - }) -} - -chrome.contextMenus.onClicked.addListener((info, tab) => { - chrome.runtime.sendMessage({ - vueContextMenu: { - id: info.menuItemId - } - }) + }) + } }) diff --git a/packages/shell-chrome/webpack.config.js b/packages/shell-chrome/webpack.config.js index c99a162bd..8870b2189 100644 --- a/packages/shell-chrome/webpack.config.js +++ b/packages/shell-chrome/webpack.config.js @@ -4,12 +4,14 @@ const { createConfig } = require('@vue-devtools/build-tools') module.exports = createConfig({ entry: { hook: './src/hook.js', + 'hook-exec': './src/hook-exec.js', devtools: './src/devtools.js', - background: './src/background.js', + 'service-worker': './src/service-worker.js', 'devtools-background': './src/devtools-background.js', backend: './src/backend.js', proxy: './src/proxy.js', - detector: './src/detector.js' + detector: './src/detector.js', + 'detector-exec': './src/detector-exec.js', }, output: { path: path.join(__dirname, 'build'), From 839e2a1ba6a9d2c0235c416519ebf9e59a7ba916 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 11 Sep 2024 22:23:11 +0800 Subject: [PATCH 6/7] update package name --- packages/shell-chrome/manifest.json | 33 ++++++++--------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/packages/shell-chrome/manifest.json b/packages/shell-chrome/manifest.json index a74bdabac..a836ed580 100644 --- a/packages/shell-chrome/manifest.json +++ b/packages/shell-chrome/manifest.json @@ -1,8 +1,8 @@ { - "name": "Vue.js devtools", + "name": "Vue.js devtools (v5)", "version": "5.3.4", "version_name": "5.3.4", - "description": "DevTools extension for debugging Vue.js applications. This is version 5.", + "description": "This version is provided for legacy users and will not be updated in the future.", "manifest_version": 3, "icons": { "16": "icons/16.png", @@ -28,9 +28,7 @@ "build/hook-exec.js", "build/detector-exec.js" ], - "matches": [ - "" - ], + "matches": [""], "extension_ids": [] } ], @@ -38,30 +36,17 @@ "background": { "service_worker": "build/service-worker.js" }, - "permissions": [ - "storage", - "scripting" - ], - "host_permissions": [ - "" - ], + "permissions": ["storage", "scripting"], + "host_permissions": [""], "content_scripts": [ { - "matches": [ - "" - ], - "js": [ - "build/hook.js" - ], + "matches": [""], + "js": ["build/hook.js"], "run_at": "document_start" }, { - "matches": [ - "" - ], - "js": [ - "build/detector.js" - ], + "matches": [""], + "js": ["build/detector.js"], "run_at": "document_idle" } ], From 3c128e6649f6f640425740faf932e34e0816d246 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 11 Sep 2024 22:49:20 +0800 Subject: [PATCH 7/7] add .node-version file --- .node-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .node-version diff --git a/.node-version b/.node-version new file mode 100644 index 000000000..b6a7d89c6 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +16