Match-id-9696388f05085d0c1eb211cd745a75e2c2a6ab46
This commit is contained in:
parent
e9b9f69269
commit
18a5f36604
|
@ -1,5 +1,6 @@
|
||||||
import { checkData, packagePayload } from '../utils/transferTool';
|
import { checkMessage, packagePayload, changeSource } from '../utils/transferTool';
|
||||||
import { requestAllVNodeTreeInfos, initDevToolPageConnection } from '../utils/constants';
|
import { RequestAllVNodeTreeInfos, InitDevToolPageConnection, DevToolBackground } from '../utils/constants';
|
||||||
|
import { DevToolPanel, DevToolContentScript } from './../utils/constants';
|
||||||
|
|
||||||
// 多个页面、tab页共享一个 background,需要建立连接池,给每个tab建立连接
|
// 多个页面、tab页共享一个 background,需要建立连接池,给每个tab建立连接
|
||||||
const connections = {};
|
const connections = {};
|
||||||
|
@ -7,22 +8,21 @@ 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) {
|
function extensionListener(message) {
|
||||||
const isHorizonMessage = checkData(message);
|
const isHorizonMessage = checkMessage(message, DevToolPanel);
|
||||||
if (isHorizonMessage) {
|
if (isHorizonMessage) {
|
||||||
console.log('received message', message);
|
|
||||||
const { payload } = message;
|
const { payload } = message;
|
||||||
const { type, data } = payload;
|
const { type, data } = payload;
|
||||||
let passMessage;
|
let passMessage;
|
||||||
if (type === initDevToolPageConnection) {
|
if (type === InitDevToolPageConnection) {
|
||||||
if (!connections[data]) {
|
if (!connections[data]) {
|
||||||
// 获取 panel 所在 tab 页的tabId
|
// 获取 panel 所在 tab 页的tabId
|
||||||
connections[data] = port;
|
connections[data] = port;
|
||||||
}
|
}
|
||||||
passMessage = packagePayload({ type: requestAllVNodeTreeInfos });
|
passMessage = packagePayload({ type: RequestAllVNodeTreeInfos }, DevToolBackground);
|
||||||
} else {
|
} else {
|
||||||
passMessage = message;
|
passMessage = message;
|
||||||
|
changeSource(passMessage, DevToolBackground);
|
||||||
}
|
}
|
||||||
console.log('post message:', passMessage);
|
|
||||||
// 查询参数有 active 和 currentWindow, 如果开发者工具与页面分离,会导致currentWindow为false才能找到
|
// 查询参数有 active 和 currentWindow, 如果开发者工具与页面分离,会导致currentWindow为false才能找到
|
||||||
// 所以只用 active 参数查找,但不确定这么写是否会引发查询错误的情况
|
// 所以只用 active 参数查找,但不确定这么写是否会引发查询错误的情况
|
||||||
// 或许需要用不同的查询参数查找两次
|
// 或许需要用不同的查询参数查找两次
|
||||||
|
@ -53,12 +53,13 @@ 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 (message, 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 && checkData(request)) {
|
if (tabId in connections && checkMessage(message, DevToolContentScript)) {
|
||||||
connections[tabId].postMessage(request);
|
changeSource(message, DevToolBackground);
|
||||||
|
connections[tabId].postMessage(message);
|
||||||
} else {
|
} else {
|
||||||
console.log('Tab not found in connection list.');
|
console.log('Tab not found in connection list.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { useState, useRef, useEffect } from 'horizon';
|
import { useState, useRef, useEffect } from 'horizon';
|
||||||
import styles from './VList.less';
|
import styles from './VList.less';
|
||||||
|
|
||||||
interface IProps<T extends { id: string }> {
|
interface IProps<T extends { id: number | string }> {
|
||||||
data: T[],
|
data: T[],
|
||||||
width: number, // 暂时未用到,当需要支持横向滚动时使用
|
width: number, // 暂时未用到,当需要支持横向滚动时使用
|
||||||
height: number, // VList 的高度
|
height: number, // VList 的高度
|
||||||
|
@ -20,7 +20,7 @@ export type renderInfoType<T> = {
|
||||||
skipItemCountBeforeScrollItem: number,
|
skipItemCountBeforeScrollItem: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function VList<T extends { id: string }>(props: IProps<T>) {
|
export function VList<T extends { id: number | string }>(props: IProps<T>) {
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
height,
|
height,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { SizeObserver } from './SizeObserver';
|
||||||
import { renderInfoType, VList } from './VList';
|
import { renderInfoType, VList } from './VList';
|
||||||
|
|
||||||
export interface IData {
|
export interface IData {
|
||||||
id: string;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
indentation: number;
|
indentation: number;
|
||||||
userKey: string;
|
userKey: string;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { injectCode } from '../utils/injectUtils';
|
import { injectCode } from '../utils/injectUtils';
|
||||||
import { checkData } from '../utils/transferTool';
|
import { checkMessage } from '../utils/transferTool';
|
||||||
|
import { DevToolContentScript, DevToolHook, DevToolBackground } from './../utils/constants';
|
||||||
|
import { changeSource } 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'));
|
||||||
|
@ -12,7 +14,8 @@ window.addEventListener('message', event => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = event.data;
|
const data = event.data;
|
||||||
if (checkData(data)) {
|
if (checkMessage(data, DevToolHook)) {
|
||||||
|
changeSource(data, DevToolContentScript);
|
||||||
// 传递给background
|
// 传递给background
|
||||||
chrome.runtime.sendMessage(data);
|
chrome.runtime.sendMessage(data);
|
||||||
}
|
}
|
||||||
|
@ -22,12 +25,13 @@ window.addEventListener('message', event => {
|
||||||
|
|
||||||
// 监听来自background的消息
|
// 监听来自background的消息
|
||||||
chrome.runtime.onMessage.addListener(
|
chrome.runtime.onMessage.addListener(
|
||||||
function (request, sender) {
|
function (message, sender) {
|
||||||
// 该方法可以监听页面 contentScript 和插件的消息
|
// 该方法可以监听页面 contentScript 和插件的消息
|
||||||
// 没有 tab 信息说明消息来自插件
|
// 没有 tab 信息说明消息来自插件
|
||||||
if (!sender.tab && checkData(request)) {
|
if (!sender.tab && checkMessage(message, DevToolBackground)) {
|
||||||
|
changeSource(message, DevToolContentScript);
|
||||||
// 传递消息给页面
|
// 传递消息给页面
|
||||||
window.postMessage(request, '*');
|
window.postMessage(message, '*');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,23 @@
|
||||||
import parseTreeRoot, { deleteVNode } from '../parser/parseVNode';
|
import parseTreeRoot, { deleteVNode, queryVNode } from '../parser/parseVNode';
|
||||||
import { packagePayload, checkData } from './../utils/transferTool';
|
import { packagePayload, checkMessage } from './../utils/transferTool';
|
||||||
import { oneVNodeTreeInfos, allVNodeTreesInfos, requestAllVNodeTreeInfos } from './../utils/constants';
|
import {
|
||||||
|
RequestAllVNodeTreeInfos,
|
||||||
|
AllVNodeTreesInfos,
|
||||||
|
RequestComponentAttrs,
|
||||||
|
ComponentAttrs,
|
||||||
|
DevToolHook,
|
||||||
|
DevToolContentScript
|
||||||
|
} from './../utils/constants';
|
||||||
|
import { VNode } from './../../../horizon/src/renderer/vnode/VNode';
|
||||||
|
import { ClassComponent } from '../../../horizon/src/renderer/vnode/VNodeTags';
|
||||||
|
import { parseAttr } from '../parser/parseAttr';
|
||||||
|
|
||||||
|
function postMessage(type: string, data) {
|
||||||
|
window.postMessage(packagePayload({
|
||||||
|
type: type,
|
||||||
|
data: data,
|
||||||
|
}, DevToolHook), '*');
|
||||||
|
}
|
||||||
|
|
||||||
const roots = [];
|
const roots = [];
|
||||||
|
|
||||||
|
@ -11,19 +28,20 @@ function injectHook() {
|
||||||
Object.defineProperty(window, '__HORIZON_DEV_HOOK__', {
|
Object.defineProperty(window, '__HORIZON_DEV_HOOK__', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
value: {
|
value: {
|
||||||
addIfNotInclude: function( treeRoot: any) {
|
addIfNotInclude: function (treeRoot: VNode) {
|
||||||
if (!roots.includes(treeRoot)) {
|
if (!roots.includes(treeRoot)) {
|
||||||
roots.push(treeRoot);
|
roots.push(treeRoot);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
send: function (vNode: any) {
|
send: function () {
|
||||||
const result = parseTreeRoot(vNode);
|
const result = roots.reduce((pre, current) => {
|
||||||
window.postMessage(packagePayload({
|
const info = parseTreeRoot(current);
|
||||||
data: result,
|
pre.push(info);
|
||||||
type: oneVNodeTreeInfos
|
return pre;
|
||||||
}), '*');
|
}, []);
|
||||||
|
postMessage(AllVNodeTreesInfos, result);
|
||||||
},
|
},
|
||||||
delete: function (vNode: any) {
|
delete: function (vNode: VNode) {
|
||||||
// 开发工具中保存了 vNode 的引用,在清理 VNode 的时候需要一并删除
|
// 开发工具中保存了 vNode 的引用,在清理 VNode 的时候需要一并删除
|
||||||
deleteVNode(vNode);
|
deleteVNode(vNode);
|
||||||
const index = roots.indexOf(vNode);
|
const index = roots.indexOf(vNode);
|
||||||
|
@ -39,19 +57,28 @@ function injectHook() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const request = event.data;
|
const request = event.data;
|
||||||
if (checkData(request)) {
|
if (checkMessage(request, DevToolContentScript)) {
|
||||||
const { payload } = request;
|
const { payload } = request;
|
||||||
const { type, data } = payload;
|
const { type, data } = payload;
|
||||||
if (type === requestAllVNodeTreeInfos) {
|
if (type === RequestAllVNodeTreeInfos) {
|
||||||
const result = roots.reduce((pre, current) => {
|
const result = roots.reduce((pre, current) => {
|
||||||
const info = parseTreeRoot(current);
|
const info = parseTreeRoot(current);
|
||||||
pre.push(info);
|
pre.push(info);
|
||||||
return pre;
|
return pre;
|
||||||
}, []);
|
}, []);
|
||||||
window.postMessage(packagePayload({
|
postMessage(AllVNodeTreesInfos, result);
|
||||||
data: result,
|
} else if (type === RequestComponentAttrs) {
|
||||||
type: allVNodeTreesInfos
|
const vNode: VNode = queryVNode(data);
|
||||||
}), '*');
|
const tag = vNode.tag;
|
||||||
|
if (tag === ClassComponent) {
|
||||||
|
const { props, state } = vNode;
|
||||||
|
const parsedProps = parseAttr(props);
|
||||||
|
const parsedState = parseAttr(state);
|
||||||
|
postMessage(ComponentAttrs, {
|
||||||
|
parsedProps,
|
||||||
|
parsedState,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,13 @@ 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 {
|
||||||
|
InitDevToolPageConnection,
|
||||||
|
AllVNodeTreesInfos,
|
||||||
|
RequestComponentAttrs,
|
||||||
|
ComponentAttrs,
|
||||||
|
DevToolPanel,
|
||||||
|
} from './../utils/constants';
|
||||||
import { packagePayload } from './../utils/transferTool';
|
import { packagePayload } from './../utils/transferTool';
|
||||||
|
|
||||||
const parseVNodeData = (rawData) => {
|
const parseVNodeData = (rawData) => {
|
||||||
|
@ -18,7 +24,7 @@ const parseVNodeData = (rawData) => {
|
||||||
const data: IData[] = [];
|
const data: IData[] = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < rawData.length) {
|
while (i < rawData.length) {
|
||||||
const id = rawData[i] as string;
|
const id = rawData[i] as number;
|
||||||
i++;
|
i++;
|
||||||
const name = rawData[i] as string;
|
const name = rawData[i] as string;
|
||||||
i++;
|
i++;
|
||||||
|
@ -53,11 +59,26 @@ const getParents = (item: IData | null, parsedVNodeData: IData[]) => {
|
||||||
return parents;
|
return parents;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let connection;
|
||||||
|
if (!isDev) {
|
||||||
|
// 与 background 的唯一连接
|
||||||
|
connection = chrome.runtime.connect({
|
||||||
|
name: 'panel'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function postMessage(type: string, data: any) {
|
||||||
|
connection.postMessage(packagePayload({
|
||||||
|
type: type,
|
||||||
|
data: data,
|
||||||
|
}, DevToolPanel));
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
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 treeRootInfos = useRef<{id: number, length: number}[]>([]); // 记录保存的根节点 id 和长度,
|
||||||
|
|
||||||
const {
|
const {
|
||||||
filterValue,
|
filterValue,
|
||||||
|
@ -81,30 +102,31 @@ function App() {
|
||||||
props: parsedMockState,
|
props: parsedMockState,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const connection = chrome.runtime.connect({
|
|
||||||
name: 'panel'
|
|
||||||
});
|
|
||||||
// 页面打开后发送初始化请求
|
// 页面打开后发送初始化请求
|
||||||
connection.postMessage(packagePayload({
|
postMessage(InitDevToolPageConnection, chrome.devtools.inspectedWindow.tabId);
|
||||||
type: initDevToolPageConnection,
|
|
||||||
data: chrome.devtools.inspectedWindow.tabId
|
|
||||||
}));
|
|
||||||
// 监听 background消息
|
// 监听 background消息
|
||||||
connection.onMessage.addListener(function (message) {
|
connection.onMessage.addListener(function (message) {
|
||||||
const { payload } = message;
|
const { payload } = message;
|
||||||
if (payload) {
|
if (payload) {
|
||||||
const { type, data } = payload;
|
const { type, data } = payload;
|
||||||
if (type === allVNodeTreesInfos) {
|
if (type === AllVNodeTreesInfos) {
|
||||||
const allTreeData = data.reduce((pre, current) => {
|
const allTreeData = data.reduce((pre, current) => {
|
||||||
const parsedTreeData = parseVNodeData(current);
|
const parsedTreeData = parseVNodeData(current);
|
||||||
const length = parsedTreeData.length;
|
const length = parsedTreeData.length;
|
||||||
|
treeRootInfos.current.length = 0;
|
||||||
if (length) {
|
if (length) {
|
||||||
const treeRoot = parsedTreeData[0];
|
const treeRoot = parsedTreeData[0];
|
||||||
treeRootInfos.current[treeRoot.id] = length;
|
treeRootInfos.current.push({id: treeRoot.id, length: length});
|
||||||
}
|
}
|
||||||
return pre.concat(parsedTreeData);
|
return pre.concat(parsedTreeData);
|
||||||
}, []);
|
}, []);
|
||||||
setParsedVNodeData(allTreeData);
|
setParsedVNodeData(allTreeData);
|
||||||
|
} else if (type === ComponentAttrs) {
|
||||||
|
const {parsedProps, parsedState} = data;
|
||||||
|
setComponentAttrs({
|
||||||
|
state: parsedProps,
|
||||||
|
props: parsedState,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -122,10 +144,7 @@ function App() {
|
||||||
props: parsedMockState,
|
props: parsedMockState,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
connection.postMessage({
|
postMessage(RequestComponentAttrs, item.id);
|
||||||
name: requestComponentAttrs,
|
|
||||||
data: item.id
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setSelectComp(item);
|
setSelectComp(item);
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,6 +57,10 @@ function parseTreeRoot(treeRoot: VNode) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function queryVNode(id: number) {
|
||||||
|
return IdToVNodeMap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
export function deleteVNode(vNode: VNode) {
|
export function deleteVNode(vNode: VNode) {
|
||||||
if (VNodeToIdMap.has(vNode)) {
|
if (VNodeToIdMap.has(vNode)) {
|
||||||
const id = VNodeToIdMap.get(vNode);
|
const id = VNodeToIdMap.get(vNode);
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
// panel 页面打开后初始化连接标志
|
// panel 页面打开后初始化连接标志
|
||||||
export const initDevToolPageConnection = 'init dev tool page connection';
|
export const InitDevToolPageConnection = 'init dev tool page connection';
|
||||||
// background 解析全部 root VNodes 标志
|
// background 解析全部 root VNodes 标志
|
||||||
export const requestAllVNodeTreeInfos = 'request all vNodes tree infos';
|
export const RequestAllVNodeTreeInfos = 'request all vNodes tree infos';
|
||||||
// vNodes 全部树解析结果标志
|
// vNodes 全部树解析结果标志
|
||||||
export const allVNodeTreesInfos = 'vNode trees Infos';
|
export const AllVNodeTreesInfos = 'vNode trees Infos';
|
||||||
// 一棵树的解析
|
// 一棵树的解析
|
||||||
export const oneVNodeTreeInfos = 'one vNode tree';
|
export const OneVNodeTreeInfos = 'one vNode tree';
|
||||||
// 获取组件属性
|
// 获取组件属性
|
||||||
export const requestComponentAttrs = 'get component attrs';
|
export const RequestComponentAttrs = 'get component attrs';
|
||||||
// 返回组件属性
|
// 返回组件属性
|
||||||
export const componentAttrs = 'component attrs';
|
export const ComponentAttrs = 'component attrs';
|
||||||
|
|
||||||
|
|
||||||
|
// 传递消息来源标志
|
||||||
|
export const DevToolPanel = 'dev tool panel';
|
||||||
|
|
||||||
|
export const DevToolBackground = 'dev tool background';
|
||||||
|
|
||||||
|
export const DevToolContentScript = 'dev tool content script';
|
||||||
|
|
||||||
|
export const DevToolHook = 'dev tool hook';
|
|
@ -5,17 +5,28 @@ interface payLoadType {
|
||||||
data?: any,
|
data?: any,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function packagePayload(payload: payLoadType) {
|
interface message {
|
||||||
|
type: typeof devTools,
|
||||||
|
payload: payLoadType,
|
||||||
|
from: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function packagePayload(payload: payLoadType, from: string): message {
|
||||||
return {
|
return {
|
||||||
type: devTools,
|
type: devTools,
|
||||||
payload,
|
payload,
|
||||||
|
from,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkData(data: any) {
|
export function checkMessage(data: any, from: string) {
|
||||||
if (data?.type === devTools) {
|
if (data?.type === devTools && data?.from === from) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function changeSource(message: message, from: string) {
|
||||||
|
message.from = from;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue