vite-uni-dev-tool
Version:
vite-uni-dev-tool, debug, uni-app, 一处编写,到处调试
811 lines (717 loc) • 18.3 kB
text/typescript
import { backup } from '../core';
import {
DEV_BUTTON_SHOW_OR_HIDE,
DEV_CONSOLE_CLEAR,
DEV_DESTROY,
DEV_EXPORT_LOG,
DEV_IS_DESTROY,
DEV_LOG_CACHE_CLEAR,
DEV_NETWORK_CLEAR,
DEV_PAGE_JUMP,
DEV_PINIA_CHANGE,
DEV_RESTART_APP,
DEV_RESTART_DEBUGGER,
DEV_ROUTE_REFRESH,
DEV_STORAGE_ADD,
DEV_STORAGE_CLEAR,
DEV_STORAGE_REFRESH,
DEV_STORAGE_REMOVE,
DEV_STORAGE_UPDATE,
DEV_UPLOAD_CLEAR,
DEV_VUEX_CHANGE,
DEV_WEBSOCKET_CLEAR,
DEV_WINDOW_OPEN,
DEV_APP_MESSAGE,
DEV_BUTTON_VISIBLE,
DEV_WINDOW_VISIBLE,
DEV_WINDOW_MESSAGE,
DEV_WINDOW_CLOSE,
DEV_OPTION_GET,
DEV_OPTION_SEND,
DEV_UNI_EVENT_CLEAR,
DEV_RUN_JS,
DEV_CAPTURE_SCREEN_CLEAR,
} from '../const';
import { DevStore } from '../devStore';
import type { DevTool } from '../type';
import {
formatStorageSize,
calculateObjectSize,
throttle,
saveTxtFileApp,
saveTextFileH5,
saveTextFileMicro,
getCurrentDate,
isNil,
transformValueToView,
parseValue,
} from '../utils/index';
import type { EventBus } from '../devEventBus';
/**
* 事件中心
*
* @export
* @class DevEvent
*/
export class DevEvent {
private store: DevStore;
private eventBus: EventBus;
constructor({ store, eventBus }: { store: DevStore; eventBus: EventBus }) {
this.store = store;
this.eventBus = eventBus;
this.acceptMessage();
}
/**
* 发送数据
*
* @param {DevTool.WindowData} data
* @memberof DevEvent
*/
async postMessageFn() {
if (this.getDevToolDestroy()) {
return;
}
const data = await this.store.getDevData();
const size = calculateObjectSize(data);
const sizeFormat = formatStorageSize(size);
data.size = size;
data.sizeFormat = sizeFormat;
this.eventBus.emit(DEV_APP_MESSAGE, data);
if (size > this.store.cacheMaxSize) {
this.store?.clearDevCache();
}
}
/**
* 发送数据 节流
*
* @memberof DevEvent
*/
postMessage = throttle(this.postMessageFn, 1000);
/**
* 创建调试器
*
* @return {*}
* @memberof DevEvent
*/
createDevTool() {
if (!this.getDevToolDestroy()) {
console.warn('[DevTool] 调试器已存在,不在重新创建');
return;
}
this.store.setDevToolDestroy(false);
console.log('[DevTool] 调试器创建成功');
}
/**
* 销毁调试器
*
* @return {*}
* @memberof DevEvent
*/
destroyDevTool() {
if (this.getDevToolDestroy()) {
console.warn('[DevTool] 调试器已经销毁了,不在重新销毁');
return;
}
this.store.setRequestIndex(-1);
this.store.setUploadIndex(-1);
this.store.clearAll();
this.hideDevToolButton();
this.closeDevToolWindow();
this.resetInterceptAppConsole();
this.resetInterceptPromiseReject();
this.resetInterceptErrorApp();
this.resetInterceptWarnApp();
this.resetInterceptStorage();
this.resetInterceptUpload();
this.resetInterceptRequest();
this.resetInterceptNavigateTo();
this.resetInterceptSwitchTab();
this.resetUniEvent();
this.store.setDevToolDestroy(true);
// this.eventBus.clear();
console.warn('[DevTool] 调试器已销毁');
}
/**
* 重启调试器
*
* @memberof DevEvent
*/
restartDevTool() {
this.destroyDevTool();
this.createDevTool();
this.openDevToolWindow();
}
/**
* 打开调试器窗口
*
* @memberof DevEvent
*/
openDevToolWindow() {
if (this.getDevToolDestroy()) return;
setTimeout(async () => {
this.postMessage();
}, 100);
this.eventBus.emit(DEV_WINDOW_VISIBLE, true);
}
/**
* 关闭调试器窗口
*
* @memberof DevEvent
*/
closeDevToolWindow() {
if (this.getDevToolDestroy()) return;
this.eventBus.emit(DEV_WINDOW_VISIBLE, false);
}
/**
* 显示调试按钮
*
* @export
*/
showDevToolButton() {
if (this.getDevToolDestroy()) return;
this.eventBus.emit(DEV_BUTTON_VISIBLE, true);
this.store.setDevToolVisible(true);
}
/**
* 隐藏调试按钮
*
* @return {*}
*/
hideDevToolButton() {
if (this.getDevToolDestroy()) return;
this.eventBus.emit(DEV_BUTTON_VISIBLE, false);
this.store.setDevToolVisible(false);
}
exportLog(data: {
exportLog: boolean;
exportNetwork: boolean;
exportStorage: boolean;
exportWebSocket: boolean;
exportUpload: boolean;
exportWindow: boolean;
exportDevice: boolean;
exportSystem: boolean;
}) {
const exportData = this.store.getExportData(data);
// #ifdef APP-PLUS
saveTxtFileApp(JSON.stringify(exportData, null, 2), 'dev-tool-log');
// #endif
// #ifdef H5
saveTextFileH5(JSON.stringify(exportData, null, 2), 'dev-tool-log');
// #endif
// #ifdef MP-WEIXIN
saveTextFileMicro(JSON.stringify(exportData, null, 2), 'dev-tool-log');
// #endif
}
/**
* 切换页面
*
* @param {string} path
* @memberof DevEvent
*/
switchTo(path: string) {
// this.showDevToolButton();
this.closeDevToolWindow();
uni.switchTab({
url: path,
});
}
/**
* 跳转页面
*
* @param {string} path
* @memberof DevEvent
*/
navigateTo(path: string) {
// this.showDevToolButton();
this.closeDevToolWindow();
uni.navigateTo({
url: path,
});
}
/**
* 重启app
*
* @memberof DevEvent
*/
restartApp() {
// #ifdef APP-PLUS
plus.runtime.restart();
// #endif
// #ifdef H5
window.location.reload();
// #endif
// #ifdef MP-WEIXIN
uni.reLaunch({
url: '/' + this.store.getCurrentPagePath(),
});
// #endif
}
refreshRouteList() {
this.store.getRouteList();
this.postMessage();
}
sendDevToolOption() {
const options = this.store.getDevToolOptions();
this.eventBus.emit(DEV_OPTION_SEND, options);
}
/**
* 接受消息
*
* @memberof DevEvent
*/
acceptMessage() {
this.eventBus.on(
DEV_WINDOW_MESSAGE,
(data: {
type: string;
data: {
key: string;
_oldKey: string;
value: any;
exportLog: boolean;
exportNetwork: boolean;
exportStorage: boolean;
exportWebSocket: boolean;
exportUpload: boolean;
exportWindow: boolean;
exportDevice: boolean;
exportSystem: boolean;
code: string;
[key: string]: any;
};
}) => {
// 清空console数据
if (data.type === DEV_CONSOLE_CLEAR) {
this.store.clearConsoleList();
}
// 清空network数据
else if (data.type === DEV_NETWORK_CLEAR) {
this.store.clearNetworkList();
}
// 清空websocket数据
else if (data.type === DEV_WEBSOCKET_CLEAR) {
this.store.clearWsList();
}
// 清空上传信息
else if (data.type === DEV_UPLOAD_CLEAR) {
this.store.clearUploadList();
}
// 清空storage数据
else if (data.type === DEV_STORAGE_CLEAR) {
this.store.clearStorageList();
}
// 刷新storage数据
else if (data.type === DEV_STORAGE_REFRESH) {
this.store.refreshStore();
this.postMessage();
}
// 移除storage数据
else if (data.type === DEV_STORAGE_REMOVE) {
this.store.removeStorage(data.data.key + '');
this.postMessage();
}
// 新增storage数据
else if (data.type === DEV_STORAGE_ADD) {
this.store.addStorage(data.data);
this.postMessage();
}
// 改变storage数据
else if (data.type === DEV_STORAGE_UPDATE) {
this.store.updateStore(data.data);
this.postMessage();
}
// 切换页面
else if (data.type === DEV_PAGE_JUMP) {
data.data?.type === 'nav'
? this.switchTo(data.data.path ?? '')
: this.navigateTo(data.data.path ?? '');
}
// 隐藏调试按钮
else if (data.type === DEV_BUTTON_SHOW_OR_HIDE) {
data.data.show ? this.showDevToolButton() : this.hideDevToolButton();
this.postMessage();
}
// 重启调试器
else if (data.type === DEV_RESTART_DEBUGGER) {
this.restartDevTool();
}
// 重启app
else if (data.type === DEV_RESTART_APP) {
this.restartApp();
}
// 导出日志
else if (data.type === DEV_EXPORT_LOG) {
this.exportLog(data.data);
}
// 改变vuex数据
else if (data.type === DEV_VUEX_CHANGE) {
this.store.updateVuexStore(data.data);
this.postMessage();
}
// 改变pinia数据
else if (data.type === DEV_PINIA_CHANGE) {
this.store.updatePiniaStore(data.data);
this.postMessage();
}
// 清除缓存
else if (data.type === DEV_LOG_CACHE_CLEAR) {
this.store.clearDevCache();
}
// 销毁工具
else if (data.type === DEV_DESTROY) {
this.destroyDevTool();
}
// 显示工具
else if (data.type === DEV_WINDOW_OPEN) {
this.openDevToolWindow();
}
// 隐藏工具
else if (data.type === DEV_WINDOW_CLOSE) {
this.closeDevToolWindow();
}
// 刷新路由列表
else if (data.type === DEV_ROUTE_REFRESH) {
this.refreshRouteList();
}
// 获取dev options 数据
else if (data.type === DEV_OPTION_GET) {
this.sendDevToolOption();
}
// 清空事件
else if (data.type === DEV_UNI_EVENT_CLEAR) {
this.uniEventClear();
}
// 运行 js
else if (data.type === DEV_RUN_JS) {
this.devRunJS(data.data.code);
}
// 清空截屏列表
else if (data.type === DEV_CAPTURE_SCREEN_CLEAR) {
this.store.clearCaptureScreenList();
}
},
);
}
/**
* 重置拦截 promise reject
*
* @memberof DevEvent
*/
resetInterceptPromiseReject() {
Object.defineProperty(Promise, 'reject', {
value: function (reason: any) {
return backup.reject.call(Promise, reason);
},
});
}
/**
* 重置劫持 app 错误
*
* @memberof DevEvent
*/
resetInterceptErrorApp() {}
/**
* 重置劫持 app 警告
*
* @memberof DevEvent
*/
resetInterceptWarnApp() {}
/**
* 更新路由信息
*
* @param {string} path
* @memberof DevEvent
*/
updateCurrentPagePath(path: string) {
this.store.updateCurrentPagePath(path);
this.postMessage();
}
/**
* 重置 nav 跳转
*
* @memberof DevEvent
*/
resetInterceptSwitchTab() {
uni.removeInterceptor('switchTab');
}
/**
* 重置页面跳转
*
* @memberof DevEvent
*/
resetInterceptNavigateTo() {
uni.removeInterceptor('navigateTo');
}
/**
* 清除console日志
*
* @memberof DevEvent
*/
clearConsoleList() {
this.store.clearConsoleList();
this.postMessage();
}
/**
* 更新控制台日志
*
* @param {DevTool.ConsoleItem[]} addItems
* @param {number} [index]
* @memberof DevEvent
*/
updateConsoleList(addItems: DevTool.ConsoleItem[], index?: number) {
this.store.updateConsoleList(addItems, index);
this.postMessage();
}
/**
* 重置console
*
* @memberof DevEvent
*/
resetInterceptAppConsole() {
if ((uni as any).__log__) {
(uni as any).__log__ = backup.__log__;
}
}
/**
* 更新网络日志
*
* @param {DevTool.NetworkItem[]} addItems
* @param {number} [index]
* @memberof DevEvent
*/
updateNetworkList(addItems: DevTool.NetworkItem[], index?: number) {
this.store.updateNetworkList(addItems, index);
this.postMessage();
}
/**
* 重置网络监听
*
* @memberof DevEvent
*/
resetInterceptRequest() {
uni.removeInterceptor('request');
}
/**
* 更新websocket日志
*
* @param {DevTool.WS} item
* @memberof DevEvent
*/
updateWsList(item: DevTool.WS) {
this.store.updateWsList(item);
this.postMessage();
}
/**
* 重置websocket
*
* @memberof DevEvent
*/
resetWebSocket() {
uni.connectSocket = backup.connectSocket;
}
/**
* 更新状态存储
*
* @param {DevTool.StorageItem[]} addItems
* @memberof DevEvent
*/
updateStoreList(addItems: DevTool.StorageItem[]) {
this.store.updateStoreList(addItems);
this.postMessage();
}
/**
* 移除状态
*
* @param {string} key
* @memberof DevEvent
*/
removeStorage(key: string) {
this.store.removeStorage(key);
this.postMessage();
}
/**
* 清除缓存
*
* @memberof DevEvent
*/
clearStorage() {
this.store.clearStorageList();
}
/**
* 重置 storage 函数
*
* @memberof DevEvent
*/
resetInterceptStorage() {
uni.setStorage = backup.setStorage;
uni.setStorageSync = backup.setStorageSync;
uni.clearStorage = backup.clearStorage;
uni.clearStorageSync = backup.clearStorageSync;
uni.removeStorage = backup.removeStorage;
uni.removeStorageSync = backup.removeStorageSync;
}
/**
* 更新上传日志
*
* @param {DevTool.UploadItem[]} addItems
* @param {number} [index]
* @memberof DevEvent
*/
updateUploadList(addItems: DevTool.UploadItem[], index?: number) {
this.store.updateUploadList(addItems, index);
this.postMessage();
}
/**
* 移除上传任务
*
* @param {(number | string)} index
* @memberof DevEvent
*/
removeUploadTask(index: number | string) {
this.store.removeUploadTask(index);
}
/**
* 新增上传任务
*
* @param {(number | string)} index
* @param {UniApp.UploadTask} task
* @memberof DevEvent
*/
addUploadTask(index: number | string, task: UniApp.UploadTask) {
this.store.addUploadTask(index, task);
}
/**
* 重置 uni.uploadFile
*
* @memberof DevEvent
*/
resetInterceptUpload() {
uni.uploadFile = backup.uploadFile;
}
setRequestIndex(index: number) {
return this.store.setRequestIndex(index);
}
getRequestIndex() {
return this.store.getRequestIndex();
}
setUploadIndex(index: number) {
return this.store.setUploadIndex(index);
}
getUploadIndex() {
return this.store.getUploadIndex();
}
setVuexList(list: Record<string, any>) {
this.store.setVuexList(list);
}
setPiniaList(list: Record<string, any>) {
this.store.setPiniaList(list);
}
setPiniaStore(piniaStore: any) {
this.store.setPiniaStore(piniaStore);
}
getDevToolDestroy() {
return this.store.getDevToolDestroy();
}
updateUniEventCount(type: DevTool.EventCountKey) {
this.store.updateUniEventCount(type);
this.postMessage();
}
updateUniEventList(eventList: DevTool.EventItem[]) {
this.store.updateUniEventList(eventList);
this.postMessage();
}
uniEventClear() {
this.store.uniEventClear();
}
resetUniEvent() {
uni.$on = backup.$on;
uni.$once = backup.$once;
uni.$emit = backup.$emit;
uni.$off = backup.$off;
}
execute(code: any): Promise<any> {
const evalFunction = '_e_v_a_l_'.replace(
/_/g,
'',
) as keyof typeof globalThis;
if (!globalThis?.[evalFunction]) {
return Promise.reject(
new Error('[DevTool] DevRunJS 当前环境不支持执行js'),
);
}
return Promise.resolve(globalThis?.[evalFunction](code));
}
/**
* 运行js
*
* @param {string} code
* @memberof DevEvent
*/
devRunJS(code: string) {
const start = Date.now();
const consoleItem: DevTool.ConsoleItem = {
type: 'log',
args: [
{
type: 'string',
value: code,
},
],
position: 'dev/devEvent/index.ts',
time: getCurrentDate(),
stack: 'http://usr/devRunJS',
mode: 'input',
};
console.log(code);
this.store.updateConsoleList([{ ...consoleItem }]);
this.postMessageFn();
this.execute(code)
.then((res) => {
consoleItem.args = [
{
type: transformValueToView(res),
value: parseValue(res),
},
];
consoleItem.position = `dev/devEvent/index.ts ${Date.now() - start}ms`;
consoleItem.time = getCurrentDate();
consoleItem.mode = 'output';
})
.catch((err: Error) => {
console.error(err);
consoleItem.args = [
{
type: 'string',
value: err.message,
},
];
consoleItem.position = `dev/devEvent/index.ts ${Date.now() - start}ms`;
consoleItem.time = getCurrentDate();
consoleItem.type = 'error';
consoleItem.mode = 'output';
})
.finally(() => {
this.store.updateConsoleList([{ ...consoleItem }]);
this.postMessageFn();
});
}
/**
* 更新截屏列表
*
* @param {DevTool.CaptureScreenItem[]} list
* @memberof DevEvent
*/
updateCaptureScreenList(list: DevTool.CaptureScreenItem[]) {
this.store.updateCaptureScreenList(list);
this.postMessage();
}
/**
* 清空截屏列表
*
* @memberof DevEvent
*/
clearCaptureScreenList() {
this.store.clearCaptureScreenList();
}
}