vite-uni-dev-tool 0.0.4 → 0.0.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # vite-uni-dev-tool
2
2
 
3
- 用于 vue3 + ts + uni-app 的开发调试插件
3
+ 用于 vue3 + ts + hooks + uni-app 的开发调试插件
4
4
 
5
5
  ## 安装
6
6
 
@@ -28,7 +28,7 @@ import * as path from 'path';
28
28
  // https://vitejs.dev/config/
29
29
  export default defineConfig({
30
30
  plugins: [
31
- // 一定要在 uni() 之前调用 否则微信小程序将无法解组件
31
+ // 一定要在 uni() 之前调用 否则微信小程序将无法正常编译组件
32
32
  uniDevTool({
33
33
  pages,
34
34
  }),
@@ -46,6 +46,27 @@ export default defineConfig({
46
46
  });
47
47
  ```
48
48
 
49
+ ### 为什么不用 subPackages?
50
+
51
+ - 从当前页跳转到subPackages页面时,会触发 uni-app 页面生命周期,有时是不希望如此的,比如在开发过程中,希望可以直接在当前页面进行调试。
52
+
53
+ ### 如何将 console 日志输出到控制台
54
+
55
+ - 0.0.5版本之后为了在生产环境中移除插件,开发环境中插件将会自动导入 `console`,无需手动导入
56
+
57
+ - 0.0.5版本之后不推荐使用 `uni.__dev__console` , 在未来版本中可能会进行移除
58
+
59
+ ```ts
60
+ // 方法 1
61
+ import { console } from 'vite-uni-dev-tool/dev/core';
62
+
63
+ console.log('hello vite-uni-dev-tool');
64
+
65
+ // 方法 2
66
+
67
+ uni.__dev__console.log('hello vite-uni-dev-tool');
68
+ ```
69
+
49
70
  ### 注意事项
50
71
 
51
72
  ### 兼容性说明
@@ -58,6 +79,13 @@ export default defineConfig({
58
79
  | ---------- | ---- | ------ |
59
80
  | Y | Y | 未测试 |
60
81
 
82
+ ### 安全性声明
83
+
84
+ 插件不收收集任何信息,只供开发人员调试使用
85
+
86
+ - 插件中使用到了 `fs`,用于栈信息获取源代码文件
87
+ - 插件使用了 `uni.request` ,用于栈信息获取源代码文件
88
+
61
89
  ### 预览
62
90
 
63
91
  ![all.png](https://gitee.com/cloud_l/vite-uni-dev-tool/raw/master/packages/docs/public/all.png)
@@ -120,3 +148,29 @@ export default defineConfig({
120
148
  - setting 页,支持重启,导出日志(h5,app)
121
149
 
122
150
  ![image.png](https://gitee.com/cloud_l/vite-uni-dev-tool/raw/master/packages/docs/public/setting.jpg)
151
+
152
+ ## 更新日志
153
+
154
+ ### 0.0.6
155
+ - 修复 app 查看 source 重启
156
+
157
+ ### 0.0.5
158
+
159
+ - 修复 路由支持跳转 subPackages
160
+ - 增加栈位置查看(实验中功能)
161
+
162
+ ### 0.0.4
163
+
164
+ - 修复初始启用状态
165
+
166
+ ### 0.0.3
167
+
168
+ - 文档调整
169
+
170
+ ### 0.0.2
171
+
172
+ - 文档调整
173
+
174
+ ### 0.0.1
175
+
176
+ - 初始版本发布
@@ -21,5 +21,6 @@ function onClick() {
21
21
  border-radius: 50%;
22
22
  border: 1px solid #000;
23
23
  box-sizing: border-box;
24
+ color: #000;
24
25
  }
25
26
  </style>
@@ -0,0 +1,227 @@
1
+ <template>
2
+ <view class="dev-tool-code">
3
+ <view class="dev-tool-code-control">
4
+ <FilterInput
5
+ v-model="modelValue"
6
+ style="width: 100%"
7
+ @search="onSearch"
8
+ />
9
+ <CloseButton style="margin-left: auto" @click="onClose" />
10
+ </view>
11
+ <view class="dev-tool-code-title">{{ fileName }}</view>
12
+ <scroll-view
13
+ scroll-y="true"
14
+ scroll-x="true"
15
+ class="dev-tool-code-list"
16
+ scroll-with-animation="true"
17
+ :scroll-top="scrollTop"
18
+ :scroll-into-view="scrollIntoView"
19
+ >
20
+ <view
21
+ v-for="(code, index) in codes"
22
+ :id="`dev-tool-code-item-${index}`"
23
+ :key="index"
24
+ :class="`dev-tool-code-item ${index === activeRowCol.activeRow ? 'dev-tool-code-item-active' : ''}`"
25
+ >
26
+ <view class="dev-tool-code-item-index"> {{ index + 1 }}</view>
27
+
28
+ <view class="dev-tool-code-item-content" v-html="code"></view>
29
+ </view>
30
+ <Empty v-if="!codes || codes.length === 0" />
31
+ </scroll-view>
32
+ </view>
33
+ </template>
34
+ <script lang="ts" setup>
35
+ import { computed, ref, nextTick, onMounted } from 'vue';
36
+ import FilterInput from '../FilterInput/index.vue';
37
+ import CloseButton from '../CloseButton/index.vue';
38
+ import Empty from '../Empty/index.vue';
39
+ import { escapeHTML, hightLight, isAndroid, parseStock } from '../../utils';
40
+
41
+ const props = defineProps<{
42
+ url: string;
43
+ sourceFileServers?: string[];
44
+ mode?: string;
45
+ }>();
46
+
47
+ const emit = defineEmits<{ (e: 'close'): void }>();
48
+
49
+ const modelValue = ref('');
50
+ const scrollTop = ref(0);
51
+ const fileName = computed(() => {
52
+ const name =
53
+ props?.url?.split('/')?.pop()?.replace(/\)|\(/, '') ?? '文件名称未知';
54
+ return name;
55
+ });
56
+
57
+ const activeRowCol = ref({ row: -1, col: -1, activeRow: -1 });
58
+
59
+ let backupCodes: string[] = [];
60
+
61
+ const codes = ref<string[]>([]);
62
+
63
+ const scrollIntoView = ref('');
64
+
65
+ function onClose() {
66
+ emit('close');
67
+ }
68
+
69
+ function onSearch(value: string) {
70
+ codes.value = backupCodes.map((code) => {
71
+ return hightLight(code, value);
72
+ });
73
+ }
74
+
75
+ let index = 0;
76
+ function getCode(url: string, i: number = 0) {
77
+ let allUrl = url;
78
+ // 平台判断
79
+ if (isAndroid()) {
80
+ if (!props.sourceFileServers?.[i]) {
81
+ index = 0;
82
+ return;
83
+ }
84
+
85
+ allUrl = props.sourceFileServers?.[i] + '/src/' + url;
86
+ }
87
+
88
+ uni.showLoading({ mask: true });
89
+ uni.request({
90
+ url: allUrl,
91
+ success: (res) => {
92
+ if (typeof res.data === 'string') {
93
+ // 为什么要注释掉?
94
+ // 在 Android 识别到标签后会进行重启,导致代码无法显示
95
+ // TODO: 还有其它原因导致重启
96
+ const str = res.data
97
+ ?.replace(/<jscript/, '// [DevTool] 注释 <javascript')
98
+ ?.replace(/<\/script>/, '// [DevTool] 注释 </javascript>')
99
+ ?.replace(/<style/, '// [DevTool] 注释 <style')
100
+ ?.replace(/<\/style>/, '// [DevTool] 注释 </style>');
101
+ backupCodes = escapeHTML(str ?? '')
102
+ .toString()
103
+ .split('\n');
104
+
105
+ const start =
106
+ activeRowCol.value.row - 20 > 0 ? activeRowCol.value.row - 20 : 0;
107
+
108
+ const end =
109
+ activeRowCol.value.row + 20 > backupCodes.length
110
+ ? backupCodes.length
111
+ : activeRowCol.value.row + 20;
112
+
113
+ // backupCodes.slice(start, end);
114
+
115
+ codes.value = backupCodes.slice(start, end);
116
+
117
+ activeRowCol.value.activeRow = activeRowCol.value.row - start;
118
+
119
+ nextTick(() => {
120
+ scrollIntoView.value = `dev-tool-code-item-${activeRowCol.value.activeRow}`;
121
+ });
122
+ }
123
+ },
124
+ fail: (err) => {
125
+ index++;
126
+ getCode(url, index);
127
+ uni.showToast({ icon: 'none', title: '正在重新尝试中...' });
128
+ },
129
+ complete: () => {
130
+ uni.hideLoading();
131
+ },
132
+ });
133
+ }
134
+
135
+ /** 开发环境获取源代码 */
136
+ function getSourceCodeDev(url: string) {
137
+ if (!url) {
138
+ uni.showToast({ icon: 'none', title: '[DevTool] url 处理异常' });
139
+ uni?.__dev__console?.log('[DevTool] url 处理异常');
140
+ return;
141
+ }
142
+
143
+ getCode(url, index);
144
+ }
145
+
146
+ onMounted(() => {
147
+ let url = props?.url;
148
+
149
+ const { path, col, row } = parseStock(props?.url ?? '');
150
+
151
+ if (path) {
152
+ url = path;
153
+ }
154
+
155
+ activeRowCol.value.col = col;
156
+ activeRowCol.value.row = row;
157
+
158
+ if (props.mode === 'development') {
159
+ // 开发环境查看源码
160
+ getSourceCodeDev(url);
161
+ } else if (props.mode === 'production') {
162
+ // TODO 生产环境查看源码
163
+ }
164
+ });
165
+ </script>
166
+ <style scoped>
167
+ .dev-tool-code {
168
+ position: fixed;
169
+ width: 100vw;
170
+ height: 100vh;
171
+ z-index: 10000;
172
+ top: 0;
173
+ left: 0;
174
+ padding: 0 16px;
175
+ /* #ifdef H5 */
176
+ padding: 50px 16px;
177
+ /* #endif */
178
+
179
+ background-color: rgba(255, 255, 255, 0.95);
180
+ box-sizing: border-box;
181
+ color: #000;
182
+ }
183
+
184
+ .dev-tool-code-control {
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 12px;
188
+ height: 32px;
189
+ border-bottom: 1px solid var(--dev-tool-border-color);
190
+ box-sizing: border-box;
191
+ }
192
+
193
+ .dev-tool-code-title {
194
+ height: 32px;
195
+ line-height: 32px;
196
+ margin-bottom: 4px;
197
+ border-bottom: 1px solid var(--dev-tool-border-color);
198
+ box-sizing: border-box;
199
+ white-space: nowrap;
200
+ overflow: auto;
201
+ }
202
+
203
+ .dev-tool-code-list {
204
+ height: calc(100% - 68px);
205
+ }
206
+
207
+ .dev-tool-code-item {
208
+ display: flex;
209
+ align-items: center;
210
+ height: 28px;
211
+ }
212
+ .dev-tool-code-item-active {
213
+ color: #fff;
214
+ background-color: var(--dev-tool-main-color);
215
+ }
216
+
217
+ .dev-tool-code-item-index {
218
+ flex-shrink: 0;
219
+ width: 20px;
220
+ margin-right: 8px;
221
+ text-align: right;
222
+ }
223
+
224
+ .dev-tool-code-item-content {
225
+ white-space: pre;
226
+ }
227
+ </style>
@@ -18,21 +18,85 @@
18
18
  <view class="console-time">{{ consoleItem.time }}</view>
19
19
  <view class="console-other" v-html="consoleItem.position"></view>
20
20
  <view
21
- class="console-other"
21
+ :class="`console-other ${isUseDevSource ? 'console-stack' : ''}`"
22
22
  v-if="consoleItem.stack"
23
23
  v-html="consoleItem.stack"
24
+ @click="onStackClick"
24
25
  ></view>
25
26
  </view>
26
27
  </view>
27
28
  </view>
28
29
  <!-- <view class="console-copy">C</view> -->
30
+ <Code
31
+ v-if="openCode && consoleItem.stack"
32
+ :url="consoleItem.stack"
33
+ :sourceFileServers="sourceFileServers"
34
+ :mode="mode"
35
+ @close="onCloseCode"
36
+ />
29
37
  </view>
30
38
  </template>
31
39
 
32
40
  <script setup lang="ts">
41
+ import { ref, computed } from 'vue';
33
42
  import Tag from '../Tag/index.vue';
43
+ import Code from './Code.vue';
34
44
  import type { DevTool } from '../../type';
35
- defineProps<{ consoleItem: DevTool.ConsoleItem }>();
45
+ import { isAndroid, isMockWX } from '../../utils';
46
+ const props = defineProps<{
47
+ consoleItem: DevTool.ConsoleItem;
48
+ sourceFileServers?: string[];
49
+ mode?: string;
50
+ useDevSource?: boolean;
51
+ }>();
52
+
53
+ const openCode = ref(false);
54
+
55
+ const isUseDevSource = computed(() => {
56
+ return (
57
+ !isMockWX(props?.consoleItem?.stack ?? '') &&
58
+ props.mode === 'development' &&
59
+ props.useDevSource
60
+ );
61
+ });
62
+
63
+ const isWXLink = computed(() => {
64
+ return (
65
+ isMockWX(props?.consoleItem?.stack ?? '') || props.mode !== 'development'
66
+ );
67
+ });
68
+
69
+ function onStackClick() {
70
+ if (isWXLink.value) {
71
+ uni.showToast({
72
+ icon: 'none',
73
+ title: '[DevTool] 请在小程序真机调试模式下查看源码',
74
+ });
75
+ return;
76
+ }
77
+
78
+ if (!isUseDevSource.value) {
79
+ return;
80
+ }
81
+
82
+ if (isAndroid()) {
83
+ if (props.sourceFileServers && props.sourceFileServers.length > 0) {
84
+ openCode.value = true;
85
+ } else {
86
+ uni.showToast({
87
+ icon: 'none',
88
+ title: '[DevTool] sourceFileServers 配置异常',
89
+ });
90
+ uni?.__dev__console?.log('[DevTool] sourceFileServers 配置异常');
91
+ }
92
+ } else {
93
+ openCode.value = true;
94
+ }
95
+ }
96
+
97
+ function onCloseCode() {
98
+ openCode.value = false;
99
+ }
36
100
  </script>
37
101
  <style scoped>
38
102
  .console-item {
@@ -41,19 +105,20 @@ defineProps<{ consoleItem: DevTool.ConsoleItem }>();
41
105
  border-bottom: 1px solid var(--dev-tool-border-color);
42
106
  font-size: var(--dev-tool-base-font-size);
43
107
  }
44
- .console-item .console-info {
108
+ .console-info {
45
109
  flex: 1;
46
110
  }
47
- .console-item .console-info .console-args {
111
+ .console-args {
48
112
  display: flex;
49
113
  flex-wrap: wrap;
50
114
  color: #000;
51
115
  }
52
- .console-item .console-info .console-args .console-arg {
116
+ .console-arg {
53
117
  margin-right: 4px;
118
+ white-space: pre-line;
54
119
  word-break: break-all;
55
120
  }
56
- .console-item .console-info .console-position {
121
+ .console-position {
57
122
  display: flex;
58
123
  align-items: flex-start;
59
124
  justify-content: space-between;
@@ -61,14 +126,20 @@ defineProps<{ consoleItem: DevTool.ConsoleItem }>();
61
126
  color: #616161;
62
127
  text-align: right;
63
128
  }
64
- .console-item .console-info .console-position .console-time {
129
+ .console-time {
65
130
  margin-right: auto;
66
131
  word-break: break-all;
67
132
  }
68
- .console-item .console-info .console-position .console-other {
133
+ .console-other {
69
134
  word-break: break-all;
70
135
  }
71
- .console-item .console-copy {
136
+
137
+ .console-stack {
138
+ text-decoration: underline;
139
+ cursor: pointer;
140
+ }
141
+
142
+ .console-copy {
72
143
  flex-shrink: 0;
73
144
  margin-left: 16px;
74
145
  display: flex;
@@ -20,6 +20,9 @@
20
20
  v-for="(item, index) in consoleList"
21
21
  :consoleItem="item"
22
22
  :key="index"
23
+ :sourceFileServers="sourceFileServers"
24
+ :mode="mode"
25
+ :useDevSource="useDevSource"
23
26
  />
24
27
  <Empty v-if="!consoleList || consoleList.length === 0" />
25
28
  </view>
@@ -36,6 +39,9 @@ defineProps<{
36
39
  consoleList: DevTool.ConsoleItem[];
37
40
  currentConsoleType: string;
38
41
  modelValue: string;
42
+ sourceFileServers?: string[];
43
+ mode?: string;
44
+ useDevSource?: boolean;
39
45
  }>();
40
46
  const emit = defineEmits<{
41
47
  (e: 'choose', type: ConsoleType): void;
@@ -12,6 +12,9 @@
12
12
  <DevToolWindow
13
13
  :open="devToolWindowVisible"
14
14
  :data="windowData"
15
+ :sourceFileServers="sourceFileServers"
16
+ :mode="mode"
17
+ :useDevSource="useDevSource"
15
18
  @close="onShowDevToolWindow(false)"
16
19
  @sendMessage="onSendMessage"
17
20
  />
@@ -51,6 +54,13 @@ const windowData = ref<DevTool.WindowData>({});
51
54
 
52
55
  const devToolWindowVisible = ref(false);
53
56
  const devToolButtonVisible = ref(false);
57
+
58
+ const sourceFileServers = ref<string[]>([]);
59
+
60
+ const mode = ref<string>();
61
+
62
+ const useDevSource = ref(false);
63
+
54
64
  function onDevToolButtonClick() {
55
65
  onShowDevToolWindow(true);
56
66
  onSendMessage({
@@ -83,6 +93,12 @@ function onDevOptionSend(options: DevTool.DevToolOptions) {
83
93
  buttonProps.buttonFontSize = options.buttonFontSize ?? '16px';
84
94
  buttonProps.buttonBackgroundColor =
85
95
  options.buttonBackgroundColor ?? 'rgba(255, 255, 255, 0)';
96
+
97
+ sourceFileServers.value = options.sourceFileServers ?? [];
98
+
99
+ mode.value = options.mode ?? '';
100
+
101
+ useDevSource.value = options.useDevSource ?? false;
86
102
  }
87
103
  }
88
104
 
@@ -20,6 +20,9 @@
20
20
  <ConsoleList
21
21
  :currentConsoleType="currentConsoleType"
22
22
  :consoleList="consoleList"
23
+ :sourceFileServers="sourceFileServers"
24
+ :mode="mode"
25
+ :useDevSource="useDevSource"
23
26
  v-if="activeTab === 'Console'"
24
27
  v-model="searchConsole"
25
28
  @choose="onConsoleChoose"
@@ -260,7 +263,13 @@ const searchWs = ref('');
260
263
  const searchRoute = ref('');
261
264
  const searchStorage = ref('');
262
265
 
263
- const props = defineProps<{ open?: boolean; data?: DevTool.WindowData }>();
266
+ const props = defineProps<{
267
+ open?: boolean;
268
+ data?: DevTool.WindowData;
269
+ sourceFileServers?: string[];
270
+ mode?: string;
271
+ useDevSource?: boolean;
272
+ }>();
264
273
 
265
274
  const emits = defineEmits<{
266
275
  (e: 'close'): void;
@@ -700,7 +709,7 @@ function onGoTo(page: DevTool.Page) {
700
709
  type: DEV_PAGE_JUMP,
701
710
  data: {
702
711
  path: '/' + page.path,
703
- isNav: page.isNav,
712
+ type: page.type,
704
713
  },
705
714
  });
706
715
  }
@@ -14,7 +14,7 @@
14
14
  <view class="route-item" v-for="item in routeList" :key="item.path">
15
15
  <view class="route-item-name">
16
16
  <view v-html="item.name" />
17
- <Tag v-if="item.isNav" mode="info">Nav</Tag>
17
+ <Tag v-if="item.type" mode="info">{{ item.type }}</Tag>
18
18
  <Tag mode="warn" v-if="item.index === 4 || item.index === 3">
19
19
  当前页
20
20
  </Tag>
package/dev/core.ts CHANGED
@@ -45,7 +45,13 @@ function getDevToolOptions() {
45
45
  }
46
46
 
47
47
  function initDevTool(options?: DevTool.DevToolOptions) {
48
- store.setDevToolOptions(options || {});
48
+ if (!options?.mode) {
49
+ console.error('[DevTool] 请传入 mode: import.meta.env.MODE');
50
+ }
51
+
52
+ store.setDevToolOptions(options || { mode: '' });
53
+
54
+ intercept.interceptVue3(options?.vue3instance);
49
55
  }
50
56
 
51
57
  function showDevToolButton() {
@@ -56,7 +56,6 @@ export class DevConsole {
56
56
  const time = getCurrentDate();
57
57
  // 获取调用栈(从第4行开始,跳过 console.log 和 wrapper 函数)
58
58
  const stackList = new Error()?.stack?.split('\n');
59
-
60
59
  const stack = stackList?.slice(3)?.[0];
61
60
 
62
61
  let argList = args?.map((item) => serializeCircular(item));
@@ -351,7 +351,7 @@ export class DevEvent {
351
351
  }
352
352
  // 切换页面
353
353
  else if (data.type === DEV_PAGE_JUMP) {
354
- data.data?.isNav
354
+ data.data?.type === 'nav'
355
355
  ? this.switchTo(data.data.path ?? '')
356
356
  : this.navigateTo(data.data.path ?? '');
357
357
  }
@@ -2,14 +2,13 @@ import { backup } from '../core';
2
2
  import { DevEvent } from '../devEvent';
3
3
  import type { DevTool } from '../type';
4
4
  import {
5
+ escapeHTML,
5
6
  getCurrentDate,
6
7
  getCurrentPagePath,
7
8
  serializeCircular,
8
9
  } from '../utils/index';
9
10
  import { isObject } from '../utils/language';
10
11
 
11
- import { getCurrentInstance } from 'vue';
12
-
13
12
  /**
14
13
  * 拦截器
15
14
  *
@@ -19,8 +18,6 @@ import { getCurrentInstance } from 'vue';
19
18
  export class DevIntercept {
20
19
  private event: DevEvent;
21
20
 
22
- vue3instance = getCurrentInstance();
23
-
24
21
  initPinia = false;
25
22
 
26
23
  constructor(options: DevTool.DevInterceptOptions) {
@@ -29,14 +26,7 @@ export class DevIntercept {
29
26
  }
30
27
 
31
28
  init(options: DevTool.DevInterceptOptions) {
32
- if (this.vue3instance) {
33
- this.vue3instance.appContext.config.errorHandler = (error) => {
34
- this.interceptErrorApp(error);
35
- };
36
- this.vue3instance.appContext.config.warnHandler = (msg: string) => {
37
- this.interceptWarnApp(msg);
38
- };
39
- }
29
+ this.interceptAppError();
40
30
 
41
31
  this.interceptAppConsole();
42
32
 
@@ -97,25 +87,82 @@ export class DevIntercept {
97
87
  };
98
88
  }
99
89
 
90
+ /**
91
+ * 拦截 vue3 信息
92
+ *
93
+ * @memberof DevIntercept
94
+ */
95
+ interceptVue3(vue3instance: any) {
96
+ if (vue3instance) {
97
+ // 微信小程序触发了该事件
98
+ vue3instance.appContext.config.errorHandler = (
99
+ error: Error,
100
+ vm: any,
101
+ info: string,
102
+ ) => {
103
+ if (this.event.getDevToolDestroy()) {
104
+ return;
105
+ }
106
+ this.interceptErrorVue3(error);
107
+ };
108
+ vue3instance.appContext.config.warnHandler = (
109
+ msg: string,
110
+ vm: any,
111
+ trace: string,
112
+ ) => {
113
+ if (this.event.getDevToolDestroy()) {
114
+ return;
115
+ }
116
+
117
+ this.interceptWarnVue3(msg + '\n' + trace);
118
+ };
119
+ }
120
+ }
121
+
122
+ /**
123
+ * app 中捕获全局错误
124
+ *
125
+ * @memberof DevIntercept
126
+ */
127
+ interceptAppError() {
128
+ uni.onError((error) => {
129
+ if (this.event.getDevToolDestroy()) {
130
+ return;
131
+ }
132
+
133
+ const info = error.toString();
134
+ const stack = (error as unknown as Error)?.stack?.split('\n')?.[1] ?? '';
135
+
136
+ this.event.updateConsoleList([
137
+ {
138
+ type: 'error',
139
+ args: [info],
140
+ position: getCurrentPagePath(),
141
+ time: getCurrentDate(),
142
+ stack,
143
+ },
144
+ ]);
145
+ });
146
+ }
147
+
100
148
  /**
101
149
  * 拦截 app 错误
102
150
  *
103
151
  * @param {*} error
104
152
  * @memberof DevIntercept
105
153
  */
106
- interceptErrorApp(error: any) {
107
- const path = getCurrentPagePath();
108
- const argList = error.toString();
154
+ interceptErrorVue3(error: Error) {
155
+ const stackList = error?.stack?.split('\n');
109
156
 
110
- const stack = new Error()?.stack?.split('\n').slice(2)?.[0];
157
+ const stack = stackList?.[1];
111
158
 
112
159
  console.error(error);
113
160
 
114
161
  this.event.updateConsoleList([
115
162
  {
116
163
  type: 'error',
117
- args: [argList],
118
- position: path,
164
+ args: [error.toString()],
165
+ position: getCurrentPagePath(),
119
166
  time: getCurrentDate(),
120
167
  stack,
121
168
  },
@@ -130,18 +177,26 @@ export class DevIntercept {
130
177
  * @return {*}
131
178
  * @memberof DevIntercept
132
179
  */
133
- interceptWarnApp(warn: any) {
180
+ interceptWarnVue3(warn: string) {
134
181
  if (this.preWarn === warn) return;
135
182
  this.preWarn = warn;
136
183
  const path = getCurrentPagePath();
137
- const stack = new Error()?.stack?.split('\n').slice(2)?.[0];
184
+
185
+ const stackList = new Error()?.stack?.split('\n');
186
+
187
+ const stack = stackList?.slice(2)?.[0];
138
188
 
139
189
  console.warn(warn);
140
190
 
191
+ const args = warn
192
+ .split('\n')
193
+ ?.map((item) => escapeHTML(item))
194
+ .join('\n');
195
+
141
196
  this.event.updateConsoleList([
142
197
  {
143
198
  type: 'warn',
144
- args: [warn.toString()],
199
+ args: [args],
145
200
  position: path,
146
201
  time: getCurrentDate(),
147
202
  stack,
@@ -138,7 +138,7 @@ export class DevStore {
138
138
  : (options.initShowDevTool ?? true);
139
139
 
140
140
  this.setDevToolVisible(this.devToolVisible);
141
-
141
+
142
142
  const pages =
143
143
  options.pagesJson?.pages.map((page) => {
144
144
  const isNav = options.pagesJson?.tabBar?.list?.some(
@@ -146,9 +146,22 @@ export class DevStore {
146
146
  );
147
147
  return {
148
148
  ...page,
149
- isNav,
149
+ type: isNav ? 'nav' : 'main',
150
150
  };
151
151
  }) ?? [];
152
+
153
+ // 处理 subPackages
154
+ options.pagesJson?.subPackages?.forEach((pack) => {
155
+ pack.pages.forEach((page) => {
156
+ const p = {
157
+ ...page,
158
+ path: `${pack.root}/${page.path}`,
159
+ type: 'sub',
160
+ };
161
+ pages.push(p);
162
+ });
163
+ });
164
+
152
165
  this.setRouteList(pages);
153
166
  }
154
167
 
@@ -434,7 +447,7 @@ export class DevStore {
434
447
  const currentP = currentPath || pages?.[0]?.path || '';
435
448
  this.state.routeList = pages.map((item, index) => {
436
449
  return {
437
- isNav: item.isNav,
450
+ type: item.type,
438
451
  path: item.path,
439
452
  style: item.style,
440
453
  index:
@@ -463,7 +476,7 @@ export class DevStore {
463
476
  this.state.routeList =
464
477
  this.state.routeList?.map((item, index) => {
465
478
  return {
466
- isNav: item.isNav,
479
+ type: item.type,
467
480
  path: item.path,
468
481
  style: item.style,
469
482
  index:
package/dev/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { default as uniGlobalComponents } from './plugins/uniGlobalComponents/uniGlobalComponents';
2
2
  import { default as uniDevTool } from './plugins/uniDevTool/uniDevTool';
3
-
4
3
  export { uniDevTool, uniGlobalComponents };
5
4
  export default uniDevTool;
6
5
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,4 @@
1
1
  import { Plugin } from 'vite';
2
-
3
2
  /**
4
3
  * vite-uni-dev-tool 插件
5
4
  *
@@ -7,7 +6,6 @@ import { Plugin } from 'vite';
7
6
  *
8
7
  * 如果组件不是用 template 定义的,则不会被该插件添加。
9
8
  *
10
- * 如果在编译成微信小程序(开发环境 hbuilder 4.29) 组件 <dev-tool ></dev-tool> 中没有内容,应该开启 supportWX: true, 该属性默认关闭
11
9
  *
12
10
  * @export
13
11
  * @param {{
@@ -21,7 +19,7 @@ import { Plugin } from 'vite';
21
19
  * }
22
20
  * @return {*} {Plugin}
23
21
  */
24
- export default function uniDevTool({ pages, supportWX, ...reset }: {
22
+ export default function uniDevTool({ pages, sourceFileServers, ...reset }: {
25
23
  /** 是否拦截Promise.reject 最好不要拦截 默认禁用 */
26
24
  enableInterceptPromiseReject?: boolean;
27
25
  /** 打开窗口时隐藏按钮 */
@@ -49,18 +47,26 @@ export default function uniDevTool({ pages, supportWX, ...reset }: {
49
47
  /** 初始化时是否显示调试按钮,默认显示 */
50
48
  initShowDevTool?: boolean;
51
49
  /**
52
- * 在 hbuilder 4.29 可开发环境中无法正确的将 DevTool 组件编译完整 只有 wxml 文件其他是缺失的,开启该项将不使用 app.component('DevTool', DevTool) 方式注册组件, 将在每个 page 中直接引入组件
53
- *
54
- * 在 hbuilder 4.66 中还是这样...
55
- *
56
- * 打包构建完成之后 组件编译是完整的,可以关闭该项
50
+ * 该属性处于实验当中,谨慎使用
51
+ * 读取开发环境 source file,source map,默认 禁用
57
52
  */
58
- supportWX?: boolean;
53
+ useDevSource?: boolean;
54
+ /**
55
+ * 该属性处于实验当中,谨慎使用
56
+ * 开发环境 source file 服务器地址,默认 [] ,配合 useDevSource 使用
57
+ */
58
+ sourceFileServers?: string[];
59
59
  /** 页面配置 用于读取路由 */
60
60
  pages: {
61
61
  pages: {
62
62
  path: string;
63
63
  }[];
64
+ subPackages?: {
65
+ root: string;
66
+ pages: {
67
+ path: string;
68
+ }[];
69
+ }[];
64
70
  };
65
71
  }): Plugin;
66
72
  //# sourceMappingURL=uniDevTool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uniDevTool.d.ts","sourceRoot":"","sources":["../../../../plugins/src/plugins/uniDevTool/uniDevTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAkBnC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE;IACD,qCAAqC;IACrC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,gBAAgB;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,mBAAmB;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,WAAW;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa;IACb,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,wBAAwB;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kBAAkB;IAClB,KAAK,EAAE;QACL,KAAK,EAAE;YACL,IAAI,EAAE,MAAM,CAAC;SACd,EAAE,CAAC;KACL,CAAC;CACH,GAAG,MAAM,CAkHT"}
1
+ {"version":3,"file":"uniDevTool.d.ts","sourceRoot":"","sources":["../../../../plugins/src/plugins/uniDevTool/uniDevTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAsBnC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,KAAK,EACL,iBAAiB,EACjB,GAAG,KAAK,EACT,EAAE;IACD,qCAAqC;IACrC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,gBAAgB;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,mBAAmB;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa;IACb,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,wBAAwB;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,kBAAkB;IAClB,KAAK,EAAE;QACL,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC1B,WAAW,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,EAAE,CAAA;SAAE,EAAE,CAAC;KAC7D,CAAC;CACH,GAAG,MAAM,CAiOT"}
@@ -1,13 +1,38 @@
1
- "use strict";const u=/<template[^>]*>([\s\S]*?)<\/template>/,v=/<script[^>]*>([\s\S]*?)<\/script>/;function f(p,s){for(let i=0;i<p.length;i++)if(s(p[i]))return i+1;return-1}function T({pages:p,supportWX:s,...i}){return{name:"vite-uni-dev-tool",enforce:"pre",transform(e,m){if(m.endsWith("/src/main.ts"))try{const r=e.split(`
2
- `);let n=[...r];const c=f(n,t=>t.trim().startsWith("import")||t.trim().startsWith("export"));c!==-1&&n.splice(c,0,s?"":"import DevTool from 'vite-uni-dev-tool/dev/components/DevTool/index.vue';","import { initDevTool } from 'vite-uni-dev-tool/dev/core';","import pagesJson from './pages.json';");const o=f(n,t=>t.includes(".mount(")||t.includes("createApp("));if(o!==-1&&n.splice(o+1,0,s?"":" app.component('DevTool', DevTool);",` initDevTool({
3
- pagesJson,
4
- ...${JSON.stringify(i)}
5
- });`),n.length!==r.length)return{code:n.join(`
6
- `),map:null}}catch(r){return console.error("[DevTool] 转换 main 文件时出错:",r),{code:e,map:null}}if(m.endsWith(".vue")){const r=e.includes("<template>"),n=p.pages.some(o=>m.includes(o.path)),c=["<DevTool />"];if(n&&r){const o=e.match(u);let t=e;if(o&&o[1]){const a=`${o[1].trim()}
7
- ${c.join(`
8
- `)}`;t=e.replace(u,`<template>
9
- ${a}
10
- </template>`)}if(s){const l=e.match(v);if(l&&l[1]){const d=`import DevTool from 'vite-uni-dev-tool/dev/components/DevTool/index.vue';
11
- ${l[1].trim()}`;t=t.replace(v,`<script lang="ts" setup>
12
- ${d}
13
- <\/script>`)}}return{code:t,map:null}}}return{code:e,map:null}}}}module.exports=T;
1
+ "use strict";const I=require("path"),S=require("fs"),l=require("../utils/index.js");function C(a){const d=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const u in a)if(u!=="default"){const e=Object.getOwnPropertyDescriptor(a,u);Object.defineProperty(d,u,e.get?e:{enumerable:!0,get:()=>a[u]})}}return d.default=a,Object.freeze(d)}const D=C(I),y=C(S),_=/<template[^>]*>([\s\S]*?)<\/template>/,h=/<script[^>]*>([\s\S]*?)<\/script>/,g={isReady:!1,urls:[]};function T({pages:a,sourceFileServers:d,...u}){return{name:"vite-uni-dev-tool",enforce:"pre",configureServer(e){var p;e.middlewares.use((s,n,t)=>{const{originalUrl:r}=s;if(u.useDevSource&&(r!=null&&r.includes("__dev_sourcefile__"))){const i=r.replace("/__dev_sourcefile__","");try{const c=e.config.root,m=D.join(c,i),o=y.readFileSync(m,"utf-8");n.setHeader("Content-Type",l.getContentType(m)),n.end(o)}catch{t()}}else t()}),(p=e.httpServer)==null||p.once("listening",()=>{var t;const s=(t=e.httpServer)==null?void 0:t.address(),n=l.getLocalIPs();if(s&&!Array.isArray(s)&&typeof s!="string"){const r=n.map(i=>`http://${i}:${s.port}/__dev_sourcefile__`);g.isReady=!0,g.urls=r,console.warn(`
2
+ ⚡️ vite-uni-dev-tool source file server running at:
3
+ ${n.map(i=>`➜ Source File Network: http://${i}:${s==null?void 0:s.port}/__dev_sourcefile__`).join(`
4
+ `)}
5
+ `)}})},transform(e,p){var s;if(p.endsWith("/src/main.ts"))try{const n=e.split(`
6
+ `);let t=[...n];const r=l.findInsertionIndex(t,c=>c.trim().startsWith("import")||c.trim().startsWith("export"));r!==-1&&t.splice(r,0,"import DevTool from 'vite-uni-dev-tool/dev/components/DevTool/index.vue';");const i=l.findInsertionIndex(t,c=>c.includes(".mount(")||c.includes("createApp("));if(i!==-1&&t.splice(i+1,0," app.component('DevTool', DevTool);"),t.length!==n.length)return{code:t.join(`
7
+ `),map:null}}catch(n){return console.error("[DevTool] 转换 main 文件时出错:",n),{code:e,map:null}}if(p.endsWith("/src/App.vue")){const n=e.match(h);if(n&&n[1]){const t=n[1].trim(),r=l.hasImportCurrentInstance(t),i=l.hasImportOnLaunch(t),c=r?"":"import { getCurrentInstance } from 'vue'",m=i?"":"import { onLaunch } from '@dcloudio/uni-app'",o=`
8
+ import { initDevTool, console } from 'vite-uni-dev-tool/dev/core';
9
+ import pagesJson from './pages.json';
10
+ ${t}
11
+ onLaunch(() => {
12
+ const vue3instance = getCurrentInstance();
13
+ initDevTool({
14
+ pagesJson,
15
+ vue3instance,
16
+ mode: import.meta.env.MODE,
17
+ sourceFileServers: [
18
+ ${[...g.urls??[],...d??[]].map(v=>`'${v}'`)}
19
+ ],
20
+ useDevSource: ${u.useDevSource},
21
+ ...${JSON.stringify(u)},
22
+ });
23
+ });`;return{code:e.replace(h,`
24
+ <script lang="ts" setup>
25
+ ${c}
26
+ ${m}
27
+ ${o}
28
+ <\/script>`),map:null}}return{code:e,map:null}}if(p.endsWith(".vue")){const n=e.includes("<template>"),t=a.pages.some(o=>p.includes(o.path)),r=(s=a.subPackages)==null?void 0:s.some(o=>o.pages.some(f=>p.includes(`${o.root}/${f.path}`))),i=["<DevTool />"],c=l.hasImportConsole(e),m=l.hasUseConsole(e);if(!c&&m&&!p.endsWith("/src/App.vue")){const o=e.match(h);if(o&&o[1]){const v=`
29
+ import { console } from 'vite-uni-dev-tool/dev/core';
30
+ ${o[1]}
31
+ `;e=e.replace(h,`
32
+ <script lang="ts" setup>
33
+ ${v}
34
+ <\/script>`)}}if((t||r)&&n){const o=e.match(_);let f=e;if(o&&o[1]){const $=`${o[1].trim()}
35
+ ${i.join(`
36
+ `)}`;f=e.replace(_,`<template>
37
+ ${$}
38
+ </template>`)}return{code:f,map:null}}}return{code:e,map:null}}}}module.exports=T;
@@ -1,5 +1,4 @@
1
1
  import { Plugin } from 'vite';
2
-
3
2
  /**
4
3
  * uni-global-components 插件,用于在页面中添加全局组件
5
4
  *
@@ -22,6 +21,12 @@ export default function uniGlobalComponents({ pages, components, }: {
22
21
  pages: {
23
22
  path: string;
24
23
  }[];
24
+ subPackages?: {
25
+ root: string;
26
+ pages: {
27
+ path: string;
28
+ }[];
29
+ }[];
25
30
  };
26
31
  components: string[];
27
32
  }): Plugin;
@@ -1 +1 @@
1
- {"version":3,"file":"uniGlobalComponents.d.ts","sourceRoot":"","sources":["../../../../plugins/src/plugins/uniGlobalComponents/uniGlobalComponents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAC1C,KAAK,EACL,UAAU,GACX,EAAE;IACD,KAAK,EAAE;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;IACrC,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,MAAM,CAmCT"}
1
+ {"version":3,"file":"uniGlobalComponents.d.ts","sourceRoot":"","sources":["../../../../plugins/src/plugins/uniGlobalComponents/uniGlobalComponents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAsBnC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAC1C,KAAK,EACL,UAAU,GACX,EAAE;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC1B,WAAW,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,EAAE,CAAA;SAAE,EAAE,CAAC;KAC7D,CAAC;IACF,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,MAAM,CAsFT"}
@@ -1,5 +1,9 @@
1
- "use strict";const o=/<template[^>]*>([\s\S]*?)<\/template>/;function m({pages:s,components:a}){return{name:"uni-global-components",enforce:"pre",transform(t,n){if(n.endsWith(".vue")){const l=t.includes("<template>");if(s.pages.some(e=>n.includes(e.path))&&l){const e=t.match(o);if(e&&e[1]){const p=`${e[1].trim()}
1
+ "use strict";const d=require("path"),g=require("fs"),f=require("../utils/index.js");function _(s){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const e in s)if(e!=="default"){const r=Object.getOwnPropertyDescriptor(s,e);Object.defineProperty(a,e,r.get?r:{enumerable:!0,get:()=>s[e]})}}return a.default=s,Object.freeze(a)}const h=_(d),y=_(g),m=/<template[^>]*>([\s\S]*?)<\/template>/;function $({pages:s,components:a}){return{name:"uni-global-components",enforce:"pre",configureServer(e){var r;e.middlewares.use((t,c,i)=>{const{originalUrl:n}=t;if(n!=null&&n.includes("__dev_sourcefile__")){const o=n.replace("/__dev_sourcefile__","");try{const l=e.config.root,u=h.join(l,o),p=y.readFileSync(u,"utf-8");c.setHeader("Content-Type",f.getContentType(u)),c.end(p)}catch{i()}}else i()}),(r=e.httpServer)==null||r.once("listening",()=>{var i;const t=(i=e.httpServer)==null?void 0:i.address(),c=f.getLocalIPs();t&&!Array.isArray(t)&&typeof t!="string"&&(c.map(n=>`http://${n}:${t.port}/__dev_sourcefile__`),console.warn(`
2
+ ⚡️ vite-uni-dev-tool source file server running at:
3
+ ${c.map(n=>`➜ Source File Network: http://${n}:${t==null?void 0:t.port}/__dev_sourcefile__`).join(`
4
+ `)}
5
+ `))})},transform(e,r){var t;if(r.endsWith(".vue")){const c=e.includes("<template>"),i=s.pages.some(o=>r.includes(o.path)),n=(t=s.subPackages)==null?void 0:t.some(o=>o.pages.some(l=>r.includes(`${o.root}/${l.path}`)));if((i||n)&&c){const o=e.match(m);if(o&&o[1]){const u=`${o[1].trim()}
2
6
  ${a.join(`
3
- `)}`;return{code:t.replace(o,`<template>
4
- ${p}
5
- </template>`),map:null}}}}return{code:t,map:null}}}}module.exports=m;
7
+ `)}`;return{code:e.replace(m,`<template>
8
+ ${u}
9
+ </template>`),map:null}}}}return{code:e,map:null}}}}module.exports=$;
@@ -0,0 +1,53 @@
1
+ export declare function findInsertionIndex(lines: string[], condition: (p: string) => boolean): number;
2
+ export declare function getContentType(filePath: string): string;
3
+ export declare function getLocalIPs(): string[];
4
+ export declare function hasImportOnLaunch(str: string): boolean;
5
+ export declare function hasImportCurrentInstance(str: string): boolean;
6
+ export declare function hasImportConsole(str: string): boolean;
7
+ export declare function hasUseConsole(str: string): boolean;
8
+ /**
9
+ * 解析栈信息
10
+ *
11
+ * @export
12
+ * @param {string} stock
13
+ * @return {*}
14
+ */
15
+ export declare function parseStock(stock: string): {
16
+ info: string;
17
+ path: string;
18
+ row: number;
19
+ col: number;
20
+ };
21
+ /**
22
+ * 在字符串中获取url
23
+ *
24
+ * @export
25
+ * @param {string} text
26
+ * @return {*}
27
+ */
28
+ export declare function extractUrl(text: string): string;
29
+ /**
30
+ * 在字符串中获取路径
31
+ *
32
+ * @export
33
+ * @param {string} text
34
+ * @return {*}
35
+ */
36
+ export declare function extractPath(text: string): string;
37
+ /**
38
+ * 获取文件内的行内sourcemap
39
+ *
40
+ * @export
41
+ * @param {string} text
42
+ * @return {*}
43
+ */
44
+ export declare function extractSourceMap(text: string): string;
45
+ /**
46
+ * 解析url中的参数
47
+ *
48
+ * @export
49
+ * @param {string} queryString
50
+ * @return {*}
51
+ */
52
+ export declare function parseQueryString(queryString: string): any;
53
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../plugins/src/plugins/utils/index.ts"],"names":[],"mappings":"AAGA,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EAAE,EACf,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,GAChC,MAAM,CAOR;AAGD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,UAe9C;AAGD,wBAAgB,WAAW,aAiB1B;AAKD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD;AAKD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7D;AAID,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAGD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD;AAID;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM;;;;;EAQvC;AAGD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,UAGtC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,UAGvC;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,UAG5C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,OA4BnD"}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("path"),a=require("os");function r(t){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const e in t)if(e!=="default"){const o=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(n,e,o.get?o:{enumerable:!0,get:()=>t[e]})}}return n.default=t,Object.freeze(n)}const u=r(c),i=r(a);function p(t,n){for(let e=0;e<t.length;e++)if(n(t[e]))return e+1;return-1}function f(t){const n=u.extname(t).toLowerCase();return{".html":"text/html",".js":"text/javascript",".css":"text/css",".json":"application/json",".png":"image/png",".jpg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".woff":"font/woff",".woff2":"font/woff2"}[n]||"text/plain"}function l(){const t=i.networkInterfaces(),n=[];return Object.keys(t).forEach(e=>{var o;t!=null&&t[e]&&Array.isArray(t==null?void 0:t[e])&&((o=t==null?void 0:t[e])==null||o.forEach(s=>{s.family==="IPv4"&&!s.internal&&n.push(s.address)}))}),n.push("localhost"),n}const g=/import\s*\{[^}]*onLaunch[^}]*\}\s*from\s+['"]@dcloudio\/uni-app['"];?/;function m(t){return g.test(t)}const h=/import\s*\{[^}]*getCurrentInstance[^}]*\}\s*from\s+['"]vue['"];?/;function I(t){return h.test(t)}const d=/import\s*\{[^}]*console[^}]*\}\s*from\s+['"]vite-uni-dev-tool['"];?/;function y(t){return d.test(t)}const j=/console\.\w+\(/;function C(t){return j.test(t)}exports.findInsertionIndex=p;exports.getContentType=f;exports.getLocalIPs=l;exports.hasImportConsole=y;exports.hasImportCurrentInstance=I;exports.hasImportOnLaunch=m;exports.hasUseConsole=C;
package/dev/type.ts CHANGED
@@ -5,7 +5,7 @@ export declare namespace DevTool {
5
5
  path: string;
6
6
  sort?: number;
7
7
  name?: string;
8
- isNav?: boolean;
8
+ type?: string;
9
9
  style: {
10
10
  navigationBarTitleText?: string;
11
11
  };
@@ -39,6 +39,7 @@ export declare namespace DevTool {
39
39
  };
40
40
  type PagesJSON = {
41
41
  pages: Page[];
42
+ subPackages?: { root: string; pages: Page[] }[];
42
43
  tabBar: {
43
44
  list: Nav[];
44
45
  };
@@ -61,6 +62,17 @@ export declare namespace DevTool {
61
62
  cacheMaxSize?: number;
62
63
  /** 所有路由信息 */
63
64
  pagesJson?: PagesJSON;
65
+ /** 源文件服务地址 */
66
+ sourceFileServers?: string[];
67
+ /** 用于区分生产环境和开发环境,开发环境下,为了获取 Android 异常栈源码会获取本地源码进行展示 */
68
+ mode: string;
69
+ /** 用于捕获 vue3 抛出的错误和警告 */
70
+ vue3instance?: any;
71
+ /**
72
+ * 该属性处于实验当中,谨慎使用
73
+ * 读取开发环境 source file,source map,默认 禁用
74
+ */
75
+ useDevSource?: boolean;
64
76
  } & ButtonOptions;
65
77
 
66
78
  type ButtonOptions = Partial<{
@@ -0,0 +1,6 @@
1
+ export declare function findInsertionIndex(lines: string[], condition: (p: string) => boolean): number;
2
+ export declare function getContentType(filePath: string): string;
3
+ export declare function getLocalIPs(): string[];
4
+ export declare function hasImportOnLaunch(str: string): boolean;
5
+ export declare function hasImportCurrentInstance(str: string): boolean;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -20,6 +20,15 @@ export { getCurrentPagePath } from './page';
20
20
 
21
21
  export { getCurrentDate, formatDate, sleep } from './date';
22
22
 
23
- export { hightLight } from './string';
23
+ export {
24
+ hightLight,
25
+ escapeHTML,
26
+ extractUrl,
27
+ extractRowAndCol,
28
+ parseStock,
29
+ isMockWX,
30
+ } from './string';
24
31
 
25
32
  export { getWifiIp, getDeviceMac, getLanIp, getMicroAppIp } from './ip';
33
+
34
+ export { isAndroid, isH5, isWX } from './platform';
@@ -0,0 +1,14 @@
1
+ export function isH5(): boolean {
2
+ return process.env.UNI_PLATFORM === 'h5';
3
+ }
4
+
5
+ export function isWX() {
6
+ return process.env.UNI_PLATFORM === 'mp-weixin';
7
+ }
8
+
9
+ export function isAndroid() {
10
+ return (
11
+ process.env.UNI_PLATFORM === 'app' ||
12
+ process.env.UNI_PLATFORM === 'app-plus'
13
+ );
14
+ }
@@ -13,11 +13,109 @@ export function hightLight(str: string = '', search: string = '') {
13
13
  // 转义特殊字符,确保正则表达式安全
14
14
  const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
15
15
  const regex = new RegExp(escapedSearch, 'g');
16
-
16
+
17
17
  const html = str.replace(
18
18
  regex,
19
- `<span style="color:#fff; background-color: var(--dev-tool-main-color);">${search}</span>`
19
+ `<span style="color:#fff; background-color: var(--dev-tool-main-color);">${search}</span>`,
20
20
  );
21
-
21
+
22
22
  return html;
23
- }
23
+ }
24
+
25
+ export function escapeHTML(unsafe: string) {
26
+ if (!unsafe) return '';
27
+
28
+ const escapeMap: Record<string, string> = {
29
+ '&': '&amp;',
30
+ '"': '&quot;',
31
+ "'": '&#39;',
32
+ '>': '&gt;',
33
+ '<': '&lt;',
34
+ '=': '&#61;',
35
+ '+': '&#43;',
36
+ '-': '&#45;',
37
+ '(': '&#40;',
38
+ ')': '&#41;',
39
+ '[': '&#91;',
40
+ ']': '&#93;',
41
+ '{': '&#123;',
42
+ '}': '&#125;',
43
+ '.': '&#46;',
44
+ '?': '&#63;',
45
+ '/': '&#47;',
46
+ ':': '&#58;',
47
+ };
48
+
49
+ return unsafe.replace(
50
+ /[&"'><=+\-().?\/:[\]{}]/g,
51
+ (char) => escapeMap[char] || char,
52
+ );
53
+ }
54
+
55
+ const urlPattern = /https?:\/\/[^\s/$.?#](?:(?!\s|\)).)*/g;
56
+ /**
57
+ * 在字符串中获取url
58
+ *
59
+ * @export
60
+ * @param {string} text
61
+ * @return {*}
62
+ */
63
+ export function extractUrl(text: string) {
64
+ const match = text.match(urlPattern);
65
+ return match ? match[0] : '';
66
+ }
67
+
68
+ const rowAndColPattern = /:(\d+)(?::(\d+))?\)?$/;
69
+ /**
70
+ * 获取url 中末尾的行号和列号
71
+ *
72
+ * @export
73
+ * @param {string} url
74
+ * @return {*}
75
+ */
76
+ export function extractRowAndCol(url: string) {
77
+ const match = url.match(rowAndColPattern);
78
+ if (match) {
79
+ const lineNumber = match[1];
80
+ const columnNumber = match[2];
81
+ return {
82
+ row: parseInt(lineNumber) - 1,
83
+ col: parseInt(columnNumber) - 1,
84
+ };
85
+ }
86
+
87
+ return {
88
+ row: -1,
89
+ col: -1,
90
+ };
91
+ }
92
+
93
+ // at pages/index/index.js:46
94
+ // at pages/index/index.js:46:10
95
+ // at handleClick (http://localhost:8080/pages/main.js:123:4)
96
+ // at http://example.com/app.bundle.js:5:2
97
+ // at init (lib/utils.js:10)
98
+ const stockReg =
99
+ /at\s+(?:([^(]+)\s+\()?((?:[^:\/\s]+(?:\/[^:\/\s]+)*\.[^:\/\s]+)|(?:[^:]+:\/\/[^:\/\s]+(?::\d+)?(?:\/[^:\s]*)*)):(\d+)(?::(\d+))?(?:\s*\)?)?$/;
100
+
101
+ /**
102
+ * 解析栈信息
103
+ *
104
+ * @export
105
+ * @param {string} stock
106
+ * @return {*}
107
+ */
108
+ export function parseStock(stock: string) {
109
+ const match = stock.match(stockReg);
110
+ return {
111
+ info: match?.[1] ?? '',
112
+ path: match?.[2] ?? '',
113
+ row: match?.[3] ? parseInt(match?.[3]) - 1 : -1,
114
+ col: match?.[4] ? parseInt(match?.[4]) - 1 : -1,
115
+ };
116
+ }
117
+
118
+ const mockWXReg = /https?:\/\/usr/;
119
+ export function isMockWX(stock: string) {
120
+ return mockWXReg.test(stock);
121
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-uni-dev-tool",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "vite-uni-dev-tool, debug, uni-app, 一处编写,到处调试",
5
5
  "keywords": [
6
6
  "vite",