11#!/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 ) => {
311 const cp = require ( "child_process" ) ;
412 return new Promise ( ( resolve , reject ) => {
5- const executedCommand = cp . spawn ( command , options , {
13+ const executedCommand = cp . spawn ( command , args , {
614 stdio : "inherit" ,
715 shell : true
816 } ) ;
@@ -13,114 +21,146 @@ function runCommand(command, options) {
1321
1422 executedCommand . on ( "exit" , code => {
1523 if ( code === 0 ) {
16- resolve ( true ) ;
24+ resolve ( ) ;
1725 } else {
1826 reject ( ) ;
1927 }
2028 } ) ;
2129 } ) ;
22- }
30+ } ;
2331
24- function isInstalled ( packageName ) {
32+ /**
33+ * @param {string } packageName name of the package
34+ * @returns {boolean } is the package installed?
35+ */
36+ const isInstalled = packageName => {
2537 try {
2638 require . resolve ( packageName ) ;
2739
2840 return true ;
2941 } catch ( err ) {
3042 return false ;
3143 }
32- }
33-
34- const CLI = [
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 = [
3558 {
3659 name : "webpack-cli" ,
60+ package : "webpack-cli" ,
61+ alias : "cli" ,
3762 installed : isInstalled ( "webpack-cli" ) ,
38- URL : "https://github.com/webpack/webpack-cli" ,
39- description : "The original webpack full-featured CLI from webpack@3 ."
63+ url : "https://github.com/webpack/webpack-cli" ,
64+ description : "The original webpack full-featured CLI."
4065 } ,
4166 {
4267 name : "webpack-command" ,
68+ package : "webpack-command" ,
69+ alias : "command" ,
4370 installed : isInstalled ( "webpack-command" ) ,
44- URL : "https://github.com/webpack-contrib/webpack-command" ,
71+ url : "https://github.com/webpack-contrib/webpack-command" ,
4572 description : "A lightweight, opinionated webpack CLI."
4673 }
4774] ;
4875
49- if ( CLI . every ( item => ! item . installed ) ) {
76+ const installedClis = CLIs . filter ( cli => cli . installed ) ;
77+
78+ if ( installedClis . length === 0 ) {
5079 const path = require ( "path" ) ;
5180 const fs = require ( "fs" ) ;
5281 const readLine = require ( "readline" ) ;
5382
5483 let notify =
55- "The CLI for webpack must be installed as a separate package, for which there are choices:\n " ;
84+ "One CLI for webpack must be installed. These are recommended choices, delivered as separate packages: " ;
5685
57- CLI . forEach ( item => {
58- notify += ` ${ item . name } (${ item . URL } ): ${ item . description } \n ` ;
59- } ) ;
86+ for ( const item of CLIs ) {
87+ notify += `\n - ${ item . name } (${ item . url } )\n ${ item . description } ` ;
88+ }
6089
6190 console . error ( notify ) ;
6291
6392 const isYarn = fs . existsSync ( path . resolve ( process . cwd ( ) , "yarn.lock" ) ) ;
6493
6594 const packageManager = isYarn ? "yarn" : "npm" ;
66- const installOptions = [ "install" , "-D" ] ;
95+ const installOptions = [ isYarn ? "add" : "install" , "-D" ] ;
6796
68- if ( isYarn ) {
69- installOptions [ 0 ] = "add" ;
70- }
97+ console . error (
98+ `We will use "${ packageManager } " to install the CLI via "${ packageManager } ${ installOptions . join (
99+ " "
100+ ) } ".`
101+ ) ;
71102
72- let question = `Would you like to install (${ CLI . map ( item => item . name ) . join (
73- "/"
74- ) } ):\n`;
103+ let question = `Which one do you like to install (${ CLIs . map (
104+ item => item . name
105+ ) . join ( "/" ) } ):\n`;
75106
76107 const questionInterface = readLine . createInterface ( {
77108 input : process . stdin ,
78- output : process . stdout
109+ output : process . stderr
79110 } ) ;
80111 questionInterface . question ( question , answer => {
81112 questionInterface . close ( ) ;
82113
83114 const normalizedAnswer = answer . toLowerCase ( ) ;
84- const selectedPackage = CLI . find ( item => item . name === normalizedAnswer ) ;
115+ const selectedPackage = CLIs . find ( item => {
116+ return item . name === normalizedAnswer || item . alias === normalizedAnswer ;
117+ } ) ;
85118
86- if ( ! selectedPackage ) {
119+ if ( ! normalizedAnswer ) {
87120 console . error (
88- "It needs to be installed alongside webpack to use the CLI"
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."
89131 ) ;
90132 process . exitCode = 1 ;
91133
92134 return ;
93135 }
94136
95- installOptions . push ( normalizedAnswer ) ;
137+ const packageName = selectedPackage . package ;
96138
97139 console . log (
98- `Installing '${ normalizedAnswer } ' (running '${ packageManager } ${ installOptions . join (
140+ `Installing '${
141+ selectedPackage . name
142+ } ' (running '${ packageManager } ${ installOptions . join (
99143 " "
100- ) } ')...`
144+ ) } ${ packageName } ')...`
101145 ) ;
102146
103- runCommand ( packageManager , installOptions )
104- . then ( result => {
105- return require ( normalizedAnswer ) ; //eslint-disable-line
147+ runCommand ( packageManager , installOptions . concat ( packageName ) )
148+ . then ( ( ) => {
149+ require ( packageName ) ; //eslint-disable-line
106150 } )
107151 . catch ( error => {
108152 console . error ( error ) ;
109153 process . exitCode = 1 ;
110154 } ) ;
111155 } ) ;
156+ } else if ( installedClis . length === 1 ) {
157+ require ( installedClis [ 0 ] . package ) ; // eslint-disable-line
112158} else {
113- const installedPackage = CLI . map (
114- item => ( item . installed ? item . name : "" )
115- ) . filter ( v => v ) ;
116-
117- if ( installedPackage . length > 1 ) {
118- console . warn (
119- `You have installed ${ installedPackage . join (
159+ console . warn (
160+ `You have installed ${ installedClis
161+ . map ( item => item . name )
162+ . join (
120163 " and "
121- ) } together. To work with the webpack you need only one CLI package, please remove one of them`
122- ) ;
123- }
124-
125- require ( installedPackage [ 0 ] ) ; // eslint-disable-line
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+ ) ;
126166}
0 commit comments