From 53ecd4cb2c210e9e1f25f6d0384c1cef7309167b Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 15 Mar 2022 14:05:16 +0100 Subject: [PATCH] refactor: Chrome manifest v3 --- packages/shell-chrome/manifest.json | 37 +++++--- packages/shell-chrome/src/detector-exec.js | 69 ++++++++++++++ packages/shell-chrome/src/detector.js | 89 ++----------------- packages/shell-chrome/src/hook-exec.js | 3 + packages/shell-chrome/src/hook.js | 22 ++--- .../src/{background.js => service-worker.js} | 21 +++-- packages/shell-chrome/webpack.config.js | 4 +- 7 files changed, 127 insertions(+), 118 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} (85%) diff --git a/packages/shell-chrome/manifest.json b/packages/shell-chrome/manifest.json index fde7f5502..8a35806f9 100644 --- a/packages/shell-chrome/manifest.json +++ b/packages/shell-chrome/manifest.json @@ -3,13 +3,13 @@ "version": "6.1.3", "version_name": "6.1.3", "description": "Browser DevTools extension for debugging Vue.js applications.", - "manifest_version": 2, + "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,20 +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": [ - "", - "storage" + "storage", + "scripting" + ], + "host_permissions": [ + "" ], "content_scripts": [ { @@ -54,5 +65,7 @@ "run_at": "document_idle" } ], - "content_security_policy": "script-src 'self'; object-src 'self'" + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'" + } } \ No newline at end of file diff --git a/packages/shell-chrome/src/detector-exec.js b/packages/shell-chrome/src/detector-exec.js new file mode 100644 index 000000000..9e0472b6f --- /dev/null +++ b/packages/shell-chrome/src/detector-exec.js @@ -0,0 +1,69 @@ +import { installToast } from '@back/toast' + +function sendMessage (message) { + window.postMessage({ + key: '_vue-devtools-send-message', + message, + }) +} + +function detect () { + setTimeout(() => { + // 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, + }, '*') + } + }, 100) +} + +// inject the hook +if (document instanceof HTMLDocument) { + detect() + installToast() +} diff --git a/packages/shell-chrome/src/detector.js b/packages/shell-chrome/src/detector.js index 57a0c87b6..124897daf 100644 --- a/packages/shell-chrome/src/detector.js +++ b/packages/shell-chrome/src/detector.js @@ -1,83 +1,12 @@ -import { installToast } from '@back/toast' -import { isFirefox } from '@vue-devtools/shared-utils' - -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 = !!(window.__NUXT__ || window.$nuxt) - - if (nuxtDetected) { - let Vue - - if (window.$nuxt) { - Vue = window.$nuxt.$root && window.$nuxt.$root.constructor - } - - win.postMessage({ - 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) { - win.postMessage({ - devtoolsEnabled: /* Vue 3.2.14+ */ window.__VUE_DEVTOOLS_GLOBAL_HOOK__ && window.__VUE_DEVTOOLS_GLOBAL_HOOK__.enabled, - vueDetected: true, - }, '*') +}, false) - 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 - } - 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 b8bed57e4..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 '@vue-devtools/shared-utils' - -// 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 85% rename from packages/shell-chrome/src/background.js rename to packages/shell-chrome/src/service-worker.js index 16974c120..a36f20b2b 100644 --- a/packages/shell-chrome/src/background.js +++ b/packages/shell-chrome/src/service-worker.js @@ -33,8 +33,9 @@ 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') @@ -95,17 +96,21 @@ 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 }) } diff --git a/packages/shell-chrome/webpack.config.js b/packages/shell-chrome/webpack.config.js index 11782b5c2..da0e8c63d 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-exec': './src/detector-exec.js', }, output: { path: path.join(__dirname, 'build'),