UNPKG

vite-uni-dev-tool

Version:

vite-uni-dev-tool, debug, uni-app, 一处编写,到处调试

811 lines (717 loc) 18.3 kB
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(); } }