@dimina-kit/devtools 0.4.0-dev.20260616102751 → 0.4.0-dev.20260624040247
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 +30 -25
- package/dist/main/app/app.js +14 -2
- package/dist/main/index.bundle.js +559 -111
- package/dist/main/ipc/bridge-router.js +57 -9
- package/dist/main/ipc/projects.js +1 -1
- package/dist/main/ipc/simulator.js +1 -1
- package/dist/main/runtime/devtools-backend.d.ts +1 -1
- package/dist/main/runtime/devtools-backend.js +1 -1
- package/dist/main/runtime/miniapp-runtime.d.ts +5 -5
- package/dist/main/services/console-forward/index.js +8 -1
- package/dist/main/services/elements-forward/index.js +36 -12
- package/dist/main/services/layout/index.d.ts +12 -0
- package/dist/main/services/layout/index.js +14 -2
- package/dist/main/services/network-forward/index.d.ts +5 -6
- package/dist/main/services/network-forward/index.js +9 -10
- package/dist/main/services/notifications/renderer-notifier.d.ts +3 -4
- package/dist/main/services/projects/index.js +1 -1
- package/dist/main/services/projects/types.d.ts +1 -1
- package/dist/main/services/projects/types.js +1 -1
- package/dist/main/services/service-console/console-api.d.ts +77 -0
- package/dist/main/services/service-console/console-api.js +103 -0
- package/dist/main/services/service-console/index.d.ts +47 -0
- package/dist/main/services/service-console/index.js +139 -0
- package/dist/main/services/service-host-pool/pool.d.ts +2 -3
- package/dist/main/services/simulator-storage/index.d.ts +2 -4
- package/dist/main/services/simulator-storage/index.js +2 -4
- package/dist/main/services/simulator-temp-files/index.js +2 -2
- package/dist/main/services/update/update-manager.d.ts +1 -1
- package/dist/main/services/update/update-manager.js +1 -1
- package/dist/main/services/views/host-toolbar-session-runtime.d.ts +4 -4
- package/dist/main/services/views/host-toolbar-session-runtime.js +4 -4
- package/dist/main/services/views/view-manager.d.ts +24 -1
- package/dist/main/services/views/view-manager.js +120 -41
- package/dist/main/services/workbench-context.d.ts +7 -6
- package/dist/main/services/workspace/workspace-service.js +11 -0
- package/dist/main/windows/service-host-window/create.d.ts +1 -0
- package/dist/main/windows/service-host-window/create.js +1 -0
- package/dist/preload/runtime/host-toolbar-port.d.ts +1 -1
- package/dist/preload/runtime/host-toolbar-port.js +1 -1
- package/dist/preload/runtime/host-toolbar-runtime.d.ts +8 -7
- package/dist/preload/runtime/host-toolbar-runtime.js +8 -7
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs +1 -1
- package/dist/preload/windows/simulator.cjs.map +1 -1
- package/dist/preload/windows/simulator.js +1 -1
- package/dist/renderer/assets/index-PtsdWlGu.js +50 -0
- package/dist/renderer/assets/{input-B8NDCYv3.js → input-DiCxYlqY.js} +2 -2
- package/dist/renderer/assets/{ipc-transport-DhrajiC5.js → ipc-transport-DSBmaWpJ.js} +1 -1
- package/dist/renderer/assets/ipc-transport-DZxf2YoM.css +1 -0
- package/dist/renderer/assets/{popover-DbZOg03s.js → popover-CyL_uffj.js} +2 -2
- package/dist/renderer/assets/{select-pW3Ysc9T.js → select-BSwvDMtA.js} +2 -2
- package/dist/renderer/assets/settings-Ch8XbFxf.js +2 -0
- package/dist/renderer/assets/{settings-api-BSKzKiWd.js → settings-api-e9ILe2JO.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-BGxjl25x.js → workbenchSettings-DZsHf1g_.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +11 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/service-host/preload.cjs +13 -15
- package/dist/service-host/sourcemap-rewrite.cjs +21 -12
- package/dist/shared/appdata-accumulator.d.ts +2 -2
- package/dist/shared/appdata-accumulator.js +3 -3
- package/dist/shared/constants.d.ts +1 -1
- package/dist/shared/constants.js +1 -1
- package/dist/shared/ipc-channels.d.ts +3 -3
- package/dist/shared/ipc-channels.js +3 -3
- package/dist/shared/open-in-editor.d.ts +20 -1
- package/dist/shared/open-in-editor.js +246 -3
- package/dist/shared/vpath.d.ts +2 -2
- package/dist/shared/vpath.js +2 -2
- package/dist/simulator/assets/{device-shell-BWX7Yopg.js → device-shell-TtcSXwhb.js} +2 -2
- package/dist/simulator/assets/{simulator-sf-D0mhw.js → simulator-CtyXt_4V.js} +3 -3
- package/dist/simulator/simulator.html +1 -1
- package/package.json +8 -6
- package/dist/renderer/assets/index-Z4Rh52G8.js +0 -50
- package/dist/renderer/assets/ipc-transport-9agi76dX.css +0 -1
- package/dist/renderer/assets/settings-CZJOHt8b.js +0 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
基于 Electron 的小程序开发者工具。提供模拟器、Chrome DevTools 面板、WXML/AppData/Storage/编译 面板、编译配置等功能。
|
|
4
4
|
|
|
5
|
-
下游 host 通过 `launch(config)` 集成并定制 devtools(零配置直接 `launch()`,配置驱动 `launch({...})`;见下方「两种用法」)。两种用法都经领域中立的 [`@dimina-kit/electron-deck`](../electron-deck) 框架编排——框架接管 Electron 进程生命周期(whenReady / will-quit)、wire/trust 原语,devtools 作为 `RuntimeBackend` 注入完整运行时(见 [`
|
|
5
|
+
下游 host 通过 `launch(config)` 集成并定制 devtools(零配置直接 `launch()`,配置驱动 `launch({...})`;见下方「两种用法」)。两种用法都经领域中立的 [`@dimina-kit/electron-deck`](../electron-deck) 框架编排——框架接管 Electron 进程生命周期(whenReady / will-quit)、wire/trust 原语,devtools 作为 `RuntimeBackend` 注入完整运行时(见 [`electron-deck 架构`](../electron-deck/docs/architecture.md))。
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -195,7 +195,8 @@ src/
|
|
|
195
195
|
| `menuBuilder` | `(mainWindow, menuContext: MenuContext) => void` | 内置菜单 | 自定义菜单构建器;`menuContext` 为手写窄契约 `MenuContext`(`appName` + workspace 窄集 + `openSettings` + `notify.{projectStatus, windowNavigateBack}`),不含内部管线 |
|
|
196
196
|
| `onSetup` | `(instance) => void` | — | 窗口和 context 创建后的回调,用于注册 Contribution(见下文)|
|
|
197
197
|
| `onBeforeClose` | `(instance) => void` | — | 窗口关闭前的回调,session 关闭由框架自动处理 |
|
|
198
|
-
| `
|
|
198
|
+
| `onBeforeOpenProject` | `(projectPath: string) => void \| Promise<void>` | — | 打开项目前、任何副作用(旧会话拆除 / 编译 / dev-server)之前运行的声明式权限门控。抛错即否决:`openProject` 返回 `{ success: false, error }`,当前活动会话保持不动、适配器不被调用,且框架自动把 error 透到状态条(`notify.projectStatus`)。覆盖 IPC / 菜单 / 内部直调三个打开入口 |
|
|
199
|
+
| `window` | `WorkbenchWindowConfig`(`width`/`height`/`autoShow?`) | — | 主窗口尺寸覆盖;`autoShow`(默认 `true`)控制 `ready-to-show` 是否自动显示窗口。`autoShow: false` 时窗口创建即隐藏(test / 非 test 一致),由 host 在登录通过后自行 `instance.mainWindow.show()` |
|
|
199
200
|
| `updateChecker` | `UpdateChecker` | — | 自定义更新检查器;提供后启用"检查更新"功能 |
|
|
200
201
|
| `updateOptions` | `{ checkInterval?, initialDelay?, getCurrentVersion? }` | — | 仅当 `updateChecker` 提供时生效,默认 1h / 5s |
|
|
201
202
|
|
|
@@ -221,11 +222,11 @@ src/
|
|
|
221
222
|
|
|
222
223
|
## Embedding & Extending the Project Panel
|
|
223
224
|
|
|
224
|
-
|
|
225
|
+
下游宿主通过 `launch({...})` 嵌入 devtools 时,可对项目面板做三个正交扩展:
|
|
225
226
|
|
|
226
227
|
| 扩展点 | 用途 |
|
|
227
228
|
| --- | --- |
|
|
228
|
-
| `projectsProvider` | 接管项目列表存储 —— 替换默认 `<userData>/dimina-projects.json
|
|
229
|
+
| `projectsProvider` | 接管项目列表存储 —— 替换默认 `<userData>/dimina-projects.json`,对接下游宿主后台 / IDE workspace / 远端工程库 |
|
|
229
230
|
| `projectTemplates` + `builtinTemplates` | 注入/覆盖/裁剪"新建项目"模板列表(同 id 覆盖内置;`builtinTemplates` 控制内置策略) |
|
|
230
231
|
| `customCreateProjectDialog` | 用宿主自家页面替换内置"新建项目"对话框(main 进程 hook,可 `new BrowserWindow` 加载任意 URL,通过 IPC/postMessage 回传结果) |
|
|
231
232
|
|
|
@@ -233,8 +234,8 @@ src/
|
|
|
233
234
|
|
|
234
235
|
| 场景 | 需要的扩展点 |
|
|
235
236
|
| --- | --- |
|
|
236
|
-
|
|
|
237
|
-
| 仅替换可选模板(e.g. 只提供 taro /
|
|
237
|
+
| 项目列表来自下游宿主后台 / 团队工程库 | `projectsProvider` |
|
|
238
|
+
| 仅替换可选模板(e.g. 只提供 taro / 宿主自家脚手架) | `projectTemplates` + `builtinTemplates` |
|
|
238
239
|
| 创建项目流程要走宿主自己的 wizard / 登录态 | `customCreateProjectDialog` |
|
|
239
240
|
|
|
240
241
|
### 最小示例
|
|
@@ -246,51 +247,51 @@ import { BrowserWindow } from 'electron'
|
|
|
246
247
|
|
|
247
248
|
const provider: ProjectsProvider = {
|
|
248
249
|
async listProjects() {
|
|
249
|
-
return await
|
|
250
|
+
return await host.api.listProjects()
|
|
250
251
|
},
|
|
251
252
|
async validateProjectDir(dirPath) {
|
|
252
|
-
return (await
|
|
253
|
+
return (await host.api.isMiniApp(dirPath)) ? null : '不是合法的小程序工程'
|
|
253
254
|
},
|
|
254
255
|
async addProject(dirPath) {
|
|
255
|
-
return await
|
|
256
|
+
return await host.api.addProject(dirPath)
|
|
256
257
|
},
|
|
257
258
|
async removeProject(dirPath) {
|
|
258
|
-
await
|
|
259
|
+
await host.api.removeProject(dirPath)
|
|
259
260
|
},
|
|
260
261
|
async updateLastOpened(dirPath) {
|
|
261
|
-
await
|
|
262
|
+
await host.api.touchLastOpened(dirPath)
|
|
262
263
|
},
|
|
263
264
|
async getCompileConfig(dirPath) {
|
|
264
|
-
return await
|
|
265
|
+
return await host.api.getCompileConfig(dirPath)
|
|
265
266
|
},
|
|
266
267
|
async saveCompileConfig(dirPath, cfg) {
|
|
267
|
-
await
|
|
268
|
+
await host.api.saveCompileConfig(dirPath, cfg)
|
|
268
269
|
},
|
|
269
270
|
// 缩略图走云端存储——dataUrl 形如 'data:image/png;base64,...'
|
|
270
271
|
async saveThumbnail(dirPath, imageDataUrl) {
|
|
271
|
-
await
|
|
272
|
+
await host.api.uploadThumbnail(dirPath, imageDataUrl)
|
|
272
273
|
},
|
|
273
274
|
async getThumbnail(dirPath) {
|
|
274
|
-
return await
|
|
275
|
+
return await host.api.fetchThumbnail(dirPath)
|
|
275
276
|
},
|
|
276
277
|
}
|
|
277
278
|
|
|
278
|
-
const
|
|
279
|
+
const hostBlank: ProjectTemplate = {
|
|
279
280
|
id: 'blank', // 同 id 覆盖内置 blank
|
|
280
|
-
name: '
|
|
281
|
-
description: '
|
|
281
|
+
name: '宿主空白工程',
|
|
282
|
+
description: '由下游宿主维护的官方空白模板',
|
|
282
283
|
source: { type: 'directory', path: '/abs/path/to/template' },
|
|
283
284
|
}
|
|
284
285
|
|
|
285
286
|
launch({
|
|
286
287
|
projectsProvider: provider,
|
|
287
|
-
projectTemplates: [
|
|
288
|
+
projectTemplates: [hostBlank],
|
|
288
289
|
builtinTemplates: ['taro-todo'], // 只保留 taro-todo,干掉默认 blank
|
|
289
290
|
customCreateProjectDialog: async ({ parentWindow }) => {
|
|
290
291
|
const win = new BrowserWindow({ parent: parentWindow, modal: true, width: 720, height: 520 })
|
|
291
|
-
await win.loadURL('https://
|
|
292
|
+
await win.loadURL('https://host.example.com/devtools/new-project')
|
|
292
293
|
return await new Promise((resolve) => {
|
|
293
|
-
win.webContents.ipc.once('
|
|
294
|
+
win.webContents.ipc.once('host:create-project:done', (_e, payload) => {
|
|
294
295
|
win.close()
|
|
295
296
|
// payload 三选一(CustomCreateProjectDialogResult):
|
|
296
297
|
// null → 用户取消
|
|
@@ -323,7 +324,7 @@ devtools 自带两个 `source`-style 模板,位于 `packages/devtools/template
|
|
|
323
324
|
- `blank` — 最小空白小程序骨架(pages/index + app.js/json/wxss + project.config.json,约 8 个文件)
|
|
324
325
|
- `taro-todo` — 复制自 `dimina/fe/example/taro-todo`,作为 Taro 编译产物的端到端演示工程
|
|
325
326
|
|
|
326
|
-
`builtinTemplates: 'none'` 排除全部内置;`builtinTemplates: ['taro-todo']` 仅保留指定 id;`projectTemplates` 同 id 注入会覆盖(例如上文 `
|
|
327
|
+
`builtinTemplates: 'none'` 排除全部内置;`builtinTemplates: ['taro-todo']` 仅保留指定 id;`projectTemplates` 同 id 注入会覆盖(例如上文 `hostBlank` 覆盖了内置 `blank`)。
|
|
327
328
|
|
|
328
329
|
### Provider 部分实现 / fallback 行为
|
|
329
330
|
|
|
@@ -547,7 +548,7 @@ instance.context.views.hostToolbar.send('host:cmd', { theme: 'dark' }) // false
|
|
|
547
548
|
|
|
548
549
|
## MiniappRuntime(宿主集成推荐契约)
|
|
549
550
|
|
|
550
|
-
|
|
551
|
+
下游宿主集成时,推荐依赖手写的稳定契约 `MiniappRuntime`,而不是整个 `WorkbenchContext`——后者携带全部内部 service 类型,内部重构会直接破坏下游编译。`asMiniappRuntime(ctx)` 恒等返回(typed view,非拷贝),宿主对 `runtime.workspace.openProject` 的 monkey-patch 会落在真实对象上:
|
|
551
552
|
|
|
552
553
|
```typescript
|
|
553
554
|
import { asMiniappRuntime, type MiniappRuntime } from '@dimina-kit/devtools'
|
|
@@ -669,9 +670,13 @@ pnpm build:preload # 仅构建 preload TypeScript
|
|
|
669
670
|
pnpm build:renderer # Vite 构建渲染层
|
|
670
671
|
pnpm dev # Watch 模式 + Electron
|
|
671
672
|
pnpm check-types # 类型检查
|
|
672
|
-
pnpm test #
|
|
673
|
+
pnpm test # 运行单元测试(vitest)
|
|
674
|
+
pnpm test:coverage # 单元测试 + 覆盖率报告(终端表格 + coverage/index.html)
|
|
675
|
+
pnpm test:e2e # 运行 Playwright e2e 测试
|
|
673
676
|
```
|
|
674
677
|
|
|
678
|
+
> 覆盖率:`pnpm test:coverage`(单包)或仓库根 `pnpm test:coverage`(全部包),报告输出到各包 `coverage/`,浏览器打开 `coverage/index.html` 看逐行高亮。
|
|
679
|
+
|
|
675
680
|
---
|
|
676
681
|
|
|
677
682
|
## 安全说明
|
|
@@ -679,7 +684,7 @@ pnpm test # 运行测试
|
|
|
679
684
|
本工具仅用于本地开发调试。当前的安全配置:
|
|
680
685
|
|
|
681
686
|
- **Workbench 窗口**(main / settings / popover overlay)均启用 `contextIsolation` 并禁用 `nodeIntegration`;renderer 通过 main preload 经 `contextBridge` 拿到 `window.devtools.ipc`,每个 IPC handler 经 sender whitelist 校验调用方
|
|
682
|
-
- **Simulator 本体** 是主进程顶层 `WebContentsView`(`nativeSimulatorView
|
|
687
|
+
- **Simulator 本体** 是主进程顶层 `WebContentsView`(`nativeSimulatorView`,per-project `persist:miniapp-<key>` partition、无 appId 时回落共享 `persist:simulator`、`nodeIntegration=false`),其 preload 由 `webPreferences.preload = cjsSiblingPreloadPath(ctx.preloadPath)` 在创建时(`attachNativeSimulator`)固定。**小程序的每页代码** 运行在该 WCV 内部 DeviceShell 托管的 render-host `<webview>` guest 里(`nodeIntegration=false`),承载逐页沙箱;guest 不带静态 `partition` 属性,由主进程 `will-attach-webview` 钉到同一 per-project partition,并钉死 contextIsolation/sandbox,渲染进程无法替换
|
|
683
688
|
- **renderer 入口** 启用了保守 CSP;`will-navigate` / `setWindowOpenHandler` 屏蔽外部跳转
|
|
684
689
|
|
|
685
690
|
仍然不要在 devtools 窗口中加载不受信任的远程内容;本工具不打算在非本地环境部署。
|
package/dist/main/app/app.js
CHANGED
|
@@ -240,6 +240,20 @@ function wireAppWindowEvents(config, instance) {
|
|
|
240
240
|
// project is open.
|
|
241
241
|
if (isAppQuitting())
|
|
242
242
|
return;
|
|
243
|
+
// A close arriving while a project teardown is already in flight (the
|
|
244
|
+
// user rapid-double-clicked the close button) MUST keep the window open.
|
|
245
|
+
// This guard runs BEFORE hasActiveSession() on purpose: `closeProject()`
|
|
246
|
+
// → `disposeSession()` synchronously nulls the active session before it
|
|
247
|
+
// finishes awaiting `session.close()`, so by the time the second close
|
|
248
|
+
// arrives `hasActiveSession()` is already false. With the old guard order
|
|
249
|
+
// that second close fell straight through the hasActiveSession() check
|
|
250
|
+
// WITHOUT `preventDefault()`, so Electron destroyed the last window →
|
|
251
|
+
// `window-all-closed` → `app.quit()`, quitting the whole app on a
|
|
252
|
+
// double-click. Swallow the re-entrant close and keep the window.
|
|
253
|
+
if (closing) {
|
|
254
|
+
e.preventDefault();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
243
257
|
if (!context.workspace.hasActiveSession())
|
|
244
258
|
return;
|
|
245
259
|
// Close button while a project session is open: stay in the workbench
|
|
@@ -249,8 +263,6 @@ function wireAppWindowEvents(config, instance) {
|
|
|
249
263
|
// unable to invoke anything, so subsequent clicks on Import/etc. would
|
|
250
264
|
// raise `No handler registered for ...`.
|
|
251
265
|
e.preventDefault();
|
|
252
|
-
if (closing)
|
|
253
|
-
return;
|
|
254
266
|
closing = true;
|
|
255
267
|
try {
|
|
256
268
|
if (config.onBeforeClose) {
|