Skip to content

Commit 520a90d

Browse files
antfuclaude
andauthored
refactor(cli): migrate dev command to devframe createDevServer (#150)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 21deaea commit 520a90d

5 files changed

Lines changed: 17 additions & 53 deletions

File tree

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ Migrate the Node Modules Inspector to use `devframe` as the underlying framework
1919
### Open Questions
2020
- Which parts of the codebase need to be refactored vs. kept as-is?
2121
- Are there any performance implications of using devframe?
22+
23+
### Implementation Notes
24+
- CLI implementation should leverage devframe patterns from vitejs/devtools PR #304 for consistency and best practices.

packages/node-modules-inspector/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
"p-limit": "catalog:deps",
5252
"pathe": "catalog:deps",
5353
"publint": "catalog:deps",
54-
"sirv": "catalog:deps",
5554
"structured-clone-es": "catalog:deps",
5655
"tinyglobby": "catalog:deps",
5756
"unconfig": "catalog:deps",

packages/node-modules-inspector/src/node/cli.ts

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import process from 'node:process'
44

55
import c from 'ansis'
66
import cac from 'cac'
7+
import { createDevServer, resolveDevServerPort } from 'devframe/adapters/dev'
78
import {
89
DEVTOOLS_CONNECTION_META_FILENAME,
910
DEVTOOLS_RPC_DUMP_DIRNAME,
@@ -13,12 +14,9 @@ import {
1314
collectStaticRpcDump,
1415
createH3DevToolsHost,
1516
createHostContext,
16-
startHttpAndWs,
1717
} from 'devframe/node'
1818
import { strictJsonStringify, structuredCloneStringify } from 'devframe/rpc'
19-
import { createApp, eventHandler, fromNodeMiddleware } from 'h3'
2019
import { dirname, relative, resolve } from 'pathe'
21-
import sirv from 'sirv'
2220
import { glob } from 'tinyglobby'
2321
import { distDir } from '../dirs'
2422
import { MARK_CHECK, MARK_NODE } from './constants'
@@ -117,58 +115,29 @@ cli
117115
.option('--port <port>', 'Port', { default: process.env.PORT || 9999 })
118116
.option('--open', 'Open browser', { default: true })
119117
.action(async (options) => {
120-
const { getPort } = await import('get-port-please')
121-
const open = (await import('open')).default
122118
const host = options.host
123-
const port = await getPort({ port: Number(options.port), portRange: [9999, 15000], host })
124-
125-
console.log(c.green`${MARK_NODE} Starting Node Modules Inspector at`, c.green(`http://${host === '127.0.0.1' ? 'localhost' : host}:${port}`), '\n')
119+
const port = await resolveDevServerPort(devtool, {
120+
host,
121+
defaultPort: Number(options.port),
122+
})
123+
const url = `http://${host === '127.0.0.1' ? 'localhost' : host}:${port}`
126124

127-
const origin = `http://${host}:${port}`
128-
const app = createApp()
125+
console.log(c.green`${MARK_NODE} Starting Node Modules Inspector at`, c.green(url), '\n')
129126

130-
const ctx = await createHostContext({
131-
cwd: options.root,
132-
mode: 'dev',
133-
host: createH3DevToolsHost({ origin }),
134-
})
135-
await devtool.setup(ctx, {
127+
const server = await createDevServer(devtool, {
128+
host,
129+
port,
136130
flags: {
137131
root: options.root,
138132
config: options.config,
139133
depth: Number(options.depth),
140134
},
135+
openBrowser: options.open ? url : false,
141136
})
142137

143-
const jsonSerializableMethods: string[] = []
144-
for (const def of ctx.rpc.definitions.values()) {
145-
if (def.jsonSerializable === true)
146-
jsonSerializableMethods.push(def.name)
147-
}
148-
149-
app.use(`/${DEVTOOLS_CONNECTION_META_FILENAME}`, eventHandler((event) => {
150-
event.node.res.setHeader('Content-Type', 'application/json')
151-
return event.node.res.end(JSON.stringify({ backend: 'websocket', websocket: port, jsonSerializableMethods }))
152-
}))
153-
154-
app.use('/', fromNodeMiddleware(sirv(distDir, { dev: true, single: true })))
155-
156-
setTimeout(() => {
157-
const invoke = ctx.rpc.invokeLocal as (method: string, ...args: any[]) => Promise<any>
158-
invoke('nmi:get-payload').catch(() => {})
159-
}, 1)
160-
161-
await startHttpAndWs({
162-
context: ctx,
163-
host,
164-
port,
165-
app,
166-
auth: false,
167-
onReady: async () => {
168-
if (options.open)
169-
await open(`http://${host === '127.0.0.1' ? 'localhost' : host}:${port}`)
170-
},
171-
})
138+
// Warm the payload; rpcGroup.functions is a Proxy returning Promise<handler>.
139+
const handlers = server.rpcGroup.functions as Record<string, Promise<(...args: unknown[]) => unknown> | undefined>
140+
handlers['nmi:get-payload']?.then(fn => fn?.()).catch(() => {})
172141
})
173142

174143
cli.help()

pnpm-lock.yaml

Lines changed: 0 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ catalogs:
4141
pathe: ^2.0.3
4242
publint: ^0.3.19
4343
semver: ^7.7.4
44-
sirv: ^3.0.2
4544
stream-json: ^2.1.0
4645
structured-clone-es: ^2.0.0
4746
tinyexec: ^1.1.2

0 commit comments

Comments
 (0)