From 94736146fae0d6b4e042b5d3360175511ee2c0bf Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 30 Apr 2023 03:26:41 +0200 Subject: [PATCH 1/2] feat: open in vscode --- packages/devtools-kit/src/_types/rpc.ts | 2 +- .../devtools-kit/src/_types/server-ctx.ts | 5 +++ packages/devtools/client/setup/client-rpc.ts | 3 +- packages/devtools/src/integrations/vscode.ts | 42 +++++++++++++++++-- packages/devtools/src/server-rpc/general.ts | 21 ++++++++-- packages/devtools/src/server-rpc/index.ts | 1 + 6 files changed, 65 insertions(+), 9 deletions(-) diff --git a/packages/devtools-kit/src/_types/rpc.ts b/packages/devtools-kit/src/_types/rpc.ts index f807250921..02cb5d17b4 100644 --- a/packages/devtools-kit/src/_types/rpc.ts +++ b/packages/devtools-kit/src/_types/rpc.ts @@ -47,7 +47,7 @@ export interface ServerFunctions { // Actions customTabAction(name: string, action: number): Promise runWizard(name: T, ...args: GetWizardArgs): Promise - openInEditor(filepath: string): void + openInEditor(filepath: string): Promise restartNuxt(hard?: boolean): Promise } diff --git a/packages/devtools-kit/src/_types/server-ctx.ts b/packages/devtools-kit/src/_types/server-ctx.ts index 8b097ad397..cd6cffde06 100644 --- a/packages/devtools-kit/src/_types/server-ctx.ts +++ b/packages/devtools-kit/src/_types/server-ctx.ts @@ -12,6 +12,11 @@ export interface NuxtDevtoolsServerContext { rpc: BirpcGroup + /** + * Hook to open file in editor + */ + openInEditorHooks: ((filepath: string) => boolean | void | Promise)[] + /** * Invalidate client cache for a function and ask for re-fetching */ diff --git a/packages/devtools/client/setup/client-rpc.ts b/packages/devtools/client/setup/client-rpc.ts index 3af7cca34d..bc83b1619d 100644 --- a/packages/devtools/client/setup/client-rpc.ts +++ b/packages/devtools/client/setup/client-rpc.ts @@ -21,7 +21,8 @@ export function setupClientRPC() { nuxt.hooks.callHookParallel('devtools:terminal:exit', data) }, async navigateTo(path: string) { - router.push(path) + if (router.currentRoute.value.path !== path) + router.push(path) }, } satisfies ClientFunctions) } diff --git a/packages/devtools/src/integrations/vscode.ts b/packages/devtools/src/integrations/vscode.ts index f532d2c658..8117b98891 100644 --- a/packages/devtools/src/integrations/vscode.ts +++ b/packages/devtools/src/integrations/vscode.ts @@ -1,4 +1,7 @@ import { hostname } from 'node:os' +import { resolve } from 'node:path' +import fs from 'node:fs/promises' +import { existsSync } from 'node:fs' import { logger } from '@nuxt/kit' import { execa } from 'execa' import { checkPort, getPort } from 'get-port-please' @@ -8,7 +11,7 @@ import { startSubprocess } from '@nuxt/devtools-kit' import { LOG_PREFIX } from '../logger' import type { NuxtDevtoolsServerContext } from '../types' -export async function setup({ nuxt, options }: NuxtDevtoolsServerContext) { +export async function setup({ nuxt, options, openInEditorHooks, rpc }: NuxtDevtoolsServerContext) { const installed = !!await which('code-server').catch(() => null) const vsOptions = options?.vscode || {} @@ -19,20 +22,53 @@ export async function setup({ nuxt, options }: NuxtDevtoolsServerContext) { let promise: Promise | null = null const mode = vsOptions?.mode || 'local-serve' const computerHostName = vsOptions.tunnel?.name || hostname().split('.').join('') + const root = nuxt.options.rootDir + const vscodeServerControllerFile = resolve(root, '.vscode', '.server-controller-port.log') + + openInEditorHooks.push(async (file) => { + if (!existsSync(vscodeServerControllerFile)) + return false + + // With vscode-server-controller, + // we can open files in VS Code Server + try { + const { port } = JSON.parse(await fs.readFile(vscodeServerControllerFile, 'utf-8')) as any + const url = `http://localhost:${port}/open?path=${encodeURIComponent(file)}` + await fetch(url) + rpc.broadcast.navigateTo('/modules/custom-builtin-vscode') + return true + } + catch (e) { + console.error(e) + return false + } + }) async function startCodeServer() { + if (existsSync(vscodeServerControllerFile)) + await fs.rm(vscodeServerControllerFile, { force: true }) + if (vsOptions?.reuseExistingServer && !(await checkPort(port))) { loaded = true - url = `http://localhost:${port}/?folder=${encodeURIComponent(nuxt.options.rootDir)}` + url = `http://localhost:${port}/?folder=${encodeURIComponent(root)}` logger.info(LOG_PREFIX, `Existing VS Code Server found at port ${port}...`) return } port = await getPort({ port }) - url = `http://localhost:${port}/?folder=${encodeURIComponent(nuxt.options.rootDir)}` + url = `http://localhost:${port}/?folder=${encodeURIComponent(root)}` logger.info(LOG_PREFIX, `Starting VS Code Server at ${url} ...`) + // Install VS Code Server Controller + // https://github.com/antfu/vscode-server-controller + execa('code-server', [ + 'serve-local', + '--accept-server-license-terms', + '--install-extension', + 'antfu.vscode-server-controller', + ], { stderr: 'inherit', stdout: 'ignore', reject: false }) + startSubprocess( { command: 'code-server', diff --git a/packages/devtools/src/server-rpc/general.ts b/packages/devtools/src/server-rpc/general.ts index 85d307d68c..b62101abea 100644 --- a/packages/devtools/src/server-rpc/general.ts +++ b/packages/devtools/src/server-rpc/general.ts @@ -8,7 +8,7 @@ import { logger } from '@nuxt/kit' import type { HookInfo, NuxtDevtoolsServerContext, ServerFunctions } from '../types' import { setupHooksDebug } from '../runtime/shared/hooks' -export function setupGeneralRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) { +export function setupGeneralRPC({ nuxt, refresh, openInEditorHooks }: NuxtDevtoolsServerContext) { const components: Component[] = [] const imports: Import[] = [] const importPresets: Import[] = [] @@ -118,12 +118,25 @@ export function setupGeneralRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) { `${input}.mjs`, `${input}.ts`, ].find(i => existsSync(i)) - if (path) { + + if (!path) { + console.error('File not found:', input) + return false + } + + try { + for (const hook of openInEditorHooks) { + const result = await hook(path) + if (result) + return true + } // @ts-expect-error missin types await import('launch-editor').then(r => (r.default || r)(path + suffix)) + return true } - else { - console.error('File not found:', input) + catch (e) { + console.error(e) + return false } }, restartNuxt(hard = true) { diff --git a/packages/devtools/src/server-rpc/index.ts b/packages/devtools/src/server-rpc/index.ts index 59f712c255..fbd94a795d 100644 --- a/packages/devtools/src/server-rpc/index.ts +++ b/packages/devtools/src/server-rpc/index.ts @@ -63,6 +63,7 @@ export function setupRPC(nuxt: Nuxt, options: ModuleOptions) { rpc, refresh, extendServerRpc, + openInEditorHooks: [], } // @ts-expect-error untyped From 7d2fd1bde8527705b5832fbfaf5ced5672b961be Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 30 Apr 2023 03:39:38 +0200 Subject: [PATCH 2/2] chore: update --- packages/devtools/src/runtime/plugins/view/Frame.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devtools/src/runtime/plugins/view/Frame.vue b/packages/devtools/src/runtime/plugins/view/Frame.vue index 64da4254c5..d15fd88edb 100644 --- a/packages/devtools/src/runtime/plugins/view/Frame.vue +++ b/packages/devtools/src/runtime/plugins/view/Frame.vue @@ -108,8 +108,8 @@ function updateClient() { if (componentInspector) { componentInspector.openInEditor = async (baseUrl, file, line, column) => { - await props.client!.hooks.callHook('host:inspector:click', baseUrl, file, line, column) disableComponentInspector() + await props.client!.hooks.callHook('host:inspector:click', baseUrl, file, line, column) } componentInspector.onUpdated = () => { props.client!.hooks.callHook('host:inspector:update', {