Vue生产环境(production) Devtools 调试

使用本脚本支持直接调试生产环境的Vue项目 完美支持Vue2、Vue3!

// ==UserScript==
// @name            Vue生产环境(production) Devtools 调试
// @namespace       https://github.com/xcr1234/vue-devtools-production
// @version         2.1.0
// @description     使用本脚本支持直接调试生产环境的Vue项目 完美支持Vue2、Vue3!
// @homepage        https://github.com/xcr1234/vue-devtools-production
// @icon            data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAbpJREFUOE+lkz9IG2EYxp/3Eo1GHWzFDqFKLQ6CIGpLS9GSQzGniw5OLTg6CCLO5kT86FpolnR3kFYXJ+9o2u9EcPEPEdqp4qKlbbaihpxw98n3JUqMqYp+03s87/P7/jzvEe656J5+KIC+ymwQBmR99OGnYgoh1rethdeyfjY4tg6gR9Z1U615HfTFMeIDCtC38u6RH/L/yPo0/S/lrmX6VRfRKAEBIcQn+Vn5on4j9LLhlQL43mNnaO7w4grR1XlGRHEpHn/c3xWu1wHgBwANQBtVaPu1E09bCuAEj8Wn1B7Fb6Bb7ARA2Pud28l+Pugq1sIjke+B5nA7gBw3zOpz7RIgarNREliSYnb5IOX9yqmraA2hzZq3Tc/Vjj4mvg2ZybIA9aAW4wCivutnjpN7NUSk1Y4/yVJ18CGANDfMzuKTXYlRt+e7IWhLNrk8w4WPYFVfY28+GejOoOlcCyjEmgBhsmRGFrlhvimdm7KDFLPmHpwikAEQyBvI01yKfB2e+XsrgDqFzaYh8L5gmOWGyUrNV2IsbdAtlgYQ5IYp4yu7rv0XojYbkQAnZi7fCfA/040p3MZ43nMG7TKHEfrJ20kAAAAASUVORK5CYII=
// @include         *
// @run-at          document-end
// @grant           none
// ==/UserScript==
const v = (e, t) => {
  let o = Object.getPrototypeOf(t).constructor;
  for (; o.super; )
    o = o.super;
  if (!o.config.devtools && (o.config.devtools = !0, e.emit("init", o), console.log(`vue devtools for [${o.version}] already open !!!`), t.$store)) {
    const n = t.$store;
    n._devtoolHook = e, e.emit("vuex:init", n), e.on("vuex:travel-to-state", (s) => {
      n.replaceState(s);
    }), n.subscribe((s, a) => {
      e.emit("vuex:mutation", s, a);
    });
  }
};
/**
* @vue/shared v3.4.33
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/
const N = (e) => typeof e == "symbol";
/**
* @vue/reactivity v3.4.33
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/
new Set(
  /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((e) => e !== "arguments" && e !== "caller").map((e) => Symbol[e]).filter(N)
);
function E(e) {
  const t = e && e.__v_raw;
  return t ? E(t) : e;
}
function C() {
  return I().__VUE_DEVTOOLS_GLOBAL_HOOK__;
}
function I() {
  return typeof navigator < "u" && typeof window < "u" ? window : typeof globalThis < "u" ? globalThis : {};
}
const R = typeof Proxy == "function", U = "devtools-plugin:setup", D = "plugin:settings:set";
let _, h;
function G() {
  var e;
  return _ !== void 0 || (typeof window < "u" && window.performance ? (_ = !0, h = window.performance) : typeof globalThis < "u" && (!((e = globalThis.perf_hooks) === null || e === void 0) && e.performance) ? (_ = !0, h = globalThis.perf_hooks.performance) : _ = !1), _;
}
function F() {
  return G() ? h.now() : Date.now();
}
class M {
  constructor(t, o) {
    this.target = null, this.targetQueue = [], this.onQueue = [], this.plugin = t, this.hook = o;
    const n = {};
    if (t.settings)
      for (const i in t.settings) {
        const r = t.settings[i];
        n[i] = r.defaultValue;
      }
    const s = `__vue-devtools-plugin-settings__${t.id}`;
    let a = Object.assign({}, n);
    try {
      const i = localStorage.getItem(s), r = JSON.parse(i);
      Object.assign(a, r);
    } catch {
    }
    this.fallbacks = {
      getSettings() {
        return a;
      },
      setSettings(i) {
        try {
          localStorage.setItem(s, JSON.stringify(i));
        } catch {
        }
        a = i;
      },
      now() {
        return F();
      }
    }, o && o.on(D, (i, r) => {
      i === this.plugin.id && this.fallbacks.setSettings(r);
    }), this.proxiedOn = new Proxy({}, {
      get: (i, r) => this.target ? this.target.on[r] : (...c) => {
        this.onQueue.push({
          method: r,
          args: c
        });
      }
    }), this.proxiedTarget = new Proxy({}, {
      get: (i, r) => this.target ? this.target[r] : r === "on" ? this.proxiedOn : Object.keys(this.fallbacks).includes(r) ? (...c) => (this.targetQueue.push({
        method: r,
        args: c,
        resolve: () => {
        }
      }), this.fallbacks[r](...c)) : (...c) => new Promise((u) => {
        this.targetQueue.push({
          method: r,
          args: c,
          resolve: u
        });
      })
    });
  }
  async setRealTarget(t) {
    this.target = t;
    for (const o of this.onQueue)
      this.target.on[o.method](...o.args);
    for (const o of this.targetQueue)
      o.resolve(await this.target[o.method](...o.args));
  }
}
function H(e, t) {
  const o = e, n = I(), s = C(), a = R && o.enableEarlyProxy;
  if (s && (n.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !a))
    s.emit(U, e, t);
  else {
    const i = a ? new M(o, s) : null;
    (n.__VUE_DEVTOOLS_PLUGINS__ = n.__VUE_DEVTOOLS_PLUGINS__ || []).push({
      pluginDescriptor: o,
      setupFn: t,
      proxy: i
    }), i && t(i.proxiedTarget);
  }
}
/*!
 * pinia v2.1.7
 * (c) 2023 Eduardo San Martin Morote
 * @license MIT
 */
var b;
(function(e) {
  e.direct = "direct", e.patchObject = "patch object", e.patchFunction = "patch function";
})(b || (b = {}));
const J = typeof window < "u";
const O = typeof window == "object" && window.window === window ? window : typeof self == "object" && self.self === self ? self : typeof global == "object" && global.global === global ? global : typeof globalThis == "object" ? globalThis : { HTMLElement: null };
function B(e, { autoBom: t = !1 } = {}) {
  return t && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type) ? new Blob(["\uFEFF", e], { type: e.type }) : e;
}
function S(e, t, o) {
  const n = new XMLHttpRequest();
  n.open("GET", e), n.responseType = "blob", n.onload = function() {
    x(n.response, t, o);
  }, n.onerror = function() {
    console.error("could not download file");
  }, n.send();
}
function L(e) {
  const t = new XMLHttpRequest();
  t.open("HEAD", e, !1);
  try {
    t.send();
  } catch {
  }
  return t.status >= 200 && t.status <= 299;
}
function g(e) {
  try {
    e.dispatchEvent(new MouseEvent("click"));
  } catch {
    const o = document.createEvent("MouseEvents");
    o.initMouseEvent("click", !0, !0, window, 0, 0, 0, 80, 20, !1, !1, !1, !1, 0, null), e.dispatchEvent(o);
  }
}
const m = typeof navigator == "object" ? navigator : { userAgent: "" }, P = /Macintosh/.test(m.userAgent) && /AppleWebKit/.test(m.userAgent) && !/Safari/.test(m.userAgent), x = J ? (
  // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView or mini program
  typeof HTMLAnchorElement < "u" && "download" in HTMLAnchorElement.prototype && !P ? Q : (
    // Use msSaveOrOpenBlob as a second approach
    "msSaveOrOpenBlob" in m ? K : (
      // Fallback to using FileReader and a popup
      Y
    )
  )
) : () => {
};
function Q(e, t = "download", o) {
  const n = document.createElement("a");
  n.download = t, n.rel = "noopener", typeof e == "string" ? (n.href = e, n.origin !== location.origin ? L(n.href) ? S(e, t, o) : (n.target = "_blank", g(n)) : g(n)) : (n.href = URL.createObjectURL(e), setTimeout(function() {
    URL.revokeObjectURL(n.href);
  }, 4e4), setTimeout(function() {
    g(n);
  }, 0));
}
function K(e, t = "download", o) {
  if (typeof e == "string")
    if (L(e))
      S(e, t, o);
    else {
      const n = document.createElement("a");
      n.href = e, n.target = "_blank", setTimeout(function() {
        g(n);
      });
    }
  else
    navigator.msSaveOrOpenBlob(B(e, o), t);
}
function Y(e, t, o, n) {
  if (n = n || open("", "_blank"), n && (n.document.title = n.document.body.innerText = "downloading..."), typeof e == "string")
    return S(e, t, o);
  const s = e.type === "application/octet-stream", a = /constructor/i.test(String(O.HTMLElement)) || "safari" in O, i = /CriOS\/[\d]+/.test(navigator.userAgent);
  if ((i || s && a || P) && typeof FileReader < "u") {
    const r = new FileReader();
    r.onloadend = function() {
      let c = r.result;
      if (typeof c != "string")
        throw n = null, new Error("Wrong reader.result type");
      c = i ? c : c.replace(/^data:[^;]*;/, "data:attachment/file;"), n ? n.location.href = c : location.assign(c), n = null;
    }, r.readAsDataURL(e);
  } else {
    const r = URL.createObjectURL(e);
    n ? n.location.assign(r) : location.href = r, n = null, setTimeout(function() {
      URL.revokeObjectURL(r);
    }, 4e4);
  }
}
function l(e, t) {
  const o = "🍍 " + e;
  typeof __VUE_DEVTOOLS_TOAST__ == "function" ? __VUE_DEVTOOLS_TOAST__(o, t) : t === "error" ? console.error(o) : t === "warn" ? console.warn(o) : console.log(o);
}
function w(e) {
  return "_a" in e && "install" in e;
}
function A() {
  if (!("clipboard" in navigator))
    return l("Your browser doesn't support the Clipboard API", "error"), !0;
}
function $(e) {
  return e instanceof Error && e.message.toLowerCase().includes("document is not focused") ? (l('You need to activate the "Emulate a focused page" setting in the "Rendering" panel of devtools.', "warn"), !0) : !1;
}
async function z(e) {
  if (!A())
    try {
      await navigator.clipboard.writeText(JSON.stringify(e.state.value)), l("Global state copied to clipboard.");
    } catch (t) {
      if ($(t))
        return;
      l("Failed to serialize the state. Check the console for more details.", "error"), console.error(t);
    }
}
async function W(e) {
  if (!A())
    try {
      k(e, JSON.parse(await navigator.clipboard.readText())), l("Global state pasted from clipboard.");
    } catch (t) {
      if ($(t))
        return;
      l("Failed to deserialize the state from clipboard. Check the console for more details.", "error"), console.error(t);
    }
}
async function q(e) {
  try {
    x(new Blob([JSON.stringify(e.state.value)], {
      type: "text/plain;charset=utf-8"
    }), "pinia-state.json");
  } catch (t) {
    l("Failed to export the state as JSON. Check the console for more details.", "error"), console.error(t);
  }
}
let f;
function X() {
  f || (f = document.createElement("input"), f.type = "file", f.accept = ".json");
  function e() {
    return new Promise((t, o) => {
      f.onchange = async () => {
        const n = f.files;
        if (!n)
          return t(null);
        const s = n.item(0);
        return t(s ? { text: await s.text(), file: s } : null);
      }, f.oncancel = () => t(null), f.onerror = o, f.click();
    });
  }
  return e;
}
async function Z(e) {
  try {
    const o = await X()();
    if (!o)
      return;
    const { text: n, file: s } = o;
    k(e, JSON.parse(n)), l(`Global state imported from "${s.name}".`);
  } catch (t) {
    l("Failed to import the state from JSON. Check the console for more details.", "error"), console.error(t);
  }
}
function k(e, t) {
  for (const o in t) {
    const n = e.state.value[o];
    n ? Object.assign(n, t[o]) : e.state.value[o] = t[o];
  }
}
const j = "🍍 Pinia (root)", p = "_root";
function ee(e) {
  return w(e) ? {
    id: p,
    label: j
  } : {
    id: e.$id,
    label: e.$id
  };
}
function te(e) {
  if (w(e)) {
    const o = Array.from(e._s.keys()), n = e._s;
    return {
      state: o.map((a) => ({
        editable: !0,
        key: a,
        value: e.state.value[a]
      })),
      getters: o.filter((a) => n.get(a)._getters).map((a) => {
        const i = n.get(a);
        return {
          editable: !1,
          key: a,
          value: i._getters.reduce((r, c) => (r[c] = i[c], r), {})
        };
      })
    };
  }
  const t = {
    state: Object.keys(e.$state).map((o) => ({
      editable: !0,
      key: o,
      value: e.$state[o]
    }))
  };
  return e._getters && e._getters.length && (t.getters = e._getters.map((o) => ({
    editable: !1,
    key: o,
    value: e[o]
  }))), e._customProperties.size && (t.customProperties = Array.from(e._customProperties).map((o) => ({
    editable: !0,
    key: o,
    value: e[o]
  }))), t;
}
const ne = [], oe = "pinia:mutations", d = "pinia", y = (e) => "🍍 " + e;
function re(e, t) {
  H({
    id: "dev.esm.pinia",
    label: "Pinia 🍍",
    logo: "https://pinia.vuejs.org/logo.svg",
    packageName: "pinia",
    homepage: "https://pinia.vuejs.org",
    componentStateTypes: ne,
    app: e
  }, (o) => {
    typeof o.now != "function" && l("You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html."), o.addTimelineLayer({
      id: oe,
      label: "Pinia 🍍",
      color: 15064968
    }), o.addInspector({
      id: d,
      label: "Pinia 🍍",
      icon: "storage",
      treeFilterPlaceholder: "Search stores",
      actions: [
        {
          icon: "content_copy",
          action: () => {
            z(t);
          },
          tooltip: "Serialize and copy the state"
        },
        {
          icon: "content_paste",
          action: async () => {
            await W(t), o.sendInspectorTree(d), o.sendInspectorState(d);
          },
          tooltip: "Replace the state with the content of your clipboard"
        },
        {
          icon: "save",
          action: () => {
            q(t);
          },
          tooltip: "Save the state as a JSON file"
        },
        {
          icon: "folder_open",
          action: async () => {
            await Z(t), o.sendInspectorTree(d), o.sendInspectorState(d);
          },
          tooltip: "Import the state from a JSON file"
        }
      ],
      nodeActions: [
        {
          icon: "restore",
          tooltip: 'Reset the state (with "$reset")',
          action: (n) => {
            const s = t._s.get(n);
            s ? typeof s.$reset != "function" ? l(`Cannot reset "${n}" store because it doesn't have a "$reset" method implemented.`, "warn") : (s.$reset(), l(`Store "${n}" reset.`)) : l(`Cannot reset "${n}" store because it wasn't found.`, "warn");
          }
        }
      ]
    }), o.on.inspectComponent((n, s) => {
      const a = n.componentInstance && n.componentInstance.proxy;
      if (a && a._pStores) {
        const i = n.componentInstance.proxy._pStores;
        Object.values(i).forEach((r) => {
          n.instanceData.state.push({
            type: y(r.$id),
            key: "state",
            editable: !0,
            value: r._isOptionsAPI ? {
              _custom: {
                value: E(r.$state),
                actions: [
                  {
                    icon: "restore",
                    tooltip: "Reset the state of this store",
                    action: () => r.$reset()
                  }
                ]
              }
            } : (
              // NOTE: workaround to unwrap transferred refs
              Object.keys(r.$state).reduce((c, u) => (c[u] = r.$state[u], c), {})
            )
          }), r._getters && r._getters.length && n.instanceData.state.push({
            type: y(r.$id),
            key: "getters",
            editable: !1,
            value: r._getters.reduce((c, u) => {
              try {
                c[u] = r[u];
              } catch (V) {
                c[u] = V;
              }
              return c;
            }, {})
          });
        });
      }
    }), o.on.getInspectorTree((n) => {
      if (n.app === e && n.inspectorId === d) {
        let s = [t];
        s = s.concat(Array.from(t._s.values())), n.rootNodes = (n.filter ? s.filter((a) => "$id" in a ? a.$id.toLowerCase().includes(n.filter.toLowerCase()) : j.toLowerCase().includes(n.filter.toLowerCase())) : s).map(ee);
      }
    }), o.on.getInspectorState((n) => {
      if (n.app === e && n.inspectorId === d) {
        const s = n.nodeId === p ? t : t._s.get(n.nodeId);
        if (!s)
          return;
        s && (n.state = te(s));
      }
    }), o.on.editInspectorState((n, s) => {
      if (n.app === e && n.inspectorId === d) {
        const a = n.nodeId === p ? t : t._s.get(n.nodeId);
        if (!a)
          return l(`store "${n.nodeId}" not found`, "error");
        const { path: i } = n;
        w(a) ? i.unshift("state") : (i.length !== 1 || !a._customProperties.has(i[0]) || i[0] in a.$state) && i.unshift("$state"), n.set(a, i, n.state.value);
      }
    }), o.on.editComponentState((n) => {
      if (n.type.startsWith("🍍")) {
        const s = n.type.replace(/^🍍\s*/, ""), a = t._s.get(s);
        if (!a)
          return l(`store "${s}" not found`, "error");
        const { path: i } = n;
        if (i[0] !== "state")
          return l(`Invalid path for store "${s}":
${i}
Only state can be modified.`);
        i[0] = "$state", n.set(a, i, n.state.value);
      }
    });
  });
}
const se = (e) => {
  e.includes("-alpha.") && (e = e.split("-alpha.")[0]);
  const [t, o] = e.split(".").map(Number);
  return t > 3 || t === 3 && o >= 3;
}, T = (e, t) => {
  if (t.config.devtools)
    return;
  t.config.devtools = !0, se(t.version) ? e.emit("app:init", t, t.version, {
    Fragment: Symbol.for("v-fgt"),
    Text: Symbol.for("v-txt"),
    Comment: Symbol.for("v-cmt"),
    Static: Symbol.for("v-stc")
  }) : e.emit("app:init", t, t.version, {
    Fragment: Symbol.for("Fragment"),
    Text: Symbol.for("Text"),
    Comment: Symbol.for("Comment"),
    Static: Symbol.for("Static")
  }), console.log(`vue devtools for [${t.version}] already open !!!`);
  const o = t.unmount.bind(t);
  t.unmount = () => {
    e.emit("app:unmount", t), o();
  }, t.config.globalProperties.$store && console.warn("vuex for vue3 not support. please use pinia");
  const n = t.config.globalProperties.$pinia;
  n && re(t, n);
}, ie = () => {
  if (self != top)
    return;
  const e = window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
  if (!e) {
    console.warn("No Vue devtools found , Please install it first: "), console.warn("see https://github.com/vuejs/vue-devtools");
    return;
  }
  const t = window.app;
  if (!t)
    return;
  if (t.__vue__) {
    v(e, t.__vue__);
    return;
  }
  if (t.__vue_app__) {
    T(e, t.__vue_app__);
    return;
  }
  new MutationObserver((n, s) => {
    const a = s.disconnect.bind(s);
    for (const i of n) {
      const r = i.target;
      r.__vue__ ? (v(e, r.__vue__), a()) : r.__vue_app__ && (T(e, r.__vue_app__), a());
    }
  }).observe(document.documentElement, {
    attributes: !0,
    subtree: !0,
    childList: !0
  });
};
ie();