@keyblade/vite-plugin-vue-pro 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -8,7 +8,11 @@ export interface LogPageRouteOptions {
|
|
|
8
8
|
/**
|
|
9
9
|
* 开发环境下,在控制台输出当前访问页面对应的源码文件路径(可点击跳转)。
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* 优先方案:前端读取 vue-router 当前匹配组件的 `__file`(@vitejs/plugin-vue 在 dev 注入的真实源码路径)
|
|
12
|
+
* 直接上报,服务端原样打印——可精确处理动态参数、URL 编码、任意嵌套等所有情况。
|
|
13
|
+
*
|
|
14
|
+
* 兜底方案:当拿不到 `__file` 时(如未用 vue-router、挂载结构特殊),前端上报路由字符串,
|
|
15
|
+
* 服务端按约定推断 `.vue` 文件:先试 `<route>/index.vue` 与 `<route>.vue`,
|
|
16
|
+
* 再把末段连字符当作潜在目录分隔符尝试,并逐级回退末尾段以应对动态参数。
|
|
13
17
|
*/
|
|
14
18
|
export default function logPageRoute(options?: LogPageRouteOptions): Plugin;
|
|
@@ -1,71 +1,132 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
const
|
|
4
|
-
function
|
|
5
|
-
const { basePath:
|
|
6
|
-
let
|
|
7
|
-
function
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import T from "node:fs";
|
|
2
|
+
import i from "node:path";
|
|
3
|
+
const w = "POST";
|
|
4
|
+
function P(h) {
|
|
5
|
+
const { basePath: c = "src/views", outputPrefix: p = "web" } = h || {};
|
|
6
|
+
let d = "";
|
|
7
|
+
function l(e) {
|
|
8
|
+
const t = e.replace(/\\/g, "/");
|
|
9
|
+
return p ? i.join(p, t).replace(/\\/g, "/") : t;
|
|
10
|
+
}
|
|
11
|
+
function f(e) {
|
|
12
|
+
for (const t of e) {
|
|
13
|
+
const o = i.resolve(process.cwd(), t);
|
|
14
|
+
if (T.existsSync(o))
|
|
15
|
+
return t.replace(/\\/g, "/");
|
|
13
16
|
}
|
|
14
17
|
return "";
|
|
15
18
|
}
|
|
19
|
+
function g(e) {
|
|
20
|
+
if (!e) return "";
|
|
21
|
+
const t = i.isAbsolute(e) ? i.relative(process.cwd(), e) : e;
|
|
22
|
+
return t.startsWith("..") ? e.replace(/\\/g, "/") : l(t);
|
|
23
|
+
}
|
|
24
|
+
function m(e, t) {
|
|
25
|
+
const o = [
|
|
26
|
+
i.join(c, e, t, "index.vue"),
|
|
27
|
+
i.join(c, e, `${t}.vue`)
|
|
28
|
+
], r = t.split("-");
|
|
29
|
+
for (let n = r.length - 1; n >= 1; n--) {
|
|
30
|
+
const u = r.slice(0, n).join("-"), s = r.slice(n).join("-");
|
|
31
|
+
o.push(i.join(c, e, u, `${s}.vue`)), o.push(i.join(c, e, u, s, "index.vue"));
|
|
32
|
+
}
|
|
33
|
+
return o;
|
|
34
|
+
}
|
|
35
|
+
function v(e) {
|
|
36
|
+
if (!e)
|
|
37
|
+
return l(f([i.join(c, "index.vue")]));
|
|
38
|
+
let t = e;
|
|
39
|
+
try {
|
|
40
|
+
t = decodeURIComponent(e);
|
|
41
|
+
} catch (r) {
|
|
42
|
+
}
|
|
43
|
+
const o = t.split("/").filter(Boolean);
|
|
44
|
+
for (let r = o.length; r >= 1; r--) {
|
|
45
|
+
const n = o.slice(0, r), u = n[n.length - 1] || "", s = n.slice(0, -1).join("/"), a = f(m(s, u));
|
|
46
|
+
if (a) return l(a);
|
|
47
|
+
}
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
function _(e) {
|
|
51
|
+
!e || e === d || (d = e, console.info(`\x1B[32m➜ \x1B[37m正在访问: \x1B[36m${e}\x1B[0m`));
|
|
52
|
+
}
|
|
16
53
|
return {
|
|
17
54
|
name: "keyblade-pro-log-page-route",
|
|
18
55
|
enforce: "pre",
|
|
19
56
|
apply: "serve",
|
|
20
|
-
configureServer(
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
return
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}),
|
|
57
|
+
configureServer(e) {
|
|
58
|
+
e.middlewares.use("/__log_page_route", (t, o, r) => {
|
|
59
|
+
if (t.method !== w)
|
|
60
|
+
return r();
|
|
61
|
+
const n = 1e3 * 10, u = setTimeout(() => {
|
|
62
|
+
o.statusCode = 504, o.setHeader("Content-Type", "application/json"), o.end(JSON.stringify({ success: !1, error: "Gateway Timeout" }));
|
|
63
|
+
}, n);
|
|
64
|
+
let s = "";
|
|
65
|
+
t.on("data", (a) => {
|
|
66
|
+
s += a;
|
|
67
|
+
}), t.on("end", () => {
|
|
31
68
|
try {
|
|
32
|
-
const {
|
|
33
|
-
|
|
34
|
-
const u = l ? n.join(l, s).replace(/\\/g, "/") : s;
|
|
35
|
-
if (u === c) {
|
|
36
|
-
clearTimeout(d), e.statusCode = 200, e.setHeader("Content-Type", "application/json"), e.end(JSON.stringify({ success: !0 }));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
c = u, console.info(`\x1B[32m➜ \x1B[37m正在访问: \x1B[36m${u}\x1B[0m`);
|
|
40
|
-
}
|
|
69
|
+
const { file: a, route: y } = JSON.parse(s), S = String(y || "").replace(/^\//, "").replace(/\/$/, "").split("?")[0] || "", j = a ? g(a) : v(S);
|
|
70
|
+
_(j);
|
|
41
71
|
} catch (a) {
|
|
42
72
|
}
|
|
43
|
-
clearTimeout(
|
|
73
|
+
clearTimeout(u), o.statusCode = 200, o.setHeader("Content-Type", "application/json"), o.end(JSON.stringify({ success: !0 }));
|
|
44
74
|
});
|
|
45
75
|
});
|
|
46
76
|
},
|
|
47
|
-
transformIndexHtml(
|
|
48
|
-
return
|
|
77
|
+
transformIndexHtml(e) {
|
|
78
|
+
return e.replace("</head>", `
|
|
49
79
|
<script>
|
|
50
80
|
(function() {
|
|
51
81
|
if (window.__logPageRouteInitialized) return;
|
|
52
82
|
window.__logPageRouteInitialized = true;
|
|
53
83
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
84
|
+
var lastSent = '';
|
|
85
|
+
var sendTimer = null;
|
|
86
|
+
|
|
87
|
+
// 找到 Vue 应用实例(Vue3 会在挂载容器上挂 __vue_app__)
|
|
88
|
+
function getApp() {
|
|
89
|
+
var selectors = ['#app', '#root'];
|
|
90
|
+
for (var i = 0; i < selectors.length; i++) {
|
|
91
|
+
var el = document.querySelector(selectors[i]);
|
|
92
|
+
if (el && el.__vue_app__) return el.__vue_app__;
|
|
58
93
|
}
|
|
59
|
-
|
|
60
|
-
|
|
94
|
+
if (document.body) {
|
|
95
|
+
var nodes = document.body.querySelectorAll('*');
|
|
96
|
+
for (var j = 0; j < nodes.length; j++) {
|
|
97
|
+
if (nodes[j].__vue_app__) return nodes[j].__vue_app__;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
61
101
|
}
|
|
62
102
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
103
|
+
// 读取 vue-router 当前匹配的最深层组件的 __file(dev 下由 @vitejs/plugin-vue 注入)
|
|
104
|
+
function getMatchedFile() {
|
|
105
|
+
try {
|
|
106
|
+
var app = getApp();
|
|
107
|
+
if (!app || !app.config || !app.config.globalProperties) return '';
|
|
108
|
+
var router = app.config.globalProperties.$router;
|
|
109
|
+
if (!router || !router.currentRoute || !router.currentRoute.value) return '';
|
|
110
|
+
var matched = router.currentRoute.value.matched || [];
|
|
111
|
+
for (var i = matched.length - 1; i >= 0; i--) {
|
|
112
|
+
var comps = matched[i].components || {};
|
|
113
|
+
for (var key in comps) {
|
|
114
|
+
var c = comps[key];
|
|
115
|
+
if (c && c.__file) return c.__file;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} catch (e) {}
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getRoute() {
|
|
123
|
+
var hash = location.hash;
|
|
124
|
+
if (hash && hash.length > 1) return hash.slice(1).split('?')[0];
|
|
125
|
+
return (location.pathname || '/').split('?')[0];
|
|
126
|
+
}
|
|
66
127
|
|
|
67
|
-
function
|
|
68
|
-
var data = JSON.stringify(
|
|
128
|
+
function post(payload) {
|
|
129
|
+
var data = JSON.stringify(payload);
|
|
69
130
|
if (navigator.sendBeacon) {
|
|
70
131
|
navigator.sendBeacon('/__log_page_route', new Blob([data], { type: 'application/json' }));
|
|
71
132
|
} else {
|
|
@@ -78,54 +139,53 @@ function T(f) {
|
|
|
78
139
|
}
|
|
79
140
|
}
|
|
80
141
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
142
|
+
// 异步路由组件可能尚未加载完成,重试若干次后回退到上报路由
|
|
143
|
+
function report(attempt) {
|
|
144
|
+
attempt = attempt || 0;
|
|
145
|
+
var file = getMatchedFile();
|
|
146
|
+
if (file) {
|
|
147
|
+
if (file === lastSent) return;
|
|
148
|
+
lastSent = file;
|
|
149
|
+
post({ file: file });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (attempt < 10) {
|
|
153
|
+
setTimeout(function() { report(attempt + 1); }, 120);
|
|
154
|
+
return;
|
|
85
155
|
}
|
|
86
|
-
route =
|
|
87
|
-
if (route ===
|
|
88
|
-
|
|
156
|
+
var route = getRoute().replace(/\\/$/, '') || '/';
|
|
157
|
+
if (route === lastSent) return;
|
|
158
|
+
lastSent = route;
|
|
159
|
+
post({ route: route });
|
|
160
|
+
}
|
|
89
161
|
|
|
162
|
+
function schedule() {
|
|
90
163
|
if (sendTimer) clearTimeout(sendTimer);
|
|
91
|
-
sendTimer = setTimeout(function() {
|
|
92
|
-
doSend(route);
|
|
93
|
-
}, 100);
|
|
164
|
+
sendTimer = setTimeout(function() { report(0); }, 100);
|
|
94
165
|
}
|
|
95
166
|
|
|
96
167
|
if (document.readyState === 'loading') {
|
|
97
|
-
document.addEventListener('DOMContentLoaded',
|
|
168
|
+
document.addEventListener('DOMContentLoaded', schedule);
|
|
98
169
|
} else {
|
|
99
|
-
|
|
170
|
+
schedule();
|
|
100
171
|
}
|
|
101
|
-
window.addEventListener('hashchange',
|
|
172
|
+
window.addEventListener('hashchange', schedule);
|
|
173
|
+
window.addEventListener('popstate', schedule);
|
|
102
174
|
var originalPushState = history.pushState;
|
|
103
175
|
var originalReplaceState = history.replaceState;
|
|
104
176
|
history.pushState = function() {
|
|
105
177
|
originalPushState.apply(history, arguments);
|
|
106
|
-
|
|
107
|
-
if (newHref !== lastHref) {
|
|
108
|
-
lastHref = newHref;
|
|
109
|
-
sendRoute();
|
|
110
|
-
}
|
|
178
|
+
schedule();
|
|
111
179
|
};
|
|
112
180
|
history.replaceState = function() {
|
|
113
181
|
originalReplaceState.apply(history, arguments);
|
|
114
|
-
|
|
115
|
-
if (newHref !== lastHref) {
|
|
116
|
-
lastHref = newHref;
|
|
117
|
-
sendRoute();
|
|
118
|
-
}
|
|
182
|
+
schedule();
|
|
119
183
|
};
|
|
120
|
-
window.addEventListener('popstate', function() {
|
|
121
|
-
lastHref = location.href;
|
|
122
|
-
sendRoute();
|
|
123
|
-
});
|
|
124
184
|
})();
|
|
125
185
|
<\/script>` + "</head>");
|
|
126
186
|
}
|
|
127
187
|
};
|
|
128
188
|
}
|
|
129
189
|
export {
|
|
130
|
-
|
|
190
|
+
P as default
|
|
131
191
|
};
|
package/package.json
CHANGED