@qiu_jun/monitors 0.0.3 → 0.0.5
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/README.md +2 -0
- package/dist/miniprogram.d.ts +62 -0
- package/dist/miniprogram.js +265 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -88,3 +88,5 @@ npm publish
|
|
|
88
88
|
- 性能类(paint/timing/longTask)→ `exc_perf_event`
|
|
89
89
|
- reporter 源码位于 `src/exception/`,与 exception-sdk 逻辑等价,便于独立发版
|
|
90
90
|
- **后台对接与展示**:[backend-integration.md](./backend-integration.md)(与 exception 模块 `/api/exception/*` 接口一一对照)
|
|
91
|
+
|
|
92
|
+
# npm login --registry=https://registry.npmjs.org/
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 小程序监控入口(按需引入)
|
|
3
|
+
* 与 H5 入口相互独立:transport 基于 wx.request,错误采集基于 wx.onError / wx.onUnhandledRejection
|
|
4
|
+
*/
|
|
5
|
+
import { SDK_VERSION, createReporter } from './exception/reporter';
|
|
6
|
+
import type { ExcReporter } from './exception/reporter';
|
|
7
|
+
import type { ExcEventPayload, ExcSdkOptions, ExcTransport } from './exception/types';
|
|
8
|
+
export type { ExcEventPayload, ExcSdkOptions, ExcReporter, ExcTransport };
|
|
9
|
+
export { SDK_VERSION, createReporter };
|
|
10
|
+
/** 最小 wx 类型声明(避免强制依赖 miniprogram-api-typings) */
|
|
11
|
+
interface WxLike {
|
|
12
|
+
request(options: {
|
|
13
|
+
url: string;
|
|
14
|
+
method?: string;
|
|
15
|
+
header?: Record<string, string>;
|
|
16
|
+
data?: string;
|
|
17
|
+
success?: (res: {
|
|
18
|
+
statusCode: number;
|
|
19
|
+
}) => void;
|
|
20
|
+
fail?: (err: {
|
|
21
|
+
errMsg?: string;
|
|
22
|
+
}) => void;
|
|
23
|
+
}): void;
|
|
24
|
+
onError(callback: (message: string) => void): void;
|
|
25
|
+
offError?(callback: (message: string) => void): void;
|
|
26
|
+
onUnhandledRejection(callback: (res: {
|
|
27
|
+
reason?: unknown;
|
|
28
|
+
}) => void): void;
|
|
29
|
+
offUnhandledRejection?(callback: (res: {
|
|
30
|
+
reason?: unknown;
|
|
31
|
+
}) => void): void;
|
|
32
|
+
onAppHide?(callback: () => void): void;
|
|
33
|
+
offAppHide?(callback: () => void): void;
|
|
34
|
+
getAccountInfoSync?(): {
|
|
35
|
+
miniProgram?: {
|
|
36
|
+
envVersion?: string;
|
|
37
|
+
version?: string;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
getSystemInfoSync?(): Record<string, any>;
|
|
41
|
+
}
|
|
42
|
+
/** 小程序 transport:wx.request POST JSON */
|
|
43
|
+
export declare function makeMiniProgramTransport(endpoint: string, wxApi?: WxLike): ExcTransport;
|
|
44
|
+
export interface MiniProgramMonitorOptions extends ExcSdkOptions {
|
|
45
|
+
/** 用户标识(对齐 H5 侧 IMonitorOptions.userId) */
|
|
46
|
+
userId?: string;
|
|
47
|
+
/** 默认取全局 wx;支付宝/百度等可显式传入适配后的 API */
|
|
48
|
+
wxApi?: WxLike;
|
|
49
|
+
/** 拦截 App/Page/Component 生命周期(默认 true,须在调用 App()/Page() 之前初始化) */
|
|
50
|
+
interceptLifecycle?: boolean;
|
|
51
|
+
/** 拦截 wx.request 上报失败请求(默认 true,上报自身 URL 除外,防递归) */
|
|
52
|
+
interceptRequest?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface MiniProgramMonitor {
|
|
55
|
+
reporter: ExcReporter;
|
|
56
|
+
/** 上报自定义事件 */
|
|
57
|
+
capture: (event: ExcEventPayload) => void;
|
|
58
|
+
/** 立即上报缓冲中的事件,并还原 App/Page/Component 与 wx.request 的包装 */
|
|
59
|
+
destroy: () => void;
|
|
60
|
+
}
|
|
61
|
+
/** 小程序监控:创建 reporter + 挂载错误采集(wx.onError / wx.onUnhandledRejection)+ 切后台 flush */
|
|
62
|
+
export declare function createMiniProgramMonitor(options: MiniProgramMonitorOptions): MiniProgramMonitor;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createReporter = exports.SDK_VERSION = void 0;
|
|
4
|
+
exports.makeMiniProgramTransport = makeMiniProgramTransport;
|
|
5
|
+
exports.createMiniProgramMonitor = createMiniProgramMonitor;
|
|
6
|
+
/**
|
|
7
|
+
* 小程序监控入口(按需引入)
|
|
8
|
+
* 与 H5 入口相互独立:transport 基于 wx.request,错误采集基于 wx.onError / wx.onUnhandledRejection
|
|
9
|
+
*/
|
|
10
|
+
const reporter_1 = require("./exception/reporter");
|
|
11
|
+
Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return reporter_1.SDK_VERSION; } });
|
|
12
|
+
Object.defineProperty(exports, "createReporter", { enumerable: true, get: function () { return reporter_1.createReporter; } });
|
|
13
|
+
/** 从全局取 wx(微信 / uni-app 等均已注入),取不到返回 undefined */
|
|
14
|
+
function getWx() {
|
|
15
|
+
return globalThis.wx;
|
|
16
|
+
}
|
|
17
|
+
/** 小程序 transport:wx.request POST JSON */
|
|
18
|
+
function makeMiniProgramTransport(endpoint, wxApi) {
|
|
19
|
+
const api = wxApi !== null && wxApi !== void 0 ? wxApi : getWx();
|
|
20
|
+
if (!api)
|
|
21
|
+
throw new Error('monitor: 未找到 wx 全局对象,请显式传入 wxApi');
|
|
22
|
+
return (payload, projectKey) => new Promise((resolve, reject) => {
|
|
23
|
+
api.request({
|
|
24
|
+
url: endpoint,
|
|
25
|
+
method: 'POST',
|
|
26
|
+
header: { 'content-type': 'application/json', 'X-Project-Key': projectKey },
|
|
27
|
+
data: JSON.stringify(payload),
|
|
28
|
+
success: (res) => {
|
|
29
|
+
if (res.statusCode >= 200 && res.statusCode < 300)
|
|
30
|
+
resolve();
|
|
31
|
+
else
|
|
32
|
+
reject(Object.assign(new Error(`monitor: 上报失败 ${res.statusCode}`), { statusCode: res.statusCode }));
|
|
33
|
+
},
|
|
34
|
+
fail: err => { var _a; return reject(new Error(`monitor: 上报失败 ${(_a = err === null || err === void 0 ? void 0 : err.errMsg) !== null && _a !== void 0 ? _a : 'network error'}`)); },
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** Page/Component 实例生命周期 */
|
|
39
|
+
const PAGE_LIFECYCLES = ['onLoad', 'onShow', 'onReady', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onError'];
|
|
40
|
+
/** App 生命周期 */
|
|
41
|
+
const APP_LIFECYCLES = ['onLaunch', 'onShow', 'onHide', 'onPageNotFound'];
|
|
42
|
+
/** Component 生命周期 */
|
|
43
|
+
const COMPONENT_LIFECYCLES = ['attached', 'ready', 'detached'];
|
|
44
|
+
/**
|
|
45
|
+
* 包装生命周期:正常执行不打扰;抛错(含 async 生命周期 reject)时上报
|
|
46
|
+
* 带 lifecycle/页面/组件上下文与耗时,然后原样抛出(wx.onError 兜底,内部去重防双报)
|
|
47
|
+
*/
|
|
48
|
+
function wrapLifecycle(fn, name, getContext) {
|
|
49
|
+
return function (...args) {
|
|
50
|
+
const start = Date.now();
|
|
51
|
+
const handleError = (err) => {
|
|
52
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
53
|
+
lifecycleErrorHandler === null || lifecycleErrorHandler === void 0 ? void 0 : lifecycleErrorHandler({
|
|
54
|
+
type: 'error',
|
|
55
|
+
message: e.message,
|
|
56
|
+
stack: e.stack,
|
|
57
|
+
lifecycle: name,
|
|
58
|
+
duration: Date.now() - start,
|
|
59
|
+
page: getContext().page,
|
|
60
|
+
component: getContext().component,
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
try {
|
|
64
|
+
const result = fn.apply(this, args);
|
|
65
|
+
// async 生命周期(如 async onLoad)的 reject
|
|
66
|
+
if (result instanceof Promise)
|
|
67
|
+
return result.catch((err) => { handleError(err); throw err; });
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
handleError(err);
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** wrapLifecycle 上报出口(由 createMiniProgramMonitor 注入) */
|
|
77
|
+
let lifecycleErrorHandler = null;
|
|
78
|
+
/** 不上报的消息关键字:小程序提审/平台侧产生的导航失败噪声(如 navigateTo:fail page xxx.html is not found) */
|
|
79
|
+
const IGNORED_MESSAGE_KEYWORDS = ['.html is not found'];
|
|
80
|
+
/** 命中关键字的消息不上报 */
|
|
81
|
+
function isIgnoredMessage(message) {
|
|
82
|
+
return IGNORED_MESSAGE_KEYWORDS.some(keyword => message.includes(keyword));
|
|
83
|
+
}
|
|
84
|
+
/** 短窗口内同消息去重(生命周期包装抛出 + wx.onError 会收到同一条错误) */
|
|
85
|
+
let lastErrorCache = { message: '', time: 0 };
|
|
86
|
+
function isDuplicate(message) {
|
|
87
|
+
const now = Date.now();
|
|
88
|
+
if (message === lastErrorCache.message && now - lastErrorCache.time < 5000)
|
|
89
|
+
return true;
|
|
90
|
+
lastErrorCache = { message, time: now };
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 拦截全局 App/Page/Component:包装生命周期与组件 methods(抛错时带上下文上报)
|
|
95
|
+
* 必须在业务代码调用 App()/Page()/Component() 之前执行
|
|
96
|
+
*/
|
|
97
|
+
function interceptConstructors() {
|
|
98
|
+
const g = globalThis;
|
|
99
|
+
function wrapDefinition(original, kind) {
|
|
100
|
+
return function (options) {
|
|
101
|
+
const lifecycles = kind === 'App' ? APP_LIFECYCLES : kind === 'Page' ? PAGE_LIFECYCLES : COMPONENT_LIFECYCLES;
|
|
102
|
+
const getContext = () => ({ page: kind === 'App' ? '' : currentPageRoute(), component: kind === 'Component' ? 'Component' : undefined });
|
|
103
|
+
for (const name of lifecycles) {
|
|
104
|
+
const fn = options === null || options === void 0 ? void 0 : options[name];
|
|
105
|
+
if (typeof fn === 'function')
|
|
106
|
+
options[name] = wrapLifecycle(fn, name, getContext);
|
|
107
|
+
}
|
|
108
|
+
// Component 的 methods 也包一层(组件方法抛错常见于这里)
|
|
109
|
+
if (kind === 'Component' && (options === null || options === void 0 ? void 0 : options.methods)) {
|
|
110
|
+
for (const name of Object.keys(options.methods)) {
|
|
111
|
+
const fn = options.methods[name];
|
|
112
|
+
if (typeof fn === 'function')
|
|
113
|
+
options.methods[name] = wrapLifecycle(fn, name, getContext);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return original.call(this, options);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const originals = {};
|
|
120
|
+
for (const key of ['App', 'Page', 'Component']) {
|
|
121
|
+
if (typeof g[key] === 'function') {
|
|
122
|
+
originals[key] = g[key];
|
|
123
|
+
g[key] = Object.assign(wrapDefinition(g[key], key), { __monitor_original__: g[key] });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return () => {
|
|
127
|
+
var _a;
|
|
128
|
+
for (const [key, fn] of Object.entries(originals)) {
|
|
129
|
+
if (((_a = g[key]) === null || _a === void 0 ? void 0 : _a.__monitor_original__) === fn)
|
|
130
|
+
g[key] = fn;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function currentPageRoute() {
|
|
135
|
+
var _a, _b, _c, _d;
|
|
136
|
+
try {
|
|
137
|
+
const pages = (_c = (_b = (_a = globalThis).getCurrentPages) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : [];
|
|
138
|
+
const route = (_d = pages[pages.length - 1]) === null || _d === void 0 ? void 0 : _d.route;
|
|
139
|
+
return route ? `/${route}` : '';
|
|
140
|
+
}
|
|
141
|
+
catch (_e) {
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** 拦截 wx.request:失败的请求按 H5 侧 request 事件格式上报(上报自身 URL 除外,防递归) */
|
|
146
|
+
function interceptRequest(wxApi, endpoint, capture) {
|
|
147
|
+
const original = wxApi.request.bind(wxApi);
|
|
148
|
+
wxApi.request = (options) => {
|
|
149
|
+
var _a;
|
|
150
|
+
const url = String((_a = options === null || options === void 0 ? void 0 : options.url) !== null && _a !== void 0 ? _a : '');
|
|
151
|
+
if (url === endpoint)
|
|
152
|
+
return original(options);
|
|
153
|
+
const start = Date.now();
|
|
154
|
+
return original({
|
|
155
|
+
...options,
|
|
156
|
+
success: (res) => {
|
|
157
|
+
var _a, _b;
|
|
158
|
+
if (res.statusCode >= 400) {
|
|
159
|
+
capture({
|
|
160
|
+
type: 'request',
|
|
161
|
+
message: `Request failed [${res.statusCode}]: ${String((_a = options === null || options === void 0 ? void 0 : options.method) !== null && _a !== void 0 ? _a : 'GET').toUpperCase()} ${url}`,
|
|
162
|
+
device: { durationMs: Date.now() - start },
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
(_b = options === null || options === void 0 ? void 0 : options.success) === null || _b === void 0 ? void 0 : _b.call(options, res);
|
|
166
|
+
},
|
|
167
|
+
fail: (err) => {
|
|
168
|
+
var _a, _b;
|
|
169
|
+
capture({
|
|
170
|
+
type: 'request',
|
|
171
|
+
message: `Request failed [network]: ${String((_a = options === null || options === void 0 ? void 0 : options.method) !== null && _a !== void 0 ? _a : 'GET').toUpperCase()} ${url}`,
|
|
172
|
+
device: { durationMs: Date.now() - start, msg: err === null || err === void 0 ? void 0 : err.errMsg },
|
|
173
|
+
});
|
|
174
|
+
(_b = options === null || options === void 0 ? void 0 : options.fail) === null || _b === void 0 ? void 0 : _b.call(options, err);
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
return () => {
|
|
179
|
+
;
|
|
180
|
+
wxApi.request = original;
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/** 小程序监控:创建 reporter + 挂载错误采集(wx.onError / wx.onUnhandledRejection)+ 切后台 flush */
|
|
184
|
+
function createMiniProgramMonitor(options) {
|
|
185
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
186
|
+
const wxApi = (_a = options.wxApi) !== null && _a !== void 0 ? _a : getWx();
|
|
187
|
+
if (!wxApi)
|
|
188
|
+
throw new Error('monitor: 未找到 wx 全局对象,请显式传入 wxApi');
|
|
189
|
+
const reporter = (0, reporter_1.createReporter)(options, makeMiniProgramTransport(options.endpoint, wxApi));
|
|
190
|
+
const sys = (_b = wxApi.getSystemInfoSync) === null || _b === void 0 ? void 0 : _b.call(wxApi);
|
|
191
|
+
const account = (_c = wxApi.getAccountInfoSync) === null || _c === void 0 ? void 0 : _c.call(wxApi).miniProgram;
|
|
192
|
+
// device 字段与 H5 侧 toExcEvent.baseDeviceFields 对齐:title/url/browser/os/deviceInfo/userAgent
|
|
193
|
+
const baseDevice = {
|
|
194
|
+
browser: `miniProgram ${(_d = account === null || account === void 0 ? void 0 : account.envVersion) !== null && _d !== void 0 ? _d : ''}`.trim(),
|
|
195
|
+
os: String((_e = sys === null || sys === void 0 ? void 0 : sys.system) !== null && _e !== void 0 ? _e : ''),
|
|
196
|
+
deviceInfo: `${(_f = sys === null || sys === void 0 ? void 0 : sys.brand) !== null && _f !== void 0 ? _f : ''} ${(_g = sys === null || sys === void 0 ? void 0 : sys.model) !== null && _g !== void 0 ? _g : ''}`.trim(),
|
|
197
|
+
userAgent: String((_h = sys === null || sys === void 0 ? void 0 : sys.host) !== null && _h !== void 0 ? _h : ''),
|
|
198
|
+
};
|
|
199
|
+
/** 当前页面路由(对齐 H5 侧的 page: location.href) */
|
|
200
|
+
const currentPage = currentPageRoute;
|
|
201
|
+
const withBase = (event) => {
|
|
202
|
+
var _a, _b, _c, _d, _e, _f;
|
|
203
|
+
return ({
|
|
204
|
+
level: 'ERROR',
|
|
205
|
+
...event,
|
|
206
|
+
page: (_a = event.page) !== null && _a !== void 0 ? _a : currentPage(),
|
|
207
|
+
userId: (_b = event.userId) !== null && _b !== void 0 ? _b : options.userId,
|
|
208
|
+
release: (_d = (_c = event.release) !== null && _c !== void 0 ? _c : options.release) !== null && _d !== void 0 ? _d : account === null || account === void 0 ? void 0 : account.version,
|
|
209
|
+
environment: (_f = (_e = event.environment) !== null && _e !== void 0 ? _e : options.environment) !== null && _f !== void 0 ? _f : ((account === null || account === void 0 ? void 0 : account.envVersion) === 'release' ? 'production' : account === null || account === void 0 ? void 0 : account.envVersion),
|
|
210
|
+
device: { ...baseDevice, ...event.device },
|
|
211
|
+
});
|
|
212
|
+
};
|
|
213
|
+
const onError = (message) => {
|
|
214
|
+
// 提审等平台侧噪声(如 navigateTo:fail page xxx.html is not found)不上报
|
|
215
|
+
if (isIgnoredMessage(message))
|
|
216
|
+
return;
|
|
217
|
+
// 生命周期包装已上报过的错误(包装后原样抛出会再进这里),5s 内同消息去重
|
|
218
|
+
if (isDuplicate(message))
|
|
219
|
+
return;
|
|
220
|
+
const [msg, ...stackLines] = message.split('\n');
|
|
221
|
+
reporter.capture(withBase({ type: 'error', message: msg, stack: stackLines.join('\n') || undefined }));
|
|
222
|
+
};
|
|
223
|
+
const onUnhandledRejection = (res) => {
|
|
224
|
+
var _a;
|
|
225
|
+
const reason = res.reason;
|
|
226
|
+
const err = reason instanceof Error ? reason : undefined;
|
|
227
|
+
const message = (_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : (typeof reason === 'string' ? reason : JSON.stringify(reason));
|
|
228
|
+
// 平台噪声消息同样过滤
|
|
229
|
+
if (isIgnoredMessage(message))
|
|
230
|
+
return;
|
|
231
|
+
reporter.capture(withBase({
|
|
232
|
+
type: 'unhandledrejection',
|
|
233
|
+
message,
|
|
234
|
+
stack: err === null || err === void 0 ? void 0 : err.stack,
|
|
235
|
+
}));
|
|
236
|
+
};
|
|
237
|
+
const onAppHide = () => void reporter.flush();
|
|
238
|
+
wxApi.onError(onError);
|
|
239
|
+
wxApi.onUnhandledRejection(onUnhandledRejection);
|
|
240
|
+
(_j = wxApi.onAppHide) === null || _j === void 0 ? void 0 : _j.call(wxApi, onAppHide);
|
|
241
|
+
const doCapture = (event) => reporter.capture(withBase(event));
|
|
242
|
+
// 生命周期拦截:包装内抛错 → 带上下文上报;随后原样抛出由 wx.onError 兜底(已去重)
|
|
243
|
+
lifecycleErrorHandler = info => doCapture({
|
|
244
|
+
type: 'error',
|
|
245
|
+
message: info.message,
|
|
246
|
+
stack: info.stack,
|
|
247
|
+
device: { lifecycle: info.lifecycle, duration: info.duration, component: info.component },
|
|
248
|
+
});
|
|
249
|
+
const restoreConstructors = options.interceptLifecycle !== false ? interceptConstructors() : null;
|
|
250
|
+
const restoreRequest = options.interceptRequest !== false ? interceptRequest(wxApi, options.endpoint, doCapture) : null;
|
|
251
|
+
return {
|
|
252
|
+
reporter,
|
|
253
|
+
capture: doCapture,
|
|
254
|
+
destroy: () => {
|
|
255
|
+
var _a, _b, _c;
|
|
256
|
+
lifecycleErrorHandler = null;
|
|
257
|
+
restoreConstructors === null || restoreConstructors === void 0 ? void 0 : restoreConstructors();
|
|
258
|
+
restoreRequest === null || restoreRequest === void 0 ? void 0 : restoreRequest();
|
|
259
|
+
(_a = wxApi.offError) === null || _a === void 0 ? void 0 : _a.call(wxApi, onError);
|
|
260
|
+
(_b = wxApi.offUnhandledRejection) === null || _b === void 0 ? void 0 : _b.call(wxApi, onUnhandledRejection);
|
|
261
|
+
(_c = wxApi.offAppHide) === null || _c === void 0 ? void 0 : _c.call(wxApi, onAppHide);
|
|
262
|
+
reporter.destroy();
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qiu_jun/monitors",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "前端监控,用于捕获,分析,和报告网站或应用程序中的异常,错误和性能问题的方法",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
"types": "./dist/h5.d.ts",
|
|
17
17
|
"default": "./dist/h5.js"
|
|
18
18
|
},
|
|
19
|
+
"./miniprogram": {
|
|
20
|
+
"types": "./dist/miniprogram.d.ts",
|
|
21
|
+
"default": "./dist/miniprogram.js"
|
|
22
|
+
},
|
|
19
23
|
"./reporter": {
|
|
20
24
|
"types": "./dist/reporter.d.ts",
|
|
21
25
|
"default": "./dist/reporter.js"
|
|
@@ -27,6 +31,7 @@
|
|
|
27
31
|
"scripts": {
|
|
28
32
|
"preinstall": "npx only-allow pnpm",
|
|
29
33
|
"build": "pnpm run clean && pnpm run compile && pnpm run bundle",
|
|
34
|
+
"prepublishOnly": "pnpm run build",
|
|
30
35
|
"clean": "rimraf dist",
|
|
31
36
|
"compile": "tsc -p tsconfig.build.json",
|
|
32
37
|
"bundle": "vite build"
|