Skip to content

Commit 9f17662

Browse files
authored
feat: open in file in embeded vscode (#207)
1 parent 89ffc5e commit 9f17662

File tree

7 files changed

+66
-10
lines changed

7 files changed

+66
-10
lines changed

packages/devtools-kit/src/_types/rpc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export interface ServerFunctions {
4747
// Actions
4848
customTabAction(name: string, action: number): Promise<boolean>
4949
runWizard<T extends WizardActions>(name: T, ...args: GetWizardArgs<T>): Promise<void>
50-
openInEditor(filepath: string): void
50+
openInEditor(filepath: string): Promise<boolean>
5151
restartNuxt(hard?: boolean): Promise<void>
5252
}
5353

packages/devtools-kit/src/_types/server-ctx.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ export interface NuxtDevtoolsServerContext {
1212

1313
rpc: BirpcGroup<ClientFunctions, ServerFunctions>
1414

15+
/**
16+
* Hook to open file in editor
17+
*/
18+
openInEditorHooks: ((filepath: string) => boolean | void | Promise<boolean | void>)[]
19+
1520
/**
1621
* Invalidate client cache for a function and ask for re-fetching
1722
*/

packages/devtools/client/setup/client-rpc.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export function setupClientRPC() {
2121
nuxt.hooks.callHookParallel('devtools:terminal:exit', data)
2222
},
2323
async navigateTo(path: string) {
24-
router.push(path)
24+
if (router.currentRoute.value.path !== path)
25+
router.push(path)
2526
},
2627
} satisfies ClientFunctions)
2728
}

packages/devtools/src/integrations/vscode.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { hostname } from 'node:os'
2+
import { resolve } from 'node:path'
3+
import fs from 'node:fs/promises'
4+
import { existsSync } from 'node:fs'
25
import { logger } from '@nuxt/kit'
36
import { execa } from 'execa'
47
import { checkPort, getPort } from 'get-port-please'
@@ -8,7 +11,7 @@ import { startSubprocess } from '@nuxt/devtools-kit'
811
import { LOG_PREFIX } from '../logger'
912
import type { NuxtDevtoolsServerContext } from '../types'
1013

11-
export async function setup({ nuxt, options }: NuxtDevtoolsServerContext) {
14+
export async function setup({ nuxt, options, openInEditorHooks, rpc }: NuxtDevtoolsServerContext) {
1215
const installed = !!await which('code-server').catch(() => null)
1316

1417
const vsOptions = options?.vscode || {}
@@ -19,20 +22,53 @@ export async function setup({ nuxt, options }: NuxtDevtoolsServerContext) {
1922
let promise: Promise<void> | null = null
2023
const mode = vsOptions?.mode || 'local-serve'
2124
const computerHostName = vsOptions.tunnel?.name || hostname().split('.').join('')
25+
const root = nuxt.options.rootDir
26+
const vscodeServerControllerFile = resolve(root, '.vscode', '.server-controller-port.log')
27+
28+
openInEditorHooks.push(async (file) => {
29+
if (!existsSync(vscodeServerControllerFile))
30+
return false
31+
32+
// With vscode-server-controller,
33+
// we can open files in VS Code Server
34+
try {
35+
const { port } = JSON.parse(await fs.readFile(vscodeServerControllerFile, 'utf-8')) as any
36+
const url = `http://localhost:${port}/open?path=${encodeURIComponent(file)}`
37+
await fetch(url)
38+
rpc.broadcast.navigateTo('/modules/custom-builtin-vscode')
39+
return true
40+
}
41+
catch (e) {
42+
console.error(e)
43+
return false
44+
}
45+
})
2246

2347
async function startCodeServer() {
48+
if (existsSync(vscodeServerControllerFile))
49+
await fs.rm(vscodeServerControllerFile, { force: true })
50+
2451
if (vsOptions?.reuseExistingServer && !(await checkPort(port))) {
2552
loaded = true
26-
url = `http://localhost:${port}/?folder=${encodeURIComponent(nuxt.options.rootDir)}`
53+
url = `http://localhost:${port}/?folder=${encodeURIComponent(root)}`
2754
logger.info(LOG_PREFIX, `Existing VS Code Server found at port ${port}...`)
2855
return
2956
}
3057

3158
port = await getPort({ port })
32-
url = `http://localhost:${port}/?folder=${encodeURIComponent(nuxt.options.rootDir)}`
59+
url = `http://localhost:${port}/?folder=${encodeURIComponent(root)}`
3360

3461
logger.info(LOG_PREFIX, `Starting VS Code Server at ${url} ...`)
3562

63+
// Install VS Code Server Controller
64+
// https://github.com/antfu/vscode-server-controller
65+
execa('code-server', [
66+
'serve-local',
67+
'--accept-server-license-terms',
68+
'--install-extension',
69+
'antfu.vscode-server-controller',
70+
], { stderr: 'inherit', stdout: 'ignore', reject: false })
71+
3672
startSubprocess(
3773
{
3874
command: 'code-server',

packages/devtools/src/runtime/plugins/view/Frame.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ function updateClient() {
108108
109109
if (componentInspector) {
110110
componentInspector.openInEditor = async (baseUrl, file, line, column) => {
111-
await props.client!.hooks.callHook('host:inspector:click', baseUrl, file, line, column)
112111
disableComponentInspector()
112+
await props.client!.hooks.callHook('host:inspector:click', baseUrl, file, line, column)
113113
}
114114
componentInspector.onUpdated = () => {
115115
props.client!.hooks.callHook('host:inspector:update', {

packages/devtools/src/server-rpc/general.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { logger } from '@nuxt/kit'
88
import type { HookInfo, NuxtDevtoolsServerContext, ServerFunctions } from '../types'
99
import { setupHooksDebug } from '../runtime/shared/hooks'
1010

11-
export function setupGeneralRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) {
11+
export function setupGeneralRPC({ nuxt, refresh, openInEditorHooks }: NuxtDevtoolsServerContext) {
1212
const components: Component[] = []
1313
const imports: Import[] = []
1414
const importPresets: Import[] = []
@@ -118,12 +118,25 @@ export function setupGeneralRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) {
118118
`${input}.mjs`,
119119
`${input}.ts`,
120120
].find(i => existsSync(i))
121-
if (path) {
121+
122+
if (!path) {
123+
console.error('File not found:', input)
124+
return false
125+
}
126+
127+
try {
128+
for (const hook of openInEditorHooks) {
129+
const result = await hook(path)
130+
if (result)
131+
return true
132+
}
122133
// @ts-expect-error missin types
123134
await import('launch-editor').then(r => (r.default || r)(path + suffix))
135+
return true
124136
}
125-
else {
126-
console.error('File not found:', input)
137+
catch (e) {
138+
console.error(e)
139+
return false
127140
}
128141
},
129142
restartNuxt(hard = true) {

packages/devtools/src/server-rpc/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export function setupRPC(nuxt: Nuxt, options: ModuleOptions) {
6363
rpc,
6464
refresh,
6565
extendServerRpc,
66+
openInEditorHooks: [],
6667
}
6768

6869
// @ts-expect-error untyped

0 commit comments

Comments
 (0)