启用 Vue devtools

为所有网站启用 Vue devtools

  1. // ==UserScript==
  2. // @name Vue devtools enabler
  3. // @name:zh-CN 启用 Vue devtools
  4. // @namespace https://greasyfork.org/users/667968-pyudng
  5. // @version 0.1.2
  6. // @description Enable Vue devtools on all websites
  7. // @description:zh-CN 为所有网站启用 Vue devtools
  8. // @author PY-DNG
  9. // @license GPL-3.0-or-later
  10. // @match http*://*/*
  11. // @icon https://cn.vuejs.org/logo.svg
  12. // @grant GM_log
  13. // @run-at document-start
  14. // ==/UserScript==
  15.  
  16. /* eslint-disable no-multi-spaces */
  17. /* eslint-disable no-return-assign */
  18.  
  19. (async function __MAIN__() {
  20. 'use strict';
  21.  
  22. // 获取window
  23. const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
  24.  
  25. // 监听和修改window.__VUE_DEVTOOLS_GLOBAL_HOOK__
  26. const VueDevtoolsGlobalHook = await (function() {
  27. const { promise, resolve } = Promise.withResolvers();
  28. check();
  29. return promise;
  30.  
  31. function check() {
  32. if (win.hasOwnProperty('__VUE_DEVTOOLS_GLOBAL_HOOK__')) {
  33. const VHook = win.__VUE_DEVTOOLS_GLOBAL_HOOK__;
  34. VHook.enabled = true;
  35. resolve(VHook);
  36. } else {
  37. setTimeout(check);
  38. }
  39. }
  40. }) ();
  41.  
  42. // Vue实例处理器
  43. const VueDealer = {
  44. roots: new Set(),
  45.  
  46. vue2: {
  47. connect(app) {
  48. const root = app.$root;
  49. if (VueDealer.roots.has(root)) { return; }
  50.  
  51. let Vue = root.constructor;
  52. while (Vue.super) { Vue = Vue.super; }
  53. Vue.config.devtools = true;
  54. VueDevtoolsGlobalHook.emit("init", Vue);
  55.  
  56. VueDealer.roots.add(root);
  57. },
  58. },
  59.  
  60. vue3: {
  61. connect(app) {
  62. if (VueDealer.roots.has(app)) { return; }
  63. if (!Array.isArray(VueDevtoolsGlobalHook.apps)) { return; }
  64. if (VueDevtoolsGlobalHook.apps.includes(app)) { return; }
  65.  
  66. const version = app.version;
  67. const types = {
  68. Fragment: undefined,
  69. Text: undefined,
  70. Comment: undefined,
  71. Static: undefined
  72. };
  73. VueDevtoolsGlobalHook.emit("app:init", app, version, types);
  74. const unmount = app.unmount;
  75. app.unmount = function() {
  76. VueDevtoolsGlobalHook.emit("app:unmount", app);
  77. unmount.call(app);
  78. };
  79.  
  80. VueDealer.roots.add(app);
  81. }
  82. }
  83. };
  84.  
  85. // 每当DOM变化时,都遍历所有元素,寻找Vue实例
  86. const observer = new MutationObserver(() => {
  87. for (const element of document.querySelectorAll('*')) {
  88. if (element.__vue__?._isVue) {
  89. VueDealer.vue2.connect(element.__vue__);
  90. }
  91. if (element.__vue_app__?.version) {
  92. VueDealer.vue3.connect(element.__vue_app__);
  93. }
  94. }
  95. });
  96. observer.observe(document, {
  97. attributes: true,
  98. childList: true,
  99. subtree: true,
  100. });
  101. }) ();