mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			164 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
| #!/usr/bin/env node
 | |
| 
 | |
| /**
 | |
|  * @param {string} command process to run
 | |
|  * @param {string[]} args command line 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 => {
 | |
| 	if (process.versions.pnp) {
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	const path = require("path");
 | |
| 	const fs = require("graceful-fs");
 | |
| 
 | |
| 	let dir = __dirname;
 | |
| 
 | |
| 	do {
 | |
| 		try {
 | |
| 			if (
 | |
| 				fs.statSync(path.join(dir, "node_modules", packageName)).isDirectory()
 | |
| 			) {
 | |
| 				return true;
 | |
| 			}
 | |
| 		} catch (_error) {
 | |
| 			// Nothing
 | |
| 		}
 | |
| 	} while (dir !== (dir = path.dirname(dir)));
 | |
| 
 | |
| 	return false;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * @param {CliOption} cli options
 | |
|  * @returns {void}
 | |
|  */
 | |
| const runCli = cli => {
 | |
| 	const path = require("path");
 | |
| 	const pkgPath = require.resolve(`${cli.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[cli.binName]));
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * @typedef {Object} CliOption
 | |
|  * @property {string} name display name
 | |
|  * @property {string} package npm package name
 | |
|  * @property {string} binName name of the executable file
 | |
|  * @property {boolean} installed currently installed?
 | |
|  * @property {string} url homepage
 | |
|  */
 | |
| 
 | |
| /** @type {CliOption} */
 | |
| const cli = {
 | |
| 	name: "webpack-cli",
 | |
| 	package: "webpack-cli",
 | |
| 	binName: "webpack-cli",
 | |
| 	installed: isInstalled("webpack-cli"),
 | |
| 	url: "https://github.com/webpack/webpack-cli"
 | |
| };
 | |
| 
 | |
| if (!cli.installed) {
 | |
| 	const path = require("path");
 | |
| 	const fs = require("graceful-fs");
 | |
| 	const readLine = require("readline");
 | |
| 
 | |
| 	const notify =
 | |
| 		"CLI for webpack must be installed.\n" + `  ${cli.name} (${cli.url})\n`;
 | |
| 
 | |
| 	console.error(notify);
 | |
| 
 | |
| 	let packageManager;
 | |
| 
 | |
| 	if (fs.existsSync(path.resolve(process.cwd(), "yarn.lock"))) {
 | |
| 		packageManager = "yarn";
 | |
| 	} else if (fs.existsSync(path.resolve(process.cwd(), "pnpm-lock.yaml"))) {
 | |
| 		packageManager = "pnpm";
 | |
| 	} else {
 | |
| 		packageManager = "npm";
 | |
| 	}
 | |
| 
 | |
| 	const installOptions = [packageManager === "yarn" ? "add" : "install", "-D"];
 | |
| 
 | |
| 	console.error(
 | |
| 		`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
 | |
| 			" "
 | |
| 		)} ${cli.package}".`
 | |
| 	);
 | |
| 
 | |
| 	const question = `Do you want to install 'webpack-cli' (yes/no): `;
 | |
| 
 | |
| 	const questionInterface = readLine.createInterface({
 | |
| 		input: process.stdin,
 | |
| 		output: process.stderr
 | |
| 	});
 | |
| 
 | |
| 	// In certain scenarios (e.g. when STDIN is not in terminal mode), the callback function will not be
 | |
| 	// executed. Setting the exit code here to ensure the script exits correctly in those cases. The callback
 | |
| 	// function is responsible for clearing the exit code if the user wishes to install webpack-cli.
 | |
| 	process.exitCode = 1;
 | |
| 	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."
 | |
| 			);
 | |
| 
 | |
| 			return;
 | |
| 		}
 | |
| 		process.exitCode = 0;
 | |
| 
 | |
| 		console.log(
 | |
| 			`Installing '${
 | |
| 				cli.package
 | |
| 			}' (running '${packageManager} ${installOptions.join(" ")} ${
 | |
| 				cli.package
 | |
| 			}')...`
 | |
| 		);
 | |
| 
 | |
| 		runCommand(packageManager, installOptions.concat(cli.package))
 | |
| 			.then(() => {
 | |
| 				runCli(cli);
 | |
| 			})
 | |
| 			.catch(error => {
 | |
| 				console.error(error);
 | |
| 				process.exitCode = 1;
 | |
| 			});
 | |
| 	});
 | |
| } else {
 | |
| 	runCli(cli);
 | |
| }
 |