1
1
#!/usr/bin/env node
2
- function runCommand ( command , options ) {
2
+
3
+ process . exitCode = 0 ;
4
+
5
+ /**
6
+ * @param {string } command process to run
7
+ * @param {string[] } args commandline arguments
8
+ * @returns {Promise<void> } promise
9
+ */
10
+ const runCommand = ( command , args ) => {
3
11
const cp = require ( "child_process" ) ;
4
12
return new Promise ( ( resolve , reject ) => {
5
- const executedCommand = cp . spawn ( command , options , {
13
+ const executedCommand = cp . spawn ( command , args , {
6
14
stdio : "inherit" ,
7
15
shell : true
8
16
} ) ;
@@ -13,69 +21,146 @@ function runCommand(command, options) {
13
21
14
22
executedCommand . on ( "exit" , code => {
15
23
if ( code === 0 ) {
16
- resolve ( true ) ;
24
+ resolve ( ) ;
17
25
} else {
18
26
reject ( ) ;
19
27
}
20
28
} ) ;
21
29
} ) ;
22
- }
30
+ } ;
23
31
24
- let webpackCliInstalled = false ;
25
- try {
26
- require . resolve ( "webpack-cli" ) ;
27
- webpackCliInstalled = true ;
28
- } catch ( err ) {
29
- webpackCliInstalled = false ;
30
- }
32
+ /**
33
+ * @param { string } packageName name of the package
34
+ * @returns { boolean } is the package installed?
35
+ */
36
+ const isInstalled = packageName => {
37
+ try {
38
+ require . resolve ( packageName ) ;
31
39
32
- if ( ! webpackCliInstalled ) {
40
+ return true ;
41
+ } catch ( err ) {
42
+ return false ;
43
+ }
44
+ } ;
45
+
46
+ /**
47
+ * @typedef {Object } CliOption
48
+ * @property {string } name display name
49
+ * @property {string } package npm package name
50
+ * @property {string } alias shortcut for choice
51
+ * @property {boolean } installed currently installed?
52
+ * @property {string } url homepage
53
+ * @property {string } description description
54
+ */
55
+
56
+ /** @type {CliOption[] } */
57
+ const CLIs = [
58
+ {
59
+ name : "webpack-cli" ,
60
+ package : "webpack-cli" ,
61
+ alias : "cli" ,
62
+ installed : isInstalled ( "webpack-cli" ) ,
63
+ url : "https://github.com/webpack/webpack-cli" ,
64
+ description : "The original webpack full-featured CLI."
65
+ } ,
66
+ {
67
+ name : "webpack-command" ,
68
+ package : "webpack-command" ,
69
+ alias : "command" ,
70
+ installed : isInstalled ( "webpack-command" ) ,
71
+ url : "https://github.com/webpack-contrib/webpack-command" ,
72
+ description : "A lightweight, opinionated webpack CLI."
73
+ }
74
+ ] ;
75
+
76
+ const installedClis = CLIs . filter ( cli => cli . installed ) ;
77
+
78
+ if ( installedClis . length === 0 ) {
33
79
const path = require ( "path" ) ;
34
80
const fs = require ( "fs" ) ;
35
81
const readLine = require ( "readline" ) ;
36
- const isYarn = fs . existsSync ( path . resolve ( process . cwd ( ) , "yarn.lock" ) ) ;
37
82
38
- const packageManager = isYarn ? "yarn" : "npm" ;
39
- const options = [ "install" , "-D" , "webpack-cli" ] ;
83
+ let notify =
84
+ "One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:" ;
40
85
41
- if ( isYarn ) {
42
- options [ 0 ] = "add" ;
86
+ for ( const item of CLIs ) {
87
+ notify += `\n - ${ item . name } ( ${ item . url } )\n ${ item . description } ` ;
43
88
}
44
89
45
- const commandToBeRun = ` ${ packageManager } ${ options . join ( " " ) } ` ;
90
+ console . error ( notify ) ;
46
91
47
- const question = `Would you like to install webpack-cli? (That will run ${ commandToBeRun } ) (yes/NO)` ;
92
+ const isYarn = fs . existsSync ( path . resolve ( process . cwd ( ) , "yarn.lock" ) ) ;
93
+
94
+ const packageManager = isYarn ? "yarn" : "npm" ;
95
+ const installOptions = [ isYarn ? "add" : "install" , "-D" ] ;
96
+
97
+ console . error (
98
+ `We will use "${ packageManager } " to install the CLI via "${ packageManager } ${ installOptions . join (
99
+ " "
100
+ ) } ".`
101
+ ) ;
102
+
103
+ let question = `Which one do you like to install (${ CLIs . map (
104
+ item => item . name
105
+ ) . join ( "/" ) } ):\n`;
48
106
49
- console . error ( "The CLI moved into a separate package: webpack-cli" ) ;
50
107
const questionInterface = readLine . createInterface ( {
51
108
input : process . stdin ,
52
- output : process . stdout
109
+ output : process . stderr
53
110
} ) ;
54
111
questionInterface . question ( question , answer => {
55
112
questionInterface . close ( ) ;
56
- switch ( answer . toLowerCase ( ) ) {
57
- case "y" :
58
- case "yes" :
59
- case "1" : {
60
- runCommand ( packageManager , options )
61
- . then ( result => {
62
- return require ( "webpack-cli" ) ; //eslint-disable-line
63
- } )
64
- . catch ( error => {
65
- console . error ( error ) ;
66
- process . exitCode = 1 ;
67
- } ) ;
68
- break ;
69
- }
70
- default : {
71
- console . error (
72
- "It needs to be installed alongside webpack to use the CLI"
73
- ) ;
74
- process . exitCode = 1 ;
75
- break ;
76
- }
113
+
114
+ const normalizedAnswer = answer . toLowerCase ( ) ;
115
+ const selectedPackage = CLIs . find ( item => {
116
+ return item . name === normalizedAnswer || item . alias === normalizedAnswer ;
117
+ } ) ;
118
+
119
+ if ( ! normalizedAnswer ) {
120
+ console . error (
121
+ "One CLI needs to be installed alongside webpack to use the CLI."
122
+ ) ;
123
+ process . exitCode = 1 ;
124
+
125
+ return ;
126
+ } else if ( ! selectedPackage ) {
127
+ console . error (
128
+ "No matching choice.\n" +
129
+ "One CLI needs to be installed alongside webpack to use the CLI.\n" +
130
+ "Try to installing your CLI of choice manually."
131
+ ) ;
132
+ process . exitCode = 1 ;
133
+
134
+ return ;
77
135
}
136
+
137
+ const packageName = selectedPackage . package ;
138
+
139
+ console . log (
140
+ `Installing '${
141
+ selectedPackage . name
142
+ } ' (running '${ packageManager } ${ installOptions . join (
143
+ " "
144
+ ) } ${ packageName } ')...`
145
+ ) ;
146
+
147
+ runCommand ( packageManager , installOptions . concat ( packageName ) )
148
+ . then ( ( ) => {
149
+ require ( packageName ) ; //eslint-disable-line
150
+ } )
151
+ . catch ( error => {
152
+ console . error ( error ) ;
153
+ process . exitCode = 1 ;
154
+ } ) ;
78
155
} ) ;
156
+ } else if ( installedClis . length === 1 ) {
157
+ require ( installedClis [ 0 ] . package ) ; // eslint-disable-line
79
158
} else {
80
- require ( "webpack-cli" ) ; // eslint-disable-line
159
+ console . warn (
160
+ `You have installed ${ installedClis
161
+ . map ( item => item . name )
162
+ . join (
163
+ " and "
164
+ ) } together. To work with the "webpack" command you need only one CLI package, please remove one of them or use them directly via their binary.`
165
+ ) ;
81
166
}
0 commit comments