diff --git a/README.md b/README.md index 003a71c..3fdeccc 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,6 @@ -

Svelte DevTools

+# Svelte DevTools -
- - Chrome Web Store - - - Mozilla Add-on - -
+[![Chrome Web Store](https://img.shields.io/chrome-web-store/users/ckolcbmkjpjmangdbmnkpjigpkddpogn?color=blue&label=Chrome)](https://chrome.google.com/webstore/detail/svelte-devtools/ckolcbmkjpjmangdbmnkpjigpkddpogn) [![Mozilla Add-on](https://img.shields.io/amo/users/svelte-devtools?color=orange&label=Firefox)](https://addons.mozilla.org/en-US/firefox/addon/svelte-devtools) Svelte DevTools is a Chrome extension for the [Svelte](https://svelte.dev/) framework. It allows you to inspect the Svelte state and component hierarchies in the Developer Tools. @@ -23,7 +16,7 @@ This extensions officially supports Svelte 4.0 and above. ## Development -Clone this repository and run the package script. +Clone this repository, setup and run the build script ```sh git clone https://github.com/sveltejs/svelte-devtools.git diff --git a/rollup.config.js b/rollup.config.js index 636f123..82f9b54 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -9,42 +9,9 @@ export default defineConfig([ }, { input: 'src/client/index.js', - output: { - file: 'build/courier.js', - format: 'iife', - banner: `if (!window.tag) { - window.tag = document.createElement('script') - window.tag.text = \``, - footer: `\` - if (window.sessionStorage.SvelteDevToolsProfilerEnabled === "true") window.tag.text = window.tag.text.replace('let profilerEnabled = false;', '\$&\\nstartProfiler();') - document.children[0].append(window.tag) - const sendMessage = chrome.runtime.sendMessage - const postMessage = window.postMessage.bind(window) - chrome.runtime.onMessage.addListener((message, sender) => { - const fromBackground = sender && sender.id === chrome.runtime.id - if (!fromBackground) { - console.error('Message from unexpected sender', sender, message) - return - } - switch (message.type) { - case 'startProfiler': - window.sessionStorage.SvelteDevToolsProfilerEnabled = "true" - break - case 'stopProfiler': - // fallthrough - case 'clear': - delete window.sessionStorage.SvelteDevToolsProfilerEnabled - break - } - postMessage(message) - }) - window.addEventListener( - 'message', - e => e.source == window && sendMessage(e.data), - false - ) - window.addEventListener('unload', () => sendMessage({ type: 'clear' })) -}`, - }, + output: [ + { file: 'static/courier.js', format: 'iife' }, + { file: 'build/courier.js', format: 'iife' }, + ], }, ]); diff --git a/src/client/index.js b/src/client/index.js index 5623683..1b018f6 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -108,7 +108,7 @@ function serializeNode(node) { const attributes = Array.from(node.detail.attributes || []); /** @type {NonNullable} */ - const listeners = res.detail.__listeners || []; + const listeners = node.detail.__listeners || []; res.detail = { attributes: attributes.map(({ name: key, value }) => ({ key, value })), diff --git a/src/client/svelte.js b/src/client/svelte.js index 625670a..045d3c5 100644 --- a/src/client/svelte.js +++ b/src/client/svelte.js @@ -123,8 +123,8 @@ document.addEventListener('SvelteRegisterBlock', ({ detail }) => { } Promise.resolve().then(() => { - const invalidate = node.detail.$$?.invalidate || {}; - Object.keys(invalidate.length).length && listeners.update(node); + const invalidate = node.detail.$$?.bound || {}; + Object.keys(invalidate).length && listeners.update(node); }); break; } diff --git a/static/background.js b/static/background.js index 8b0739d..bf84629 100644 --- a/static/background.js +++ b/static/background.js @@ -7,18 +7,21 @@ chrome.runtime.onConnect.addListener((port) => { return port.disconnect(); } - port.onMessage.addListener((msg, sender) => { - if (msg.type === 'init') { - return setup(msg.tabId, sender, msg.profilerEnabled); - } else if (msg.type === 'reload') { - return chrome.tabs.reload(msg.tabId, { bypassCache: true }); + // messages are from the devtools page and not content script (courier.js) + port.onMessage.addListener((message, sender) => { + if (message.type === 'init') { + return setup(message.tabId, sender); + } else if (message.type === 'reload') { + return chrome.tabs.reload(message.tabId, { bypassCache: true }); } - return chrome.tabs.sendMessage(msg.tabId, msg); + // relay messages from devtools page to `chrome.scripting` + return chrome.tabs.sendMessage(message.tabId, message); }); }); -// relay messages from content scripts to devtools page +// relay messages from `chrome.scripting` to devtools page chrome.runtime.onMessage.addListener((msg, sender) => { + if (sender.id !== chrome.runtime.id) return; // unexpected sender const port = sender.tab?.id && ports.get(sender.tab.id); if (port) port.postMessage(msg); }); @@ -27,29 +30,57 @@ chrome.runtime.onMessage.addListener((msg, sender) => { function attach(tabId, changed) { if (!ports.has(tabId) || changed.status !== 'loading') return; - chrome.tabs.executeScript(tabId, { - file: '/courier.js', - runAt: 'document_start', + chrome.scripting.executeScript({ + target: { tabId }, + + // no lexical context, `func` is serialized and deserialized. + // a limbo world where both `chrome` and `window` are defined + // with many unexpected and out of the ordinary behaviors, do + // minimal work here and delegate to `courier.js` in the page. + func: () => { + const source = chrome.runtime.getURL('/courier.js'); + if (document.querySelector(`script[src="${source}"]`)) return; + + // attach script manually instead of declaring through `files` + // because `detail` in the dispatched custom events is `null` + const script = document.createElement('script'); + script.setAttribute('src', source); + document.body.appendChild(script); + + chrome.runtime.onMessage.addListener((message, sender) => { + if (sender.id !== chrome.runtime.id) return; // unexpected sender + window.postMessage(message); // relay to content script (courier.js) + }); + + window.addEventListener('message', ({ source, data }) => { + // only accept messages from our application or script + if (source === window && data?.source === 'svelte-devtools') { + chrome.runtime.sendMessage(data); + } + }); + + window.addEventListener('unload', () => { + chrome.runtime.sendMessage({ type: 'ext/clear' }); + }); + }, }); } /** - * * @param {number} tabId - * @param {chrome.runtime.Port} port - * @param {boolean} profilerEnabled + * @param {chrome.runtime.Port} sender */ -function setup(tabId, port, profilerEnabled) { - chrome.tabs.executeScript(tabId, { - code: profilerEnabled - ? `window.sessionStorage.SvelteDevToolsProfilerEnabled = "true"` - : 'delete window.sessionStorage.SvelteDevToolsProfilerEnabled', - runAt: 'document_start', - }); +function setup(tabId, sender) { + // chrome.tabs.executeScript(tabId, { + // code: profilerEnabled + // ? `window.sessionStorage.SvelteDevToolsProfilerEnabled = "true"` + // : 'delete window.sessionStorage.SvelteDevToolsProfilerEnabled', + // runAt: 'document_start', + // }); - ports.set(tabId, port); + ports.set(tabId, sender); - port.onDisconnect.addListener(() => { + sender.onDisconnect.addListener(() => { ports.delete(tabId); chrome.tabs.onUpdated.removeListener(attach); diff --git a/static/manifest.json b/static/manifest.json index a27298e..b3c1ab9 100644 --- a/static/manifest.json +++ b/static/manifest.json @@ -1,7 +1,7 @@ { - "manifest_version": 2, - "name": "Svelte Devtools", - "version": "1.3.0", + "manifest_version": 3, + "name": "Svelte DevTools", + "version": "2.0.0", "description": "Browser devtools extension for debugging Svelte applications.", "icons": { "16": "icons/16.png", @@ -12,9 +12,15 @@ }, "background": { - "scripts": ["background.js"] + "service_worker": "background.js" }, - "devtools_page": "devtools/index.html", - "permissions": ["tabs", ""], - "web_accessible_resources": ["courier.js"] + "devtools_page": "register.html", + "host_permissions": ["*://*/*"], + "permissions": ["activeTab", "scripting"], + "web_accessible_resources": [ + { + "resources": ["courier.js"], + "matches": ["*://*/*"] + } + ] } diff --git a/static/register.html b/static/register.html index f8cef97..6689014 100644 --- a/static/register.html +++ b/static/register.html @@ -1,8 +1,4 @@ - - - - - + diff --git a/static/register.js b/static/register.js index 0f60516..cbb761a 100644 --- a/static/register.js +++ b/static/register.js @@ -1,6 +1,6 @@ chrome.devtools.panels.create( 'Svelte', - chrome.devtools.panels.themeName == 'dark' + chrome.devtools.panels.themeName === 'dark' ? '/icons/svelte-logo-dark.svg' : '/icons/svelte-logo-light.svg', '/index.html',