diff --git a/docs/guide/custom-vue2-app-scan-selector.md b/docs/guide/custom-vue2-app-scan-selector.md new file mode 100644 index 000000000..86134a197 --- /dev/null +++ b/docs/guide/custom-vue2-app-scan-selector.md @@ -0,0 +1,12 @@ +## Customize vue2 app scan selector +> For example, if you are using micro-app as your micro-frontend framework, the devtools cannot find Vue2 apps in `` by default. + +You can set a custom selector used to scan for Vue2 apps in your project with the following code in your frontend app: + +```js +if (process.env.NODE_ENV !== 'production') { + window.VUE_DEVTOOLS_CONFIG = { + customVue2ScanSelector: 'micro-app' + } +} +``` \ No newline at end of file diff --git a/packages/app-backend-core/src/app.ts b/packages/app-backend-core/src/app.ts index 125844db1..a5b7de850 100644 --- a/packages/app-backend-core/src/app.ts +++ b/packages/app-backend-core/src/app.ts @@ -26,7 +26,7 @@ export async function registerApp (options: AppRecordOptions, ctx: BackendContex async function registerAppJob (options: AppRecordOptions, ctx: BackendContext) { // Dedupe - if (ctx.appRecords.find(a => a.options === options)) { + if (ctx.appRecords.find(a => a.options.app === options.app)) { return } @@ -194,15 +194,25 @@ export async function sendApps (ctx: BackendContext) { }) } +function removeAppRecord (appRecord: AppRecord, ctx: BackendContext) { + try { + appIds.delete(appRecord.id) + const index = ctx.appRecords.indexOf(appRecord) + if (index !== -1) ctx.appRecords.splice(index, 1) + removeLayersForApp(appRecord.options.app, ctx) + ctx.bridge.send(BridgeEvents.TO_FRONT_APP_REMOVE, { id: appRecord.id }) + } catch (e) { + if (SharedData.debugInfo) { + console.error(e) + } + } +} + export async function removeApp (app: App, ctx: BackendContext) { try { const appRecord = await getAppRecord(app, ctx) if (appRecord) { - appIds.delete(appRecord.id) - const index = ctx.appRecords.indexOf(appRecord) - if (index !== -1) ctx.appRecords.splice(index, 1) - removeLayersForApp(app, ctx) - ctx.bridge.send(BridgeEvents.TO_FRONT_APP_REMOVE, { id: appRecord.id }) + removeAppRecord(appRecord, ctx) } } catch (e) { if (SharedData.debugInfo) { @@ -212,9 +222,17 @@ export async function removeApp (app: App, ctx: BackendContext) { } // eslint-disable-next-line camelcase -export async function _legacy_getAndRegisterApps (Vue: any, ctx: BackendContext) { +export async function _legacy_getAndRegisterApps (ctx: BackendContext) { + // Remove apps that are legacy + ctx.appRecords.forEach(appRecord => { + if (appRecord.meta.Vue) { + removeAppRecord(appRecord, ctx) + } + }) + const apps = scan() apps.forEach(app => { + const Vue = app.constructor registerApp({ app, types: {}, diff --git a/packages/app-backend-core/src/index.ts b/packages/app-backend-core/src/index.ts index 66ba75431..58fda5927 100644 --- a/packages/app-backend-core/src/index.ts +++ b/packages/app-backend-core/src/index.ts @@ -61,14 +61,14 @@ export async function initBackend (bridge: Bridge) { if (hook.Vue) { connect() - _legacy_getAndRegisterApps(hook.Vue, ctx) - } else { - hook.once(HookEvents.INIT, (Vue) => { - _legacy_getAndRegisterApps(Vue, ctx) - }) + _legacy_getAndRegisterApps(ctx) } + hook.on(HookEvents.INIT, () => { + _legacy_getAndRegisterApps(ctx) + }) hook.on(HookEvents.APP_ADD, async app => { + await _legacy_getAndRegisterApps(ctx) await registerApp(app, ctx) // Will init connect diff --git a/packages/app-backend-core/src/legacy/scan.ts b/packages/app-backend-core/src/legacy/scan.ts index ed5481165..bdb73a7fc 100644 --- a/packages/app-backend-core/src/legacy/scan.ts +++ b/packages/app-backend-core/src/legacy/scan.ts @@ -1,4 +1,5 @@ import { isBrowser, target } from '@vue-devtools/shared-utils' +import { getPageConfig } from '../page-config' const rootInstances = [] @@ -60,6 +61,17 @@ export function scan () { // Ignore } } + + // Scan for Vue instances in the customTarget elements + const { customVue2ScanSelector } = getPageConfig() + const customTargets = customVue2ScanSelector ? document.querySelectorAll(customVue2ScanSelector) : [] + for (const customTarget of customTargets) { + try { + walkDocument(customTarget) + } catch (e) { + // Ignore + } + } } else { if (Array.isArray(target.__VUE_ROOT_INSTANCES__)) { target.__VUE_ROOT_INSTANCES__.map(processInstance) diff --git a/packages/app-backend-core/src/page-config.ts b/packages/app-backend-core/src/page-config.ts index cdca3acf0..42b627a3e 100644 --- a/packages/app-backend-core/src/page-config.ts +++ b/packages/app-backend-core/src/page-config.ts @@ -3,6 +3,7 @@ import { target, SharedData } from '@vue-devtools/shared-utils' export interface PageConfig { openInEditorHost?: string defaultSelectedAppId?: string + customVue2ScanSelector?: string } let config: PageConfig = {}