市场夺宝奇兵
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

535 lines
17 KiB

  1. import { isBrowser, target } from "@vue/devtools-shared";
  2. import { DevToolsContextHookKeys, DevToolsMessagingHookKeys, createRpcClient, createRpcServer, devtools, devtoolsRouter, devtoolsRouterInfo, getActiveInspectors, getInspector, getInspectorActions, getInspectorInfo, getInspectorNodeActions, getRpcClient, getRpcServer, getViteRpcClient, stringify, toggleClientConnected, updateDevToolsClientDetected, updateTimelineLayersState } from "@vue/devtools-kit";
  3. import { computed, inject, onUnmounted, ref, watch } from "vue";
  4. //#region src/client.ts
  5. function setDevToolsClientUrl(url) {
  6. target.__VUE_DEVTOOLS_CLIENT_URL__ = url;
  7. }
  8. function getDevToolsClientUrl() {
  9. return target.__VUE_DEVTOOLS_CLIENT_URL__ ?? (() => {
  10. if (isBrowser) {
  11. const devtoolsMeta = document.querySelector("meta[name=__VUE_DEVTOOLS_CLIENT_URL__]");
  12. if (devtoolsMeta) return devtoolsMeta.getAttribute("content");
  13. }
  14. return "";
  15. })();
  16. }
  17. //#endregion
  18. //#region ../../node_modules/.pnpm/hookable@5.5.3/node_modules/hookable/dist/index.mjs
  19. function flatHooks(configHooks, hooks$2 = {}, parentName) {
  20. for (const key in configHooks) {
  21. const subHook = configHooks[key];
  22. const name = parentName ? `${parentName}:${key}` : key;
  23. if (typeof subHook === "object" && subHook !== null) flatHooks(subHook, hooks$2, name);
  24. else if (typeof subHook === "function") hooks$2[name] = subHook;
  25. }
  26. return hooks$2;
  27. }
  28. const defaultTask = { run: (function_) => function_() };
  29. const _createTask = () => defaultTask;
  30. const createTask = typeof console.createTask !== "undefined" ? console.createTask : _createTask;
  31. function serialTaskCaller(hooks$2, args) {
  32. const name = args.shift();
  33. const task = createTask(name);
  34. return hooks$2.reduce((promise, hookFunction) => promise.then(() => task.run(() => hookFunction(...args))), Promise.resolve());
  35. }
  36. function parallelTaskCaller(hooks$2, args) {
  37. const name = args.shift();
  38. const task = createTask(name);
  39. return Promise.all(hooks$2.map((hook) => task.run(() => hook(...args))));
  40. }
  41. function callEachWith(callbacks, arg0) {
  42. for (const callback of [...callbacks]) callback(arg0);
  43. }
  44. var Hookable = class {
  45. constructor() {
  46. this._hooks = {};
  47. this._before = void 0;
  48. this._after = void 0;
  49. this._deprecatedMessages = void 0;
  50. this._deprecatedHooks = {};
  51. this.hook = this.hook.bind(this);
  52. this.callHook = this.callHook.bind(this);
  53. this.callHookWith = this.callHookWith.bind(this);
  54. }
  55. hook(name, function_, options = {}) {
  56. if (!name || typeof function_ !== "function") return () => {};
  57. const originalName = name;
  58. let dep;
  59. while (this._deprecatedHooks[name]) {
  60. dep = this._deprecatedHooks[name];
  61. name = dep.to;
  62. }
  63. if (dep && !options.allowDeprecated) {
  64. let message = dep.message;
  65. if (!message) message = `${originalName} hook has been deprecated` + (dep.to ? `, please use ${dep.to}` : "");
  66. if (!this._deprecatedMessages) this._deprecatedMessages = /* @__PURE__ */ new Set();
  67. if (!this._deprecatedMessages.has(message)) {
  68. console.warn(message);
  69. this._deprecatedMessages.add(message);
  70. }
  71. }
  72. if (!function_.name) try {
  73. Object.defineProperty(function_, "name", {
  74. get: () => "_" + name.replace(/\W+/g, "_") + "_hook_cb",
  75. configurable: true
  76. });
  77. } catch {}
  78. this._hooks[name] = this._hooks[name] || [];
  79. this._hooks[name].push(function_);
  80. return () => {
  81. if (function_) {
  82. this.removeHook(name, function_);
  83. function_ = void 0;
  84. }
  85. };
  86. }
  87. hookOnce(name, function_) {
  88. let _unreg;
  89. let _function = (...arguments_) => {
  90. if (typeof _unreg === "function") _unreg();
  91. _unreg = void 0;
  92. _function = void 0;
  93. return function_(...arguments_);
  94. };
  95. _unreg = this.hook(name, _function);
  96. return _unreg;
  97. }
  98. removeHook(name, function_) {
  99. if (this._hooks[name]) {
  100. const index = this._hooks[name].indexOf(function_);
  101. if (index !== -1) this._hooks[name].splice(index, 1);
  102. if (this._hooks[name].length === 0) delete this._hooks[name];
  103. }
  104. }
  105. deprecateHook(name, deprecated) {
  106. this._deprecatedHooks[name] = typeof deprecated === "string" ? { to: deprecated } : deprecated;
  107. const _hooks = this._hooks[name] || [];
  108. delete this._hooks[name];
  109. for (const hook of _hooks) this.hook(name, hook);
  110. }
  111. deprecateHooks(deprecatedHooks) {
  112. Object.assign(this._deprecatedHooks, deprecatedHooks);
  113. for (const name in deprecatedHooks) this.deprecateHook(name, deprecatedHooks[name]);
  114. }
  115. addHooks(configHooks) {
  116. const hooks$2 = flatHooks(configHooks);
  117. const removeFns = Object.keys(hooks$2).map((key) => this.hook(key, hooks$2[key]));
  118. return () => {
  119. for (const unreg of removeFns.splice(0, removeFns.length)) unreg();
  120. };
  121. }
  122. removeHooks(configHooks) {
  123. const hooks$2 = flatHooks(configHooks);
  124. for (const key in hooks$2) this.removeHook(key, hooks$2[key]);
  125. }
  126. removeAllHooks() {
  127. for (const key in this._hooks) delete this._hooks[key];
  128. }
  129. callHook(name, ...arguments_) {
  130. arguments_.unshift(name);
  131. return this.callHookWith(serialTaskCaller, name, ...arguments_);
  132. }
  133. callHookParallel(name, ...arguments_) {
  134. arguments_.unshift(name);
  135. return this.callHookWith(parallelTaskCaller, name, ...arguments_);
  136. }
  137. callHookWith(caller, name, ...arguments_) {
  138. const event = this._before || this._after ? {
  139. name,
  140. args: arguments_,
  141. context: {}
  142. } : void 0;
  143. if (this._before) callEachWith(this._before, event);
  144. const result = caller(name in this._hooks ? [...this._hooks[name]] : [], arguments_);
  145. if (result instanceof Promise) return result.finally(() => {
  146. if (this._after && event) callEachWith(this._after, event);
  147. });
  148. if (this._after && event) callEachWith(this._after, event);
  149. return result;
  150. }
  151. beforeEach(function_) {
  152. this._before = this._before || [];
  153. this._before.push(function_);
  154. return () => {
  155. if (this._before !== void 0) {
  156. const index = this._before.indexOf(function_);
  157. if (index !== -1) this._before.splice(index, 1);
  158. }
  159. };
  160. }
  161. afterEach(function_) {
  162. this._after = this._after || [];
  163. this._after.push(function_);
  164. return () => {
  165. if (this._after !== void 0) {
  166. const index = this._after.indexOf(function_);
  167. if (index !== -1) this._after.splice(index, 1);
  168. }
  169. };
  170. }
  171. };
  172. function createHooks() {
  173. return new Hookable();
  174. }
  175. //#endregion
  176. //#region src/rpc/global.ts
  177. const hooks$1 = createHooks();
  178. let DevToolsMessagingEvents = /* @__PURE__ */ function(DevToolsMessagingEvents$1) {
  179. DevToolsMessagingEvents$1["INSPECTOR_TREE_UPDATED"] = "inspector-tree-updated";
  180. DevToolsMessagingEvents$1["INSPECTOR_STATE_UPDATED"] = "inspector-state-updated";
  181. DevToolsMessagingEvents$1["DEVTOOLS_STATE_UPDATED"] = "devtools-state-updated";
  182. DevToolsMessagingEvents$1["ROUTER_INFO_UPDATED"] = "router-info-updated";
  183. DevToolsMessagingEvents$1["TIMELINE_EVENT_UPDATED"] = "timeline-event-updated";
  184. DevToolsMessagingEvents$1["INSPECTOR_UPDATED"] = "inspector-updated";
  185. DevToolsMessagingEvents$1["ACTIVE_APP_UNMOUNTED"] = "active-app-updated";
  186. DevToolsMessagingEvents$1["DESTROY_DEVTOOLS_CLIENT"] = "destroy-devtools-client";
  187. DevToolsMessagingEvents$1["RELOAD_DEVTOOLS_CLIENT"] = "reload-devtools-client";
  188. return DevToolsMessagingEvents$1;
  189. }({});
  190. function getDevToolsState() {
  191. const state = devtools.ctx.state;
  192. return {
  193. connected: state.connected,
  194. clientConnected: true,
  195. vueVersion: state?.activeAppRecord?.version || "",
  196. tabs: state.tabs,
  197. commands: state.commands,
  198. vitePluginDetected: state.vitePluginDetected,
  199. appRecords: state.appRecords.map((item) => ({
  200. id: item.id,
  201. name: item.name,
  202. version: item.version,
  203. routerId: item.routerId,
  204. iframe: item.iframe
  205. })),
  206. activeAppRecordId: state.activeAppRecordId,
  207. timelineLayersState: state.timelineLayersState
  208. };
  209. }
  210. const functions = {
  211. on: (event, handler) => {
  212. hooks$1.hook(event, handler);
  213. },
  214. off: (event, handler) => {
  215. hooks$1.removeHook(event, handler);
  216. },
  217. once: (event, handler) => {
  218. hooks$1.hookOnce(event, handler);
  219. },
  220. emit: (event, ...args) => {
  221. hooks$1.callHook(event, ...args);
  222. },
  223. heartbeat: () => {
  224. return true;
  225. },
  226. devtoolsState: () => {
  227. return getDevToolsState();
  228. },
  229. async getInspectorTree(payload) {
  230. const res = await devtools.ctx.api.getInspectorTree(payload);
  231. return stringify(res);
  232. },
  233. async getInspectorState(payload) {
  234. const inspector = getInspector(payload.inspectorId);
  235. if (inspector) inspector.selectedNodeId = payload.nodeId;
  236. const res = await devtools.ctx.api.getInspectorState(payload);
  237. return stringify(res);
  238. },
  239. async editInspectorState(payload) {
  240. return await devtools.ctx.api.editInspectorState(payload);
  241. },
  242. sendInspectorState(id) {
  243. return devtools.ctx.api.sendInspectorState(id);
  244. },
  245. inspectComponentInspector() {
  246. return devtools.ctx.api.inspectComponentInspector();
  247. },
  248. cancelInspectComponentInspector() {
  249. return devtools.ctx.api.cancelInspectComponentInspector();
  250. },
  251. getComponentRenderCode(id) {
  252. return devtools.ctx.api.getComponentRenderCode(id);
  253. },
  254. scrollToComponent(id) {
  255. return devtools.ctx.api.scrollToComponent(id);
  256. },
  257. inspectDOM(id) {
  258. return devtools.ctx.api.inspectDOM(id);
  259. },
  260. getInspectorNodeActions(id) {
  261. return getInspectorNodeActions(id);
  262. },
  263. getInspectorActions(id) {
  264. return getInspectorActions(id);
  265. },
  266. updateTimelineLayersState(state) {
  267. return updateTimelineLayersState(state);
  268. },
  269. callInspectorNodeAction(inspectorId, actionIndex, nodeId) {
  270. const nodeActions = getInspectorNodeActions(inspectorId);
  271. if (nodeActions?.length) nodeActions[actionIndex].action?.(nodeId);
  272. },
  273. callInspectorAction(inspectorId, actionIndex) {
  274. const actions = getInspectorActions(inspectorId);
  275. if (actions?.length) actions[actionIndex].action?.();
  276. },
  277. openInEditor(options) {
  278. return devtools.ctx.api.openInEditor(options);
  279. },
  280. async checkVueInspectorDetected() {
  281. return !!await devtools.ctx.api.getVueInspector();
  282. },
  283. async enableVueInspector() {
  284. const inspector = await devtools?.api?.getVueInspector?.();
  285. if (inspector) await inspector.enable();
  286. },
  287. async toggleApp(id, options) {
  288. return devtools.ctx.api.toggleApp(id, options);
  289. },
  290. updatePluginSettings(pluginId, key, value) {
  291. return devtools.ctx.api.updatePluginSettings(pluginId, key, value);
  292. },
  293. getPluginSettings(pluginId) {
  294. return devtools.ctx.api.getPluginSettings(pluginId);
  295. },
  296. getRouterInfo() {
  297. return devtoolsRouterInfo;
  298. },
  299. navigate(path) {
  300. return devtoolsRouter.value?.push(path).catch(() => ({}));
  301. },
  302. getMatchedRoutes(path) {
  303. const c = console.warn;
  304. console.warn = () => {};
  305. const matched = devtoolsRouter.value?.resolve?.({ path: path || "/" }).matched ?? [];
  306. console.warn = c;
  307. return matched;
  308. },
  309. toggleClientConnected(state) {
  310. toggleClientConnected(state);
  311. },
  312. getCustomInspector() {
  313. return getActiveInspectors();
  314. },
  315. getInspectorInfo(id) {
  316. return getInspectorInfo(id);
  317. },
  318. highlighComponent(uid) {
  319. return devtools.ctx.hooks.callHook(DevToolsContextHookKeys.COMPONENT_HIGHLIGHT, { uid });
  320. },
  321. unhighlight() {
  322. return devtools.ctx.hooks.callHook(DevToolsContextHookKeys.COMPONENT_UNHIGHLIGHT);
  323. },
  324. updateDevToolsClientDetected(params) {
  325. updateDevToolsClientDetected(params);
  326. },
  327. initDevToolsServerListener() {
  328. const broadcast = getRpcServer().broadcast;
  329. devtools.ctx.hooks.hook(DevToolsMessagingHookKeys.SEND_INSPECTOR_TREE_TO_CLIENT, (payload) => {
  330. broadcast.emit(DevToolsMessagingEvents.INSPECTOR_TREE_UPDATED, stringify(payload));
  331. });
  332. devtools.ctx.hooks.hook(DevToolsMessagingHookKeys.SEND_INSPECTOR_STATE_TO_CLIENT, (payload) => {
  333. broadcast.emit(DevToolsMessagingEvents.INSPECTOR_STATE_UPDATED, stringify(payload));
  334. });
  335. devtools.ctx.hooks.hook(DevToolsMessagingHookKeys.DEVTOOLS_STATE_UPDATED, () => {
  336. broadcast.emit(DevToolsMessagingEvents.DEVTOOLS_STATE_UPDATED, getDevToolsState());
  337. });
  338. devtools.ctx.hooks.hook(DevToolsMessagingHookKeys.ROUTER_INFO_UPDATED, ({ state }) => {
  339. broadcast.emit(DevToolsMessagingEvents.ROUTER_INFO_UPDATED, state);
  340. });
  341. devtools.ctx.hooks.hook(DevToolsMessagingHookKeys.SEND_TIMELINE_EVENT_TO_CLIENT, (payload) => {
  342. broadcast.emit(DevToolsMessagingEvents.TIMELINE_EVENT_UPDATED, stringify(payload));
  343. });
  344. devtools.ctx.hooks.hook(DevToolsMessagingHookKeys.SEND_INSPECTOR_TO_CLIENT, (payload) => {
  345. broadcast.emit(DevToolsMessagingEvents.INSPECTOR_UPDATED, payload);
  346. });
  347. devtools.ctx.hooks.hook(DevToolsMessagingHookKeys.SEND_ACTIVE_APP_UNMOUNTED_TO_CLIENT, () => {
  348. broadcast.emit(DevToolsMessagingEvents.ACTIVE_APP_UNMOUNTED);
  349. });
  350. }
  351. };
  352. const rpc = new Proxy({
  353. value: {},
  354. functions: {}
  355. }, { get(target$1, property) {
  356. const _rpc = getRpcClient();
  357. if (property === "value") return _rpc;
  358. else if (property === "functions") return _rpc.$functions;
  359. } });
  360. const rpcServer = new Proxy({
  361. value: {},
  362. functions: {}
  363. }, { get(target$1, property) {
  364. const _rpc = getRpcServer();
  365. if (property === "value") return _rpc;
  366. else if (property === "functions") return _rpc.functions;
  367. } });
  368. function onRpcConnected(callback) {
  369. let timer = null;
  370. let retryCount = 0;
  371. function heartbeat() {
  372. rpc.value?.heartbeat?.().then(() => {
  373. callback();
  374. clearTimeout(timer);
  375. }).catch(() => {});
  376. }
  377. timer = setInterval(() => {
  378. if (retryCount >= 30) clearTimeout(timer);
  379. retryCount++;
  380. heartbeat();
  381. }, retryCount * 200 + 200);
  382. heartbeat();
  383. }
  384. function onRpcSeverReady(callback) {
  385. let timer = null;
  386. const timeout = 120;
  387. function heartbeat() {
  388. if (rpcServer.value.clients.length > 0) {
  389. callback();
  390. clearTimeout(timer);
  391. }
  392. }
  393. timer = setInterval(() => {
  394. heartbeat();
  395. }, timeout);
  396. }
  397. //#endregion
  398. //#region src/rpc/vite.ts
  399. const hooks = createHooks();
  400. const viteRpcFunctions = {
  401. on: (event, handler) => {
  402. hooks.hook(event, handler);
  403. },
  404. off: (event, handler) => {
  405. hooks.removeHook(event, handler);
  406. },
  407. once: (event, handler) => {
  408. hooks.hookOnce(event, handler);
  409. },
  410. emit: (event, ...args) => {
  411. hooks.callHook(event, ...args);
  412. },
  413. heartbeat: () => {
  414. return true;
  415. }
  416. };
  417. const viteRpc = new Proxy({
  418. value: {},
  419. functions: {}
  420. }, { get(target$1, property) {
  421. const _rpc = getViteRpcClient();
  422. if (property === "value") return _rpc;
  423. else if (property === "functions") return _rpc?.$functions;
  424. } });
  425. function onViteRpcConnected(callback) {
  426. let timer = null;
  427. function heartbeat() {
  428. viteRpc.value?.heartbeat?.().then(() => {
  429. clearTimeout(timer);
  430. callback();
  431. }).catch(() => ({}));
  432. timer = setTimeout(() => {
  433. heartbeat();
  434. }, 80);
  435. }
  436. heartbeat();
  437. }
  438. function createViteClientRpc() {
  439. createRpcClient(viteRpcFunctions, { preset: "vite" });
  440. }
  441. function createViteServerRpc(functions$1) {
  442. createRpcServer(functions$1, { preset: "vite" });
  443. }
  444. //#endregion
  445. //#region src/vue-plugin/devtools-state.ts
  446. const VueDevToolsStateSymbol = Symbol.for("__VueDevToolsStateSymbol__");
  447. function VueDevToolsVuePlugin() {
  448. return { install(app) {
  449. const state = createDevToolsStateContext();
  450. state.getDevToolsState();
  451. app.provide(VueDevToolsStateSymbol, state);
  452. app.config.globalProperties.$getDevToolsState = state.getDevToolsState;
  453. app.config.globalProperties.$disconnectDevToolsClient = () => {
  454. state.clientConnected.value = false;
  455. state.connected.value = false;
  456. };
  457. } };
  458. }
  459. function createDevToolsStateContext() {
  460. const connected = ref(false);
  461. const clientConnected = ref(false);
  462. const vueVersion = ref("");
  463. const tabs = ref([]);
  464. const commands = ref([]);
  465. const vitePluginDetected = ref(false);
  466. const appRecords = ref([]);
  467. const activeAppRecordId = ref("");
  468. const timelineLayersState = ref({});
  469. function updateState(data) {
  470. connected.value = data.connected;
  471. clientConnected.value = data.clientConnected;
  472. vueVersion.value = data.vueVersion || "";
  473. tabs.value = data.tabs;
  474. commands.value = data.commands;
  475. vitePluginDetected.value = data.vitePluginDetected;
  476. appRecords.value = data.appRecords;
  477. activeAppRecordId.value = data.activeAppRecordId;
  478. timelineLayersState.value = data.timelineLayersState;
  479. }
  480. function getDevToolsState$1() {
  481. onRpcConnected(() => {
  482. rpc.value.devtoolsState().then((data) => {
  483. updateState(data);
  484. });
  485. rpc.functions.off(DevToolsMessagingEvents.DEVTOOLS_STATE_UPDATED, updateState);
  486. rpc.functions.on(DevToolsMessagingEvents.DEVTOOLS_STATE_UPDATED, updateState);
  487. });
  488. }
  489. return {
  490. getDevToolsState: getDevToolsState$1,
  491. connected,
  492. clientConnected,
  493. vueVersion,
  494. tabs,
  495. commands,
  496. vitePluginDetected,
  497. appRecords,
  498. activeAppRecordId,
  499. timelineLayersState
  500. };
  501. }
  502. function useDevToolsState() {
  503. return inject(VueDevToolsStateSymbol);
  504. }
  505. const fns = [];
  506. function onDevToolsConnected(fn) {
  507. const { connected, clientConnected } = useDevToolsState();
  508. fns.push(fn);
  509. onUnmounted(() => {
  510. fns.splice(fns.indexOf(fn), 1);
  511. });
  512. const devtoolsReady = computed(() => clientConnected.value && connected.value);
  513. if (devtoolsReady.value) fn();
  514. else {
  515. const stop = watch(devtoolsReady, (v) => {
  516. if (v) {
  517. fn();
  518. stop();
  519. }
  520. });
  521. }
  522. return () => {
  523. fns.splice(fns.indexOf(fn), 1);
  524. };
  525. }
  526. function refreshCurrentPageData() {
  527. fns.forEach((fn) => fn());
  528. }
  529. //#endregion
  530. export { DevToolsMessagingEvents, VueDevToolsVuePlugin, createDevToolsStateContext, createViteClientRpc, createViteServerRpc, functions, getDevToolsClientUrl, onDevToolsConnected, onRpcConnected, onRpcSeverReady, onViteRpcConnected, refreshCurrentPageData, rpc, rpcServer, setDevToolsClientUrl, useDevToolsState, viteRpc, viteRpcFunctions };