4
4
import fs from 'node:fs'
5
5
import path from 'node:path'
6
6
import { fileURLToPath } from 'node:url'
7
+ import spawn from 'cross-spawn'
7
8
import minimist from 'minimist'
8
9
import prompts from 'prompts'
9
10
import {
10
11
blue ,
11
12
cyan ,
12
13
green ,
14
+ lightGreen ,
13
15
lightRed ,
14
16
magenta ,
15
17
red ,
@@ -25,6 +27,7 @@ const cwd = process.cwd()
25
27
const FRAMEWORKS = [
26
28
{
27
29
name : 'vanilla' ,
30
+ display : 'Vanilla' ,
28
31
color : yellow ,
29
32
variants : [
30
33
{
@@ -41,6 +44,7 @@ const FRAMEWORKS = [
41
44
} ,
42
45
{
43
46
name : 'vue' ,
47
+ display : 'Vue' ,
44
48
color : green ,
45
49
variants : [
46
50
{
@@ -52,11 +56,24 @@ const FRAMEWORKS = [
52
56
name : 'vue-ts' ,
53
57
display : 'TypeScript' ,
54
58
color : blue
59
+ } ,
60
+ {
61
+ name : 'custom-create-vue' ,
62
+ display : 'Customize with create-vue' ,
63
+ color : green ,
64
+ customCommand : 'npm create vue@latest TARGET_DIR'
65
+ } ,
66
+ {
67
+ name : 'custom-nuxt' ,
68
+ display : 'Nuxt' ,
69
+ color : lightGreen ,
70
+ customCommand : 'npm exec nuxi init TARGET_DIR'
55
71
}
56
72
]
57
73
} ,
58
74
{
59
75
name : 'react' ,
76
+ display : 'React' ,
60
77
color : cyan ,
61
78
variants : [
62
79
{
@@ -73,6 +90,7 @@ const FRAMEWORKS = [
73
90
} ,
74
91
{
75
92
name : 'preact' ,
93
+ display : 'Preact' ,
76
94
color : magenta ,
77
95
variants : [
78
96
{
@@ -89,6 +107,7 @@ const FRAMEWORKS = [
89
107
} ,
90
108
{
91
109
name : 'lit' ,
110
+ display : 'Lit' ,
92
111
color : lightRed ,
93
112
variants : [
94
113
{
@@ -105,6 +124,7 @@ const FRAMEWORKS = [
105
124
} ,
106
125
{
107
126
name : 'svelte' ,
127
+ display : 'Svelte' ,
108
128
color : red ,
109
129
variants : [
110
130
{
@@ -116,6 +136,12 @@ const FRAMEWORKS = [
116
136
name : 'svelte-ts' ,
117
137
display : 'TypeScript' ,
118
138
color : blue
139
+ } ,
140
+ {
141
+ name : 'custom-svelte-kit' ,
142
+ display : 'SvelteKit' ,
143
+ color : red ,
144
+ customCommand : 'npm create svelte@latest TARGET_DIR'
119
145
}
120
146
]
121
147
}
@@ -191,7 +217,7 @@ async function init() {
191
217
choices : FRAMEWORKS . map ( ( framework ) => {
192
218
const frameworkColor = framework . color
193
219
return {
194
- title : frameworkColor ( framework . name ) ,
220
+ title : frameworkColor ( framework . display || framework . name ) ,
195
221
value : framework
196
222
}
197
223
} )
@@ -206,7 +232,7 @@ async function init() {
206
232
framework . variants . map ( ( variant ) => {
207
233
const variantColor = variant . color
208
234
return {
209
- title : variantColor ( variant . name ) ,
235
+ title : variantColor ( variant . display || variant . name ) ,
210
236
value : variant . name
211
237
}
212
238
} )
@@ -237,6 +263,46 @@ async function init() {
237
263
// determine template
238
264
template = variant || framework || template
239
265
266
+ const pkgInfo = pkgFromUserAgent ( process . env . npm_config_user_agent )
267
+ const pkgManager = pkgInfo ? pkgInfo . name : 'npm'
268
+ const isYarn1 = pkgManager === 'yarn' && pkgInfo ?. version . startsWith ( '1.' )
269
+
270
+ if ( template . startsWith ( 'custom-' ) ) {
271
+ const getCustomCommand = ( name ) => {
272
+ for ( const f of FRAMEWORKS ) {
273
+ for ( const v of f . variants || [ ] ) {
274
+ if ( v . name === name ) {
275
+ return v . customCommand
276
+ }
277
+ }
278
+ }
279
+ }
280
+ const customCommand = getCustomCommand ( template )
281
+ const fullCustomCommand = customCommand
282
+ . replace ( 'TARGET_DIR' , targetDir )
283
+ . replace ( / ^ n p m c r e a t e / , `${ pkgManager } create` )
284
+ // Only Yarn 1.x doesn't support `@version` in the `create` command
285
+ . replace ( '@latest' , ( ) => ( isYarn1 ? '' : '@latest' ) )
286
+ . replace ( / ^ n p m e x e c / , ( ) => {
287
+ // Prefer `pnpm dlx` or `yarn dlx`
288
+ if ( pkgManager === 'pnpm' ) {
289
+ return 'pnpm dlx'
290
+ }
291
+ if ( pkgManager === 'yarn' && ! isYarn1 ) {
292
+ return 'yarn dlx'
293
+ }
294
+ // Use `npm exec` in all other cases,
295
+ // including Yarn 1.x and other custom npm clients.
296
+ return 'npm exec'
297
+ } )
298
+
299
+ const [ command , ...args ] = fullCustomCommand . split ( ' ' )
300
+ const { status } = spawn . sync ( command , args , {
301
+ stdio : 'inherit'
302
+ } )
303
+ process . exit ( status ?? 0 )
304
+ }
305
+
240
306
console . log ( `\nScaffolding project in ${ root } ...` )
241
307
242
308
const templateDir = path . resolve (
@@ -269,9 +335,6 @@ async function init() {
269
335
270
336
write ( 'package.json' , JSON . stringify ( pkg , null , 2 ) )
271
337
272
- const pkgInfo = pkgFromUserAgent ( process . env . npm_config_user_agent )
273
- const pkgManager = pkgInfo ? pkgInfo . name : 'npm'
274
-
275
338
console . log ( `\nDone. Now run:\n` )
276
339
if ( root !== cwd ) {
277
340
console . log ( ` cd ${ path . relative ( cwd , root ) } ` )
0 commit comments