@tourmind-frontend/monitor-plugin-webpack 1.4.0 → 1.6.0
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.
- package/dist/index.cjs +36 -7
- package/dist/index.d.ts +13 -0
- package/dist/index.js +36 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(src_exports, {
|
|
|
33
33
|
default: () => UploadSourceMapPlugin
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(src_exports);
|
|
36
|
+
var import_zlib = require("zlib");
|
|
36
37
|
var import_axios = __toESM(require("axios"), 1);
|
|
37
38
|
var import_form_data = __toESM(require("form-data"), 1);
|
|
38
39
|
var LOG_PREFIX = "[frontend-monitor]";
|
|
@@ -43,6 +44,11 @@ function defaultLogger(level, msg, extra) {
|
|
|
43
44
|
else if (level === "warn") console.warn(line, tail);
|
|
44
45
|
else console.error(line, tail);
|
|
45
46
|
}
|
|
47
|
+
function formatSize(bytes) {
|
|
48
|
+
if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
49
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
50
|
+
return `${bytes}B`;
|
|
51
|
+
}
|
|
46
52
|
function extractSourceMaps(compilation) {
|
|
47
53
|
const result = [];
|
|
48
54
|
const assets = compilation.assets;
|
|
@@ -65,10 +71,16 @@ function extractSourceMaps(compilation) {
|
|
|
65
71
|
}
|
|
66
72
|
async function uploadFiles({ url, query, files }) {
|
|
67
73
|
const form = new import_form_data.default();
|
|
74
|
+
let rawBytes = 0;
|
|
75
|
+
let gzipBytes = 0;
|
|
68
76
|
for (const [filename, content] of files) {
|
|
69
|
-
|
|
77
|
+
const raw = Buffer.from(content, "utf-8");
|
|
78
|
+
const gz = (0, import_zlib.gzipSync)(raw);
|
|
79
|
+
rawBytes += raw.byteLength;
|
|
80
|
+
gzipBytes += gz.byteLength;
|
|
81
|
+
form.append("file", gz, { filename });
|
|
70
82
|
}
|
|
71
|
-
const qs = new URLSearchParams(query).toString();
|
|
83
|
+
const qs = new URLSearchParams({ ...query, encoding: "gzip" }).toString();
|
|
72
84
|
const fullUrl = `${url}${url.includes("?") ? "&" : "?"}${qs}`;
|
|
73
85
|
await (0, import_axios.default)({
|
|
74
86
|
method: "POST",
|
|
@@ -78,9 +90,13 @@ async function uploadFiles({ url, query, files }) {
|
|
|
78
90
|
maxBodyLength: Infinity,
|
|
79
91
|
maxContentLength: Infinity
|
|
80
92
|
});
|
|
93
|
+
return { rawBytes, gzipBytes };
|
|
81
94
|
}
|
|
82
95
|
var UploadSourceMapPlugin = class {
|
|
83
96
|
constructor(options) {
|
|
97
|
+
// emit 阶段 fire-and-forget 启动的上传任务;用数组而非单值,兼容同一实例被挂到
|
|
98
|
+
// 多个 compiler(如 Nuxt 2 modern 模式 client + modern 双客户端构建)的情况。
|
|
99
|
+
this.pendingUploads = [];
|
|
84
100
|
if (!options.url) throw new Error(`${LOG_PREFIX} "url" is required`);
|
|
85
101
|
if (!options.authToken) throw new Error(`${LOG_PREFIX} "authToken" is required`);
|
|
86
102
|
if (!options.authToken.startsWith("fm_at_")) {
|
|
@@ -89,6 +105,13 @@ var UploadSourceMapPlugin = class {
|
|
|
89
105
|
if (!options.commit) throw new Error(`${LOG_PREFIX} "commit" is required`);
|
|
90
106
|
this.options = options;
|
|
91
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* 等待所有已启动的上传完成(上传失败已被内部 catch 吞掉,不会 reject)。
|
|
110
|
+
* deferWait 模式下由调用方在构建尾声调用,确保进程退出前上传完成。
|
|
111
|
+
*/
|
|
112
|
+
waitForUpload() {
|
|
113
|
+
return Promise.all(this.pendingUploads).then(() => void 0);
|
|
114
|
+
}
|
|
92
115
|
apply(compiler) {
|
|
93
116
|
var _a;
|
|
94
117
|
const options = this.options;
|
|
@@ -96,7 +119,6 @@ var UploadSourceMapPlugin = class {
|
|
|
96
119
|
if (compiler.options.mode !== "production") return;
|
|
97
120
|
const uploadUrl = `${options.url.replace(/\/+$/, "")}/api/upload`;
|
|
98
121
|
compiler.options.devtool = "hidden-source-map";
|
|
99
|
-
let uploadPromise = null;
|
|
100
122
|
compiler.hooks.emit.tap("UploadSourceMapPlugin", (compilation) => {
|
|
101
123
|
var _a2;
|
|
102
124
|
const files = extractSourceMaps(compilation);
|
|
@@ -111,10 +133,17 @@ var UploadSourceMapPlugin = class {
|
|
|
111
133
|
timestamp: String(timestamp)
|
|
112
134
|
};
|
|
113
135
|
query.commit = commit;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
136
|
+
this.pendingUploads.push(
|
|
137
|
+
uploadFiles({ url: uploadUrl, query, files }).then(
|
|
138
|
+
({ rawBytes, gzipBytes }) => log(
|
|
139
|
+
"info",
|
|
140
|
+
`uploaded ${files.length} sourcemap file(s) (commit=${commit}, ${formatSize(rawBytes)} -> ${formatSize(gzipBytes)} gzipped)`
|
|
141
|
+
)
|
|
142
|
+
).catch((err) => log("error", "upload failed", err instanceof Error ? err.message : err))
|
|
143
|
+
);
|
|
118
144
|
});
|
|
145
|
+
if (!options.deferWait) {
|
|
146
|
+
compiler.hooks.done.tapPromise("UploadSourceMapPlugin", () => this.waitForUpload());
|
|
147
|
+
}
|
|
119
148
|
}
|
|
120
149
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -10,9 +10,22 @@ export interface UploadSourceMapOptions {
|
|
|
10
10
|
timestamp?: number;
|
|
11
11
|
/** 自定义 logger,默认走 `console.log` / `console.warn` / `console.error`。 */
|
|
12
12
|
logger?: (level: "info" | "warn" | "error", msg: string, extra?: unknown) => void;
|
|
13
|
+
/**
|
|
14
|
+
* 为 true 时本插件不在 compiler 的 done 阶段等待上传完成,由调用方在更晚的时机
|
|
15
|
+
* (如 Nuxt 2 的 `build:done`,所有 compiler 都结束后)await `waitForUpload()`,
|
|
16
|
+
* 让上传与后续其它 compiler 的编译并行。
|
|
17
|
+
* 注意:调用方必须在构建进程退出前 await,否则 CI 退出会掐断未完成的上传。
|
|
18
|
+
*/
|
|
19
|
+
deferWait?: boolean;
|
|
13
20
|
}
|
|
14
21
|
export default class UploadSourceMapPlugin {
|
|
15
22
|
options: UploadSourceMapOptions;
|
|
23
|
+
private pendingUploads;
|
|
16
24
|
constructor(options: UploadSourceMapOptions);
|
|
25
|
+
/**
|
|
26
|
+
* 等待所有已启动的上传完成(上传失败已被内部 catch 吞掉,不会 reject)。
|
|
27
|
+
* deferWait 模式下由调用方在构建尾声调用,确保进程退出前上传完成。
|
|
28
|
+
*/
|
|
29
|
+
waitForUpload(): Promise<void>;
|
|
17
30
|
apply(compiler: Compiler): void;
|
|
18
31
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// extensions/plugin-webpack/src/index.ts
|
|
2
|
+
import { gzipSync } from "zlib";
|
|
2
3
|
import axios from "axios";
|
|
3
4
|
import FormData from "form-data";
|
|
4
5
|
var LOG_PREFIX = "[frontend-monitor]";
|
|
@@ -9,6 +10,11 @@ function defaultLogger(level, msg, extra) {
|
|
|
9
10
|
else if (level === "warn") console.warn(line, tail);
|
|
10
11
|
else console.error(line, tail);
|
|
11
12
|
}
|
|
13
|
+
function formatSize(bytes) {
|
|
14
|
+
if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
15
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
16
|
+
return `${bytes}B`;
|
|
17
|
+
}
|
|
12
18
|
function extractSourceMaps(compilation) {
|
|
13
19
|
const result = [];
|
|
14
20
|
const assets = compilation.assets;
|
|
@@ -31,10 +37,16 @@ function extractSourceMaps(compilation) {
|
|
|
31
37
|
}
|
|
32
38
|
async function uploadFiles({ url, query, files }) {
|
|
33
39
|
const form = new FormData();
|
|
40
|
+
let rawBytes = 0;
|
|
41
|
+
let gzipBytes = 0;
|
|
34
42
|
for (const [filename, content] of files) {
|
|
35
|
-
|
|
43
|
+
const raw = Buffer.from(content, "utf-8");
|
|
44
|
+
const gz = gzipSync(raw);
|
|
45
|
+
rawBytes += raw.byteLength;
|
|
46
|
+
gzipBytes += gz.byteLength;
|
|
47
|
+
form.append("file", gz, { filename });
|
|
36
48
|
}
|
|
37
|
-
const qs = new URLSearchParams(query).toString();
|
|
49
|
+
const qs = new URLSearchParams({ ...query, encoding: "gzip" }).toString();
|
|
38
50
|
const fullUrl = `${url}${url.includes("?") ? "&" : "?"}${qs}`;
|
|
39
51
|
await axios({
|
|
40
52
|
method: "POST",
|
|
@@ -44,9 +56,13 @@ async function uploadFiles({ url, query, files }) {
|
|
|
44
56
|
maxBodyLength: Infinity,
|
|
45
57
|
maxContentLength: Infinity
|
|
46
58
|
});
|
|
59
|
+
return { rawBytes, gzipBytes };
|
|
47
60
|
}
|
|
48
61
|
var UploadSourceMapPlugin = class {
|
|
49
62
|
constructor(options) {
|
|
63
|
+
// emit 阶段 fire-and-forget 启动的上传任务;用数组而非单值,兼容同一实例被挂到
|
|
64
|
+
// 多个 compiler(如 Nuxt 2 modern 模式 client + modern 双客户端构建)的情况。
|
|
65
|
+
this.pendingUploads = [];
|
|
50
66
|
if (!options.url) throw new Error(`${LOG_PREFIX} "url" is required`);
|
|
51
67
|
if (!options.authToken) throw new Error(`${LOG_PREFIX} "authToken" is required`);
|
|
52
68
|
if (!options.authToken.startsWith("fm_at_")) {
|
|
@@ -55,6 +71,13 @@ var UploadSourceMapPlugin = class {
|
|
|
55
71
|
if (!options.commit) throw new Error(`${LOG_PREFIX} "commit" is required`);
|
|
56
72
|
this.options = options;
|
|
57
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* 等待所有已启动的上传完成(上传失败已被内部 catch 吞掉,不会 reject)。
|
|
76
|
+
* deferWait 模式下由调用方在构建尾声调用,确保进程退出前上传完成。
|
|
77
|
+
*/
|
|
78
|
+
waitForUpload() {
|
|
79
|
+
return Promise.all(this.pendingUploads).then(() => void 0);
|
|
80
|
+
}
|
|
58
81
|
apply(compiler) {
|
|
59
82
|
var _a;
|
|
60
83
|
const options = this.options;
|
|
@@ -62,7 +85,6 @@ var UploadSourceMapPlugin = class {
|
|
|
62
85
|
if (compiler.options.mode !== "production") return;
|
|
63
86
|
const uploadUrl = `${options.url.replace(/\/+$/, "")}/api/upload`;
|
|
64
87
|
compiler.options.devtool = "hidden-source-map";
|
|
65
|
-
let uploadPromise = null;
|
|
66
88
|
compiler.hooks.emit.tap("UploadSourceMapPlugin", (compilation) => {
|
|
67
89
|
var _a2;
|
|
68
90
|
const files = extractSourceMaps(compilation);
|
|
@@ -77,11 +99,18 @@ var UploadSourceMapPlugin = class {
|
|
|
77
99
|
timestamp: String(timestamp)
|
|
78
100
|
};
|
|
79
101
|
query.commit = commit;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
102
|
+
this.pendingUploads.push(
|
|
103
|
+
uploadFiles({ url: uploadUrl, query, files }).then(
|
|
104
|
+
({ rawBytes, gzipBytes }) => log(
|
|
105
|
+
"info",
|
|
106
|
+
`uploaded ${files.length} sourcemap file(s) (commit=${commit}, ${formatSize(rawBytes)} -> ${formatSize(gzipBytes)} gzipped)`
|
|
107
|
+
)
|
|
108
|
+
).catch((err) => log("error", "upload failed", err instanceof Error ? err.message : err))
|
|
109
|
+
);
|
|
84
110
|
});
|
|
111
|
+
if (!options.deferWait) {
|
|
112
|
+
compiler.hooks.done.tapPromise("UploadSourceMapPlugin", () => this.waitForUpload());
|
|
113
|
+
}
|
|
85
114
|
}
|
|
86
115
|
};
|
|
87
116
|
export {
|
package/package.json
CHANGED