| #!/usr/bin/env node |
| |
| // @ts-ignore |
| process.exitCode = 0; |
| |
| /** |
| * @param {string} command process to run |
| * @param {string[]} args commandline arguments |
| * @returns {Promise<void>} promise |
| */ |
| const runCommand = (command, args) => { |
| const cp = require("child_process"); |
| return new Promise((resolve, reject) => { |
| const executedCommand = cp.spawn(command, args, { |
| stdio: "inherit", |
| shell: true |
| }); |
| |
| executedCommand.on("error", error => { |
| reject(error); |
| }); |
| |
| executedCommand.on("exit", code => { |
| if (code === 0) { |
| resolve(); |
| } else { |
| reject(); |
| } |
| }); |
| }); |
| }; |
| |
| /** |
| * @param {string} packageName name of the package |
| * @returns {boolean} is the package installed? |
| */ |
| const isInstalled = packageName => { |
| try { |
| require.resolve(packageName); |
| |
| return true; |
| } catch (err) { |
| return false; |
| } |
| }; |
| |
| /** |
| * @typedef {Object} CliOption |
| * @property {string} name display name |
| * @property {string} package npm package name |
| * @property {string} binName name of the executable file |
| * @property {string} alias shortcut for choice |
| * @property {boolean} installed currently installed? |
| * @property {boolean} recommended is recommended |
| * @property {string} url homepage |
| * @property {string} description description |
| */ |
| |
| /** @type {CliOption[]} */ |
| const CLIs = [ |
| { |
| name: "webpack-cli", |
| package: "webpack-cli", |
| binName: "webpack-cli", |
| alias: "cli", |
| installed: isInstalled("webpack-cli"), |
| recommended: true, |
| url: "https://github.com/webpack/webpack-cli", |
| description: "The original webpack full-featured CLI." |
| }, |
| { |
| name: "webpack-command", |
| package: "webpack-command", |
| binName: "webpack-command", |
| alias: "command", |
| installed: isInstalled("webpack-command"), |
| recommended: false, |
| url: "https://github.com/webpack-contrib/webpack-command", |
| description: "A lightweight, opinionated webpack CLI." |
| } |
| ]; |
| |
| const installedClis = CLIs.filter(cli => cli.installed); |
| |
| if (installedClis.length === 0) { |
| const path = require("path"); |
| const fs = require("fs"); |
| const readLine = require("readline"); |
| |
| let notify = |
| "One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:"; |
| |
| for (const item of CLIs) { |
| if (item.recommended) { |
| notify += `\n - ${item.name} (${item.url})\n ${item.description}`; |
| } |
| } |
| |
| console.error(notify); |
| |
| const isYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock")); |
| |
| const packageManager = isYarn ? "yarn" : "npm"; |
| const installOptions = [isYarn ? "add" : "install", "-D"]; |
| |
| console.error( |
| `We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join( |
| " " |
| )}".` |
| ); |
| |
| const question = `Do you want to install 'webpack-cli' (yes/no): `; |
| |
| const questionInterface = readLine.createInterface({ |
| input: process.stdin, |
| output: process.stderr |
| }); |
| questionInterface.question(question, answer => { |
| questionInterface.close(); |
| |
| const normalizedAnswer = answer.toLowerCase().startsWith("y"); |
| |
| if (!normalizedAnswer) { |
| console.error( |
| "You need to install 'webpack-cli' to use webpack via CLI.\n" + |
| "You can also install the CLI manually." |
| ); |
| process.exitCode = 1; |
| |
| return; |
| } |
| |
| const packageName = "webpack-cli"; |
| |
| console.log( |
| `Installing '${packageName}' (running '${packageManager} ${installOptions.join( |
| " " |
| )} ${packageName}')...` |
| ); |
| |
| runCommand(packageManager, installOptions.concat(packageName)) |
| .then(() => { |
| require(packageName); //eslint-disable-line |
| }) |
| .catch(error => { |
| console.error(error); |
| process.exitCode = 1; |
| }); |
| }); |
| } else if (installedClis.length === 1) { |
| const path = require("path"); |
| const pkgPath = require.resolve(`${installedClis[0].package}/package.json`); |
| // eslint-disable-next-line node/no-missing-require |
| const pkg = require(pkgPath); |
| // eslint-disable-next-line node/no-missing-require |
| require(path.resolve( |
| path.dirname(pkgPath), |
| pkg.bin[installedClis[0].binName] |
| )); |
| } else { |
| console.warn( |
| `You have installed ${installedClis |
| .map(item => item.name) |
| .join( |
| " and " |
| )} 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.` |
| ); |
| |
| // @ts-ignore |
| process.exitCode = 1; |
| } |