diff --git a/libs/extension/src/background/index.ts b/libs/extension/src/background/index.ts new file mode 100644 index 00000000..2745c61a --- /dev/null +++ b/libs/extension/src/background/index.ts @@ -0,0 +1,58 @@ +// 多个页面、tab页共享一个 background,需要建立连接池,给每个tab建立连接 +const connections = {}; + +// panel 代码中调用 let backgroundPageConnection = chrome.runtime.connect({...}) 会触发回调函数 +chrome.runtime.onConnect.addListener(function (port) { + + // The original connection event doesn't include the tab ID of the + // DevTools page, so we need to send it explicitly. + function extensionListener(message, sender, sendResponse) { + // 在backgroundPageConnection创建后会发送初始化请求,这样就可以获取tabId,给连接编号 + if (message.name === 'init') { + // 获取 panel 所在 tab 页的tabId + connections[message.tabId] = port; + chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { + chrome.tabs.sendMessage(tabs[0].id, {tag: 'init horizon info'}, function(response) { + console.log(response.farewell); + }); + }); + return; + } + + if (message.name === 'update') { + return; + } + // other message handling + } + + // Listen to messages sent from the DevTools page + port.onMessage.addListener(extensionListener); + + port.onDisconnect.addListener(function (port) { + port.onMessage.removeListener(extensionListener); + + const tabs = Object.keys(connections); + for (let i = 0, len = tabs.length; i < len; i++) { + if (connections[tabs[i]] == port) { + delete connections[tabs[i]]; + break; + } + } + }); +}); + +// 监听来自 content script 的消息,并将消息发送给对应的 devTools page,也就是 panel +chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { + // Messages from content scripts should have sender.tab set + if (sender.tab) { + const tabId = sender.tab.id; + if (tabId in connections) { + connections[tabId].postMessage(request); + } else { + console.log('Tab not found in connection list.'); + } + } else { + console.log('sender.tab not defined.'); + } + return true; +}); diff --git a/libs/extension/src/contentScript/index.ts b/libs/extension/src/contentScript/index.ts new file mode 100644 index 00000000..2236496a --- /dev/null +++ b/libs/extension/src/contentScript/index.ts @@ -0,0 +1,36 @@ +import { injectCode } from '../utils/injectUtils'; + +// 页面的window对象不能直接通过 contentScript 代码修改,只能通过添加 js 代码往页面 window 注入hook +injectCode(chrome.runtime.getURL('/injector.js')); + +// 监听来自页面的信息 +window.addEventListener('message', event => { + // 只监听来自本页面的消息 + if (event.source !== window) { + return; + } + + if (event.data.type && (event.data.type === 'HORIZON_DEV_TOOLS')) { + console.log('Content script received: ' + JSON.stringify(event.data.vNode)); + // 传递给background + chrome.runtime.sendMessage(event.data.vNode, function (response) { + console.log(response); + }); + } +}, false); + + + +// 监听来自background的消息 +chrome.runtime.onMessage.addListener( + function (request, sender, sendResponse) { + console.log(sender.tab ? + 'from a content script:' + sender.tab.url : + 'from the extension'); + if (request.tag === 'init horizon info') { + // 传递消息给页面 + console.log('start pass info to webpage'); + window.postMessage({type: 'HORIZON_DEV_TOOLS', id: 1}, '*'); + } + } +); diff --git a/libs/extension/src/injector/index.ts b/libs/extension/src/injector/index.ts new file mode 100644 index 00000000..178cf608 --- /dev/null +++ b/libs/extension/src/injector/index.ts @@ -0,0 +1,32 @@ +import parseTreeRoot from "../parser/parseVNode"; + +function injectHook() { + if (window.__HORIZON_DEV_HOOK__) { + return; + } + Object.defineProperty(window, '__HORIZON_DEV_HOOK__', { + enumerable: false, + value: { + roots: [], + send: function (vNode: any) { + const result = parseTreeRoot(vNode); + window.postMessage({ + type: 'HORIZON_DEV_TOOLS', vNode: result + }, '*'); + }, + listen: function (id: number) { + window.addEventListener('message', function(event) { + // We only accept messages from ourselves + if (event.source !== window) { + return; + } + + if (event.data.type && (event.data.type === 'HORIZON_DEV_TOOLS') && event.data.id === id) { + console.log('todo'); + } + }); + } + }, + }); +} +injectHook(); diff --git a/libs/extension/src/main/index.ts b/libs/extension/src/main/index.ts new file mode 100644 index 00000000..b81f544c --- /dev/null +++ b/libs/extension/src/main/index.ts @@ -0,0 +1,7 @@ +chrome.devtools.panels.create('Horizon', + '', + 'panel.html', + function(panel) { + + } +); \ No newline at end of file diff --git a/libs/extension/src/main/main.html b/libs/extension/src/main/main.html new file mode 100644 index 00000000..540f18ae --- /dev/null +++ b/libs/extension/src/main/main.html @@ -0,0 +1,12 @@ + + + + + + +
+

Horizon dev tools!

+
+ + + diff --git a/libs/extension/src/manifest.json b/libs/extension/src/manifest.json new file mode 100644 index 00000000..3db7b374 --- /dev/null +++ b/libs/extension/src/manifest.json @@ -0,0 +1,22 @@ +{ + "name": "Horizon dev tool", + "description": "Horizon chrome dev extension", + "version": "1.0", + "minimum_chrome_version": "10.0", + "manifest_version": 3, + "background": { + "service_worker": "background.js" + }, + "permissions": ["storage", "activeTab", "scripting"], + + "devtools_page": "main.html", + "action": {}, + "content_scripts": [ + { + "matches": [""], + "js": ["contentScript.js"], + "run_at": "document_start" + } + ], + "web_accessible_resources": [] +} diff --git a/libs/extension/src/utils/injectUtils.ts b/libs/extension/src/utils/injectUtils.ts new file mode 100644 index 00000000..583eb5ea --- /dev/null +++ b/libs/extension/src/utils/injectUtils.ts @@ -0,0 +1,19 @@ + +function ifNullThrows(v) { + if (v === null) { + throw new Error('received a null'); + } + return v; +} + +// 用于向页面注入脚本 +export function injectCode(src) { + const script = document.createElement('script'); + script.src = src; + script.onload = function () { + // 加载完毕后需要移除 + script.remove(); + }; + + ifNullThrows(document.head || document.documentElement).appendChild(script); +} diff --git a/libs/extension/src/utils.ts b/libs/extension/src/utils/regExpUtils.ts similarity index 100% rename from libs/extension/src/utils.ts rename to libs/extension/src/utils/regExpUtils.ts diff --git a/libs/extension/webpack.config.js b/libs/extension/webpack.config.js index 3910117e..f712808b 100644 --- a/libs/extension/webpack.config.js +++ b/libs/extension/webpack.config.js @@ -7,7 +7,6 @@ const config = { injector: './src/injector/index.ts', contentScript: './src/contentScript/index.ts', panel: './src/panel/index.tsx', - popup: './src/popup/index.ts', }, output: { path: path.resolve(__dirname, './build'),