Skip to content

Commit 6f5ce18

Browse files
committed
feat: provide better error message for magicast, close #395
1 parent 14935ee commit 6f5ce18

5 files changed

Lines changed: 64 additions & 27 deletions

File tree

packages/devtools/client/pages/modules/timeline.vue

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,19 @@ const Dialog = createTemplatePromise<boolean, [string, string]>()
1313
const openInEditor = useOpenInEditor()
1414
1515
async function showPopup() {
16-
const [source, modified] = await rpc.enableTimeline(true)
17-
if (!await Dialog.start(source, modified))
18-
return
19-
await rpc.enableTimeline(false)
16+
try {
17+
const [source, modified] = await rpc.enableTimeline(true)
18+
if (!await Dialog.start(source, modified))
19+
return
20+
await rpc.enableTimeline(false)
21+
}
22+
catch {
23+
showNotification({
24+
message: 'Failed to enable timeline automatically. Check the terminal for more details.',
25+
icon: 'i-carbon-warning',
26+
classes: 'text-red',
27+
})
28+
}
2029
}
2130
</script>
2231

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import type { ChannelOptions } from 'birpc'
44

55
import { parse, stringify } from 'flatted'
66
import type { Nuxt } from 'nuxt/schema'
7+
import { colors } from 'consola/utils'
78
import type { Plugin } from 'vite'
9+
import { logger } from '@nuxt/kit'
810
import type { ClientFunctions, ModuleOptions, NuxtDevtoolsServerContext, ServerFunctions } from '../types'
911
import { WS_EVENT_NAME } from '../constant'
1012
import { getDevAuthToken } from '../dev-auth'
@@ -39,7 +41,10 @@ export function setupRPC(nuxt: Nuxt, options: ModuleOptions) {
3941
return extendedRpcMap.get(namespace)?.[fnName]
4042
},
4143
onError(error, name) {
42-
console.error(`[nuxt-devtools] RPC error on executing "${name}":`, error)
44+
logger.error(
45+
colors.yellow(`[nuxt-devtools] RPC error on executing "${colors.bold(name)}":\n`)
46+
+ colors.red(error?.message || ''),
47+
)
4348
},
4449
timeout: 120_000,
4550
},

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { parseModule } from 'magicast'
77
import { addNuxtModule, getDefaultExportOptions } from 'magicast/helpers'
88
import { checkForUpdateOf } from '../npm'
99
import type { NpmCommandOptions, NpmCommandType, NuxtDevtoolsServerContext, PackageUpdateInfo, ServerFunctions } from '../types'
10+
import { magicastGuard } from '../utils/magicast'
1011

1112
export function setupNpmRPC({ nuxt, ensureDevAuthToken }: NuxtDevtoolsServerContext) {
1213
let detectPromise: Promise<PackageManager | undefined> | undefined
@@ -97,11 +98,13 @@ export function setupNpmRPC({ nuxt, ensureDevAuthToken }: NuxtDevtoolsServerCont
9798
let source = latestGenerated
9899
if (source == null)
99100
source = await fs.readFile(filepath, 'utf-8')
100-
const mod = parseModule(source, { sourceFileName: filepath })
101101

102-
addNuxtModule(mod, name)
102+
const generated = await magicastGuard(async () => {
103+
const mod = parseModule(source!, { sourceFileName: filepath })
104+
addNuxtModule(mod, name)
103105

104-
const generated = mod.generate().code
106+
return mod.generate().code
107+
})
105108
const processId = `nuxt:add-module:${name}`
106109

107110
if (!dry) {
@@ -153,20 +156,22 @@ export function setupNpmRPC({ nuxt, ensureDevAuthToken }: NuxtDevtoolsServerCont
153156

154157
const filepath = nuxt.options._nuxtConfigFile
155158
const source = await fs.readFile(filepath, 'utf-8')
156-
const mod = parseModule(source, { sourceFileName: filepath })
157-
158-
// TODO: remove module from config
159-
// removeNuxtModule(mod, name)
160-
const config = getDefaultExportOptions(mod)
161-
config.modules ||= []
162-
if (config.modules.includes(name)) {
163-
Object.values(config.modules).forEach((value, index) => {
164-
if (value === name)
165-
config.modules.splice(index - 1, 1)
166-
})
167-
}
159+
const generated = await magicastGuard(async () => {
160+
const mod = parseModule(source, { sourceFileName: filepath })
161+
162+
// TODO: remove module from config
163+
// removeNuxtModule(mod, name)
164+
const config = getDefaultExportOptions(mod)
165+
config.modules ||= []
166+
if (config.modules.includes(name)) {
167+
Object.values(config.modules).forEach((value, index) => {
168+
if (value === name)
169+
config.modules.splice(index - 1, 1)
170+
})
171+
}
168172

169-
const generated = mod.generate().code
173+
return mod.generate().code
174+
})
170175

171176
const processId = `nuxt:remove-module:${name}`
172177

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@ import fs from 'node:fs/promises'
22
import { parseModule } from 'magicast'
33
import { getDefaultExportOptions } from 'magicast/helpers'
44
import type { NuxtDevtoolsServerContext, ServerFunctions } from '../types'
5+
import { magicastGuard } from '../utils/magicast'
56

67
export function setupTimelineRPC({ nuxt }: NuxtDevtoolsServerContext) {
78
return {
89
async enableTimeline(dry: boolean) {
910
const filepath = nuxt.options._nuxtConfigFile
1011
const source = await fs.readFile(filepath, 'utf-8')
11-
const mod = await parseModule(source, { sourceFileName: filepath })
12+
const generated = await magicastGuard(async () => {
13+
const mod = parseModule(source, { sourceFileName: filepath })
1214

13-
const options = getDefaultExportOptions(mod)
15+
const options = getDefaultExportOptions(mod)
1416

15-
options.devtools = options.devtools || {}
16-
options.devtools.timeline = options.devtools.timeline || {}
17-
options.devtools.timeline.enabled = true
17+
options.devtools = options.devtools || {}
18+
options.devtools.timeline = options.devtools.timeline || {}
19+
options.devtools.timeline.enabled = true
1820

19-
const generated = mod.generate().code
21+
return mod.generate().code
22+
}, '\nYou can enable timeline manually by adding `devtools: { timeline: { enabled: true } }`')
2023

2124
if (!dry) {
2225
await fs.writeFile(filepath, generated, 'utf-8')
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { logger } from '@nuxt/kit'
2+
3+
export async function magicastGuard(fn: (() => Promise<string>), message = '') {
4+
let generated: string | undefined
5+
6+
try {
7+
generated = await fn()
8+
}
9+
catch (e) {
10+
logger.error(e)
11+
throw new Error(`Magicast failed to modify Nuxt config automatically. Maybe the config are composed too dynamically that we failed to statically analyze it. ${message}`)
12+
}
13+
14+
return generated
15+
}

0 commit comments

Comments
 (0)