您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
使用本脚本支持直接调试生产环境的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();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址