Skip to content

Commit f76679d

Browse files
BobbieGoederohrig
andauthored
feat(module): add multiple modules at once (#584)
Co-authored-by: rohrig <45824492+rohrig@users.noreply.github.com>
1 parent 04101c1 commit f76679d

File tree

1 file changed

+73
-70
lines changed

1 file changed

+73
-70
lines changed

src/commands/module/add.ts

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ export type RegistryMeta = {
2626
authToken: string | null
2727
}
2828

29+
type ResolvedModule = {
30+
nuxtModule?: NuxtModule
31+
pkg: string
32+
pkgName: string
33+
pkgVersion: string
34+
}
35+
type UnresolvedModule = false
36+
type ModuleResolution = ResolvedModule | UnresolvedModule
37+
2938
export default defineCommand({
3039
meta: {
3140
name: 'add',
@@ -36,7 +45,7 @@ export default defineCommand({
3645
...logLevelArgs,
3746
moduleName: {
3847
type: 'positional',
39-
description: 'Module name',
48+
description: 'Specify one or more modules to install by name, separated by spaces',
4049
},
4150
skipInstall: {
4251
type: 'boolean',
@@ -49,6 +58,7 @@ export default defineCommand({
4958
},
5059
async setup(ctx) {
5160
const cwd = resolve(ctx.args.cwd)
61+
const modules = ctx.args._
5262
const projectPkg = await getProjectPackage(cwd)
5363

5464
if (!projectPkg.dependencies?.nuxt && !projectPkg.devDependencies?.nuxt) {
@@ -65,64 +75,12 @@ export default defineCommand({
6575
}
6676
}
6777

68-
const r = await resolveModule(ctx.args.moduleName, cwd)
69-
if (r === false) {
70-
return
71-
}
78+
const maybeResolvedModules = await Promise.all(modules.map(moduleName => resolveModule(moduleName, cwd)))
79+
const r = maybeResolvedModules.filter((x: ModuleResolution): x is ResolvedModule => x != null)
7280

73-
// Add npm dependency
74-
if (!ctx.args.skipInstall) {
75-
const isDev = Boolean(projectPkg.devDependencies?.nuxt)
76-
consola.info(
77-
`Installing \`${r.pkg}\`${isDev ? ' development' : ''} dependency`,
78-
)
79-
const res = await addDependency(r.pkg, { cwd, dev: isDev, installPeerDependencies: true }).catch(
80-
(error) => {
81-
consola.error(error)
82-
return consola.prompt(
83-
`Install failed for ${colors.cyan(
84-
r.pkg,
85-
)}. Do you want to continue adding the module to ${colors.cyan(
86-
'nuxt.config',
87-
)}?`,
88-
{
89-
type: 'confirm',
90-
initial: false,
91-
},
92-
)
93-
},
94-
)
95-
if (res === false) {
96-
return
97-
}
98-
}
81+
consola.info(`Resolved ${r.map(x => x.pkgName).join(', ')}, adding module(s)...`)
9982

100-
// Update nuxt.config.ts
101-
if (!ctx.args.skipConfig) {
102-
await updateConfig({
103-
cwd,
104-
configFile: 'nuxt.config',
105-
async onCreate() {
106-
consola.info(`Creating \`nuxt.config.ts\``)
107-
return getDefaultNuxtConfig()
108-
},
109-
async onUpdate(config) {
110-
if (!config.modules) {
111-
config.modules = []
112-
}
113-
if (config.modules.includes(r.pkgName)) {
114-
consola.info(`\`${r.pkgName}\` is already in the \`modules\``)
115-
return
116-
}
117-
consola.info(`Adding \`${r.pkgName}\` to the \`modules\``)
118-
config.modules.push(r.pkgName)
119-
},
120-
}).catch((error) => {
121-
consola.error(`Failed to update \`nuxt.config\`: ${error.message}`)
122-
consola.error(`Please manually add \`${r.pkgName}\` to the \`modules\` in \`nuxt.config.ts\``)
123-
return null
124-
})
125-
}
83+
await addModule(r, ctx.args, projectPkg)
12684

12785
// update the types for new module
12886
const args = Object.entries(ctx.args).filter(([k]) => k in cwdArgs || k in logLevelArgs).map(([k, v]) => `--${k}=${v}`)
@@ -131,6 +89,62 @@ export default defineCommand({
13189
})
13290

13391
// -- Internal Utils --
92+
async function addModule(r: ResolvedModule[], { skipInstall, skipConfig, cwd }: { skipInstall: boolean, skipConfig: boolean, cwd: string }, projectPkg: any) {
93+
// Add npm dependency
94+
if (!skipInstall) {
95+
const isDev = Boolean(projectPkg.devDependencies?.nuxt)
96+
consola.info(`Installing \`${r.map(x => x.pkg).join(', ')}\`${isDev ? ' development' : ''} dep(s)`)
97+
const res = await addDependency(r.map(x => x.pkg), { cwd, dev: isDev, installPeerDependencies: true }).catch(
98+
(error) => {
99+
consola.error(error)
100+
return consola.prompt(
101+
`Install failed for ${
102+
r.map(x => colors.cyan(x.pkg)).join(', ')
103+
}. Do you want to continue adding the module(s) to ${
104+
colors.cyan('nuxt.config')
105+
}?`,
106+
{
107+
type: 'confirm',
108+
initial: false,
109+
},
110+
)
111+
},
112+
)
113+
if (res === false) {
114+
return
115+
}
116+
}
117+
118+
// Update nuxt.config.ts
119+
if (!skipConfig) {
120+
await updateConfig({
121+
cwd,
122+
configFile: 'nuxt.config',
123+
async onCreate() {
124+
consola.info(`Creating \`nuxt.config.ts\``)
125+
return getDefaultNuxtConfig()
126+
},
127+
async onUpdate(config) {
128+
for (const resolved of r) {
129+
if (!config.modules) {
130+
config.modules = []
131+
}
132+
if (config.modules.includes(resolved.pkgName)) {
133+
consola.info(`\`${resolved.pkgName}\` is already in the \`modules\``)
134+
return
135+
}
136+
consola.info(`Adding \`${resolved.pkgName}\` to the \`modules\``)
137+
config.modules.push(resolved.pkgName)
138+
}
139+
},
140+
}).catch((error) => {
141+
consola.error(`Failed to update \`nuxt.config\`: ${error.message}`)
142+
consola.error(`Please manually add \`${r.map(x => x.pkgName).join(', ')}\` to the \`modules\` in \`nuxt.config.ts\``)
143+
return null
144+
})
145+
}
146+
}
147+
134148
function getDefaultNuxtConfig() {
135149
return `
136150
// https://nuxt.com/docs/api/configuration/nuxt-config
@@ -143,18 +157,7 @@ export default defineNuxtConfig({
143157
const packageRegex
144158
= /^(@[a-z0-9-~][a-z0-9-._~]*\/)?([a-z0-9-~][a-z0-9-._~]*)(@[^@]+)?$/
145159

146-
async function resolveModule(
147-
moduleName: string,
148-
cwd: string,
149-
): Promise<
150-
| false
151-
| {
152-
nuxtModule?: NuxtModule
153-
pkg: string
154-
pkgName: string
155-
pkgVersion: string
156-
}
157-
> {
160+
async function resolveModule(moduleName: string, cwd: string): Promise<ModuleResolution> {
158161
let pkgName = moduleName
159162
let pkgVersion: string | undefined
160163

@@ -362,7 +365,7 @@ async function getRegistryFromFile(paths: string[], scope: string | null) {
362365
}
363366
}
364367
catch {
365-
// swallow errors as file does not exist
368+
// swallow errors as file does not exist
366369
}
367370
finally {
368371
await fd?.close()

0 commit comments

Comments
 (0)