Match-id-645d6786f413f96296f5fbf6cc123242c12adf82
This commit is contained in:
parent
4834261253
commit
e9b9f69269
|
@ -1,30 +1,41 @@
|
||||||
|
import { checkData, packagePayload } from '../utils/transferTool';
|
||||||
|
import { requestAllVNodeTreeInfos, initDevToolPageConnection } from '../utils/constants';
|
||||||
|
|
||||||
// 多个页面、tab页共享一个 background,需要建立连接池,给每个tab建立连接
|
// 多个页面、tab页共享一个 background,需要建立连接池,给每个tab建立连接
|
||||||
const connections = {};
|
const connections = {};
|
||||||
|
|
||||||
// panel 代码中调用 let backgroundPageConnection = chrome.runtime.connect({...}) 会触发回调函数
|
// panel 代码中调用 let backgroundPageConnection = chrome.runtime.connect({...}) 会触发回调函数
|
||||||
chrome.runtime.onConnect.addListener(function (port) {
|
chrome.runtime.onConnect.addListener(function (port) {
|
||||||
|
function extensionListener(message) {
|
||||||
// The original connection event doesn't include the tab ID of the
|
const isHorizonMessage = checkData(message);
|
||||||
// DevTools page, so we need to send it explicitly.
|
if (isHorizonMessage) {
|
||||||
function extensionListener(message, sender, sendResponse) {
|
console.log('received message', message);
|
||||||
// 在backgroundPageConnection创建后会发送初始化请求,这样就可以获取tabId,给连接编号
|
const { payload } = message;
|
||||||
if (message.name === 'init') {
|
const { type, data } = payload;
|
||||||
|
let passMessage;
|
||||||
|
if (type === initDevToolPageConnection) {
|
||||||
|
if (!connections[data]) {
|
||||||
// 获取 panel 所在 tab 页的tabId
|
// 获取 panel 所在 tab 页的tabId
|
||||||
connections[message.tabId] = port;
|
connections[data] = port;
|
||||||
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
|
}
|
||||||
chrome.tabs.sendMessage(tabs[0].id, {tag: 'init horizon info'}, function(response) {
|
passMessage = packagePayload({ type: requestAllVNodeTreeInfos });
|
||||||
console.log(response.farewell);
|
} else {
|
||||||
|
passMessage = message;
|
||||||
|
}
|
||||||
|
console.log('post message:', passMessage);
|
||||||
|
// 查询参数有 active 和 currentWindow, 如果开发者工具与页面分离,会导致currentWindow为false才能找到
|
||||||
|
// 所以只用 active 参数查找,但不确定这么写是否会引发查询错误的情况
|
||||||
|
// 或许需要用不同的查询参数查找两次
|
||||||
|
chrome.tabs.query({ active: true }, function (tabs) {
|
||||||
|
if (tabs.length) {
|
||||||
|
chrome.tabs.sendMessage(tabs[0].id, passMessage);
|
||||||
|
console.log('post message end');
|
||||||
|
} else {
|
||||||
|
console.log('do not find message');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.name === 'update') {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// other message handling
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen to messages sent from the DevTools page
|
// Listen to messages sent from the DevTools page
|
||||||
port.onMessage.addListener(extensionListener);
|
port.onMessage.addListener(extensionListener);
|
||||||
|
|
||||||
|
@ -42,11 +53,11 @@ chrome.runtime.onConnect.addListener(function (port) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听来自 content script 的消息,并将消息发送给对应的 devTools page,也就是 panel
|
// 监听来自 content script 的消息,并将消息发送给对应的 devTools page,也就是 panel
|
||||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||||
// Messages from content scripts should have sender.tab set
|
// Messages from content scripts should have sender.tab set
|
||||||
if (sender.tab) {
|
if (sender.tab) {
|
||||||
const tabId = sender.tab.id;
|
const tabId = sender.tab.id;
|
||||||
if (tabId in connections) {
|
if (tabId in connections && checkData(request)) {
|
||||||
connections[tabId].postMessage(request);
|
connections[tabId].postMessage(request);
|
||||||
} else {
|
} else {
|
||||||
console.log('Tab not found in connection list.');
|
console.log('Tab not found in connection list.');
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { injectCode } from '../utils/injectUtils';
|
import { injectCode } from '../utils/injectUtils';
|
||||||
|
import { checkData } from '../utils/transferTool';
|
||||||
|
|
||||||
// 页面的window对象不能直接通过 contentScript 代码修改,只能通过添加 js 代码往页面 window 注入hook
|
// 页面的window对象不能直接通过 contentScript 代码修改,只能通过添加 js 代码往页面 window 注入hook
|
||||||
injectCode(chrome.runtime.getURL('/injector.js'));
|
injectCode(chrome.runtime.getURL('/injector.js'));
|
||||||
|
@ -10,12 +11,10 @@ window.addEventListener('message', event => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.data.type && (event.data.type === 'HORIZON_DEV_TOOLS')) {
|
const data = event.data;
|
||||||
console.log('Content script received: ' + JSON.stringify(event.data.vNode));
|
if (checkData(data)) {
|
||||||
// 传递给background
|
// 传递给background
|
||||||
chrome.runtime.sendMessage(event.data.vNode, function (response) {
|
chrome.runtime.sendMessage(data);
|
||||||
console.log(response);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
@ -23,14 +22,12 @@ window.addEventListener('message', event => {
|
||||||
|
|
||||||
// 监听来自background的消息
|
// 监听来自background的消息
|
||||||
chrome.runtime.onMessage.addListener(
|
chrome.runtime.onMessage.addListener(
|
||||||
function (request, sender, sendResponse) {
|
function (request, sender) {
|
||||||
console.log(sender.tab ?
|
// 该方法可以监听页面 contentScript 和插件的消息
|
||||||
'from a content script:' + sender.tab.url :
|
// 没有 tab 信息说明消息来自插件
|
||||||
'from the extension');
|
if (!sender.tab && checkData(request)) {
|
||||||
if (request.tag === 'init horizon info') {
|
|
||||||
// 传递消息给页面
|
// 传递消息给页面
|
||||||
console.log('start pass info to webpage');
|
window.postMessage(request, '*');
|
||||||
window.postMessage({type: 'HORIZON_DEV_TOOLS', id: 1}, '*');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
import parseTreeRoot from "../parser/parseVNode";
|
import parseTreeRoot, { deleteVNode } from '../parser/parseVNode';
|
||||||
|
import { packagePayload, checkData } from './../utils/transferTool';
|
||||||
|
import { oneVNodeTreeInfos, allVNodeTreesInfos, requestAllVNodeTreeInfos } from './../utils/constants';
|
||||||
|
|
||||||
|
const roots = [];
|
||||||
|
|
||||||
function injectHook() {
|
function injectHook() {
|
||||||
if (window.__HORIZON_DEV_HOOK__) {
|
if (window.__HORIZON_DEV_HOOK__) {
|
||||||
|
@ -7,26 +11,49 @@ function injectHook() {
|
||||||
Object.defineProperty(window, '__HORIZON_DEV_HOOK__', {
|
Object.defineProperty(window, '__HORIZON_DEV_HOOK__', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
value: {
|
value: {
|
||||||
roots: [],
|
addIfNotInclude: function( treeRoot: any) {
|
||||||
|
if (!roots.includes(treeRoot)) {
|
||||||
|
roots.push(treeRoot);
|
||||||
|
}
|
||||||
|
},
|
||||||
send: function (vNode: any) {
|
send: function (vNode: any) {
|
||||||
const result = parseTreeRoot(vNode);
|
const result = parseTreeRoot(vNode);
|
||||||
window.postMessage({
|
window.postMessage(packagePayload({
|
||||||
type: 'HORIZON_DEV_TOOLS', vNode: result
|
data: result,
|
||||||
}, '*');
|
type: oneVNodeTreeInfos
|
||||||
|
}), '*');
|
||||||
},
|
},
|
||||||
listen: function (id: number) {
|
delete: function (vNode: any) {
|
||||||
window.addEventListener('message', function(event) {
|
// 开发工具中保存了 vNode 的引用,在清理 VNode 的时候需要一并删除
|
||||||
|
deleteVNode(vNode);
|
||||||
|
const index = roots.indexOf(vNode);
|
||||||
|
if (index !== -1) {
|
||||||
|
roots.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
window.addEventListener('message', function (event) {
|
||||||
// We only accept messages from ourselves
|
// We only accept messages from ourselves
|
||||||
if (event.source !== window) {
|
if (event.source !== window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const request = event.data;
|
||||||
if (event.data.type && (event.data.type === 'HORIZON_DEV_TOOLS') && event.data.id === id) {
|
if (checkData(request)) {
|
||||||
console.log('todo');
|
const { payload } = request;
|
||||||
|
const { type, data } = payload;
|
||||||
|
if (type === requestAllVNodeTreeInfos) {
|
||||||
|
const result = roots.reduce((pre, current) => {
|
||||||
|
const info = parseTreeRoot(current);
|
||||||
|
pre.push(info);
|
||||||
|
return pre;
|
||||||
|
}, []);
|
||||||
|
window.postMessage(packagePayload({
|
||||||
|
data: result,
|
||||||
|
type: allVNodeTreesInfos
|
||||||
|
}), '*');
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
injectHook();
|
injectHook();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useEffect } from 'horizon';
|
import { useState, useEffect, useRef } from 'horizon';
|
||||||
import VTree, { IData } from '../components/VTree';
|
import VTree, { IData } from '../components/VTree';
|
||||||
import Search from '../components/Search';
|
import Search from '../components/Search';
|
||||||
import ComponentInfo from '../components/ComponentInfo';
|
import ComponentInfo from '../components/ComponentInfo';
|
||||||
|
@ -8,6 +8,8 @@ import { mockParsedVNodeData, parsedMockState } from '../devtools/mock';
|
||||||
import { FilterTree } from '../hooks/FilterTree';
|
import { FilterTree } from '../hooks/FilterTree';
|
||||||
import Close from '../svgs/Close';
|
import Close from '../svgs/Close';
|
||||||
import Arrow from './../svgs/Arrow';
|
import Arrow from './../svgs/Arrow';
|
||||||
|
import { initDevToolPageConnection, allVNodeTreesInfos, requestComponentAttrs } from './../utils/constants';
|
||||||
|
import { packagePayload } from './../utils/transferTool';
|
||||||
|
|
||||||
const parseVNodeData = (rawData) => {
|
const parseVNodeData = (rawData) => {
|
||||||
const idIndentationMap: {
|
const idIndentationMap: {
|
||||||
|
@ -55,6 +57,7 @@ function App() {
|
||||||
const [parsedVNodeData, setParsedVNodeData] = useState([]);
|
const [parsedVNodeData, setParsedVNodeData] = useState([]);
|
||||||
const [componentAttrs, setComponentAttrs] = useState({});
|
const [componentAttrs, setComponentAttrs] = useState({});
|
||||||
const [selectComp, setSelectComp] = useState(null);
|
const [selectComp, setSelectComp] = useState(null);
|
||||||
|
const treeRootInfos = useRef<{[id: string]: number}>({}); // 记录保存的根节点 id 和长度
|
||||||
|
|
||||||
const {
|
const {
|
||||||
filterValue,
|
filterValue,
|
||||||
|
@ -77,6 +80,34 @@ function App() {
|
||||||
state: parsedMockState,
|
state: parsedMockState,
|
||||||
props: parsedMockState,
|
props: parsedMockState,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
const connection = chrome.runtime.connect({
|
||||||
|
name: 'panel'
|
||||||
|
});
|
||||||
|
// 页面打开后发送初始化请求
|
||||||
|
connection.postMessage(packagePayload({
|
||||||
|
type: initDevToolPageConnection,
|
||||||
|
data: chrome.devtools.inspectedWindow.tabId
|
||||||
|
}));
|
||||||
|
// 监听 background消息
|
||||||
|
connection.onMessage.addListener(function (message) {
|
||||||
|
const { payload } = message;
|
||||||
|
if (payload) {
|
||||||
|
const { type, data } = payload;
|
||||||
|
if (type === allVNodeTreesInfos) {
|
||||||
|
const allTreeData = data.reduce((pre, current) => {
|
||||||
|
const parsedTreeData = parseVNodeData(current);
|
||||||
|
const length = parsedTreeData.length;
|
||||||
|
if (length) {
|
||||||
|
const treeRoot = parsedTreeData[0];
|
||||||
|
treeRootInfos.current[treeRoot.id] = length;
|
||||||
|
}
|
||||||
|
return pre.concat(parsedTreeData);
|
||||||
|
}, []);
|
||||||
|
setParsedVNodeData(allTreeData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -85,10 +116,17 @@ function App() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectComp = (item: IData) => {
|
const handleSelectComp = (item: IData) => {
|
||||||
|
if (isDev) {
|
||||||
setComponentAttrs({
|
setComponentAttrs({
|
||||||
state: parsedMockState,
|
state: parsedMockState,
|
||||||
props: parsedMockState,
|
props: parsedMockState,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
connection.postMessage({
|
||||||
|
name: requestComponentAttrs,
|
||||||
|
data: item.id
|
||||||
|
});
|
||||||
|
}
|
||||||
setSelectComp(item);
|
setSelectComp(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -134,8 +172,8 @@ function App() {
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.right}>
|
<div className={styles.right}>
|
||||||
<ComponentInfo
|
<ComponentInfo
|
||||||
name={selectComp ? selectComp.name: null}
|
name={selectComp ? selectComp.name : null}
|
||||||
attrs={selectComp ? componentAttrs: {}}
|
attrs={selectComp ? componentAttrs : {}}
|
||||||
parents={parents}
|
parents={parents}
|
||||||
onClickParent={handleClickParent} />
|
onClickParent={handleClickParent} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -57,4 +57,12 @@ function parseTreeRoot(treeRoot: VNode) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteVNode(vNode: VNode) {
|
||||||
|
if (VNodeToIdMap.has(vNode)) {
|
||||||
|
const id = VNodeToIdMap.get(vNode);
|
||||||
|
VNodeToIdMap.delete(vNode);
|
||||||
|
IdToVNodeMap.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default parseTreeRoot;
|
export default parseTreeRoot;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// panel 页面打开后初始化连接标志
|
||||||
|
export const initDevToolPageConnection = 'init dev tool page connection';
|
||||||
|
// background 解析全部 root VNodes 标志
|
||||||
|
export const requestAllVNodeTreeInfos = 'request all vNodes tree infos';
|
||||||
|
// vNodes 全部树解析结果标志
|
||||||
|
export const allVNodeTreesInfos = 'vNode trees Infos';
|
||||||
|
// 一棵树的解析
|
||||||
|
export const oneVNodeTreeInfos = 'one vNode tree';
|
||||||
|
// 获取组件属性
|
||||||
|
export const requestComponentAttrs = 'get component attrs';
|
||||||
|
// 返回组件属性
|
||||||
|
export const componentAttrs = 'component attrs';
|
|
@ -0,0 +1,21 @@
|
||||||
|
const devTools = 'HORIZON_DEV_TOOLS';
|
||||||
|
|
||||||
|
interface payLoadType {
|
||||||
|
type: string,
|
||||||
|
data?: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function packagePayload(payload: payLoadType) {
|
||||||
|
return {
|
||||||
|
type: devTools,
|
||||||
|
payload,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkData(data: any) {
|
||||||
|
if (data?.type === devTools) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -275,6 +275,11 @@ function renderFromRoot(treeRoot) {
|
||||||
// 2. 提交变更
|
// 2. 提交变更
|
||||||
submitToRender(treeRoot);
|
submitToRender(treeRoot);
|
||||||
|
|
||||||
|
if (window.__HORIZON_DEV_HOOK__) {
|
||||||
|
const hook = window.__HORIZON_DEV_HOOK__;
|
||||||
|
hook.addIfNotInclude(treeRoot);
|
||||||
|
hook.send(treeRoot);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue