UNPKG

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