Skip to content

Commit

Permalink
feat: allow to run commands not requiring webpack without webpack ins…
Browse files Browse the repository at this point in the history
…tallation
  • Loading branch information
alexander-akait committed Aug 20, 2021
1 parent 77668d7 commit 463bf5e
Show file tree
Hide file tree
Showing 16 changed files with 281 additions and 203 deletions.
15 changes: 8 additions & 7 deletions packages/configtest/src/index.ts
@@ -1,14 +1,13 @@
class ConfigTestCommand {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
async apply(cli: any): Promise<void> {
const { logger, webpack } = cli;

await cli.makeCommand(
{
name: "configtest [config-path]",
alias: "t",
description: "Validate a webpack configuration.",
pkg: "@webpack-cli/configtest",
dependencies: ["webpack"],
},
[],
async (configPath: string | undefined): Promise<void> => {
Expand All @@ -28,11 +27,13 @@ class ConfigTestCommand {
}

if (configPaths.size === 0) {
logger.error("No configuration found.");
cli.logger.error("No configuration found.");
process.exit(2);
}

logger.info(`Validate '${Array.from(configPaths).join(" ,")}'.`);
cli.logger.info(`Validate '${Array.from(configPaths).join(" ,")}'.`);

const webpack = await cli.loadWebpack();

try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -44,15 +45,15 @@ class ConfigTestCommand {
}
} catch (error) {
if (cli.isValidationError(error)) {
logger.error(error.message);
cli.logger.error(error.message);
} else {
logger.error(error);
cli.logger.error(error);
}

process.exit(2);
}

logger.success(
cli.logger.success(
"There are no validation errors in the given webpack configuration.",
);
},
Expand Down
8 changes: 3 additions & 5 deletions packages/generators/src/index.ts
Expand Up @@ -7,8 +7,6 @@ import initGenerator from "./init-generator";
class GeneratorsCommand {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
async apply(cli: any): Promise<void> {
const { logger } = cli;

await cli.makeCommand(
{
name: "init [generation-path]",
Expand Down Expand Up @@ -51,7 +49,7 @@ class GeneratorsCommand {
env.registerStub(initGenerator, generatorName);

env.run(generatorName, { cli, options }, () => {
logger.success("Project has been initialised with webpack!");
cli.logger.success("Project has been initialised with webpack!");
});
},
);
Expand Down Expand Up @@ -83,7 +81,7 @@ class GeneratorsCommand {
env.registerStub(loaderGenerator, generatorName);

env.run(generatorName, { cli, options }, () => {
logger.success("Loader template has been successfully scaffolded.");
cli.logger.success("Loader template has been successfully scaffolded.");
});
},
);
Expand Down Expand Up @@ -115,7 +113,7 @@ class GeneratorsCommand {
env.registerStub(pluginGenerator, generatorName);

env.run(generatorName, { cli, options }, () => {
logger.success("Plugin template has been successfully scaffolded.");
cli.logger.success("Plugin template has been successfully scaffolded.");
});
},
);
Expand Down
6 changes: 2 additions & 4 deletions packages/info/src/index.ts
Expand Up @@ -32,8 +32,6 @@ const DEFAULT_DETAILS: Information = {
class InfoCommand {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
async apply(cli: any): Promise<void> {
const { logger } = cli;

await cli.makeCommand(
{
name: "info",
Expand Down Expand Up @@ -72,7 +70,7 @@ class InfoCommand {
envinfoConfig["json"] = true;
break;
default:
logger.error(`'${output}' is not a valid value for output`);
cli.logger.error(`'${output}' is not a valid value for output`);
process.exit(2);
}
}
Expand All @@ -82,7 +80,7 @@ class InfoCommand {
info = info.replace(/npmPackages/g, "Packages");
info = info.replace(/npmGlobalPackages/g, "Global Packages");

logger.raw(info);
cli.logger.raw(info);
},
);
}
Expand Down
27 changes: 15 additions & 12 deletions packages/serve/src/index.ts
Expand Up @@ -3,8 +3,6 @@ import { devServerOptionsType } from "./types";
class ServeCommand {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
async apply(cli: any): Promise<void> {
const { logger, webpack } = cli;

const loadDevServerOptions = () => {
// TODO simplify this after drop webpack v4 and webpack-dev-server v3
// eslint-disable-next-line @typescript-eslint/no-var-requires, node/no-extraneous-require
Expand All @@ -14,8 +12,8 @@ class ServeCommand {
let options = {};

if (isNewDevServerCLIAPI) {
if (webpack.cli && typeof webpack.cli.getArguments === "function") {
options = webpack.cli.getArguments(devServer.schema);
if (cli.webpack.cli && typeof cli.webpack.cli.getArguments === "function") {
options = cli.webpack.cli.getArguments(devServer.schema);
} else {
options = devServer.cli.getArguments();
}
Expand Down Expand Up @@ -50,15 +48,19 @@ class ServeCommand {
description: "Run the webpack dev server.",
usage: "[entries...] [options]",
pkg: "@webpack-cli/serve",
dependencies: ["webpack-dev-server"],
dependencies: ["webpack", "webpack-dev-server"],
},
() => {
async () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
cli.webpack = await cli.loadWebpack();

let devServerFlags = [];

try {
devServerFlags = loadDevServerOptions();
} catch (error) {
logger.error(
cli.logger.error(
`You need to install 'webpack-dev-server' for running 'webpack serve'.\n${error}`,
);
process.exit(2);
Expand Down Expand Up @@ -173,7 +175,7 @@ class ServeCommand {
// eslint-disable-next-line node/no-extraneous-require, @typescript-eslint/no-var-requires
devServerVersion = require("webpack-dev-server/package.json").version;
} catch (err) {
logger.error(
cli.logger.error(
`You need to install 'webpack-dev-server' for running 'webpack serve'.\n${err}`,
);
process.exit(2);
Expand Down Expand Up @@ -209,8 +211,9 @@ class ServeCommand {
);
const result = { ...(compilerForDevServer.options.devServer || {}) };
const problems = (
webpack.cli && typeof webpack.cli.processArguments === "function"
? webpack.cli
cli.webpack.cli &&
typeof cli.webpack.cli.processArguments === "function"
? cli.webpack.cli
: DevServer.cli
).processArguments(args, result, values);

Expand Down Expand Up @@ -356,9 +359,9 @@ class ServeCommand {
servers.push(server);
} catch (error) {
if (cli.isValidationError(error)) {
logger.error(error.message);
cli.logger.error(error.message);
} else {
logger.error(error);
cli.logger.error(error);
}

process.exit(2);
Expand Down
25 changes: 1 addition & 24 deletions packages/webpack-cli/bin/cli.js
Expand Up @@ -10,7 +10,6 @@ require("v8-compile-cache");

const importLocal = require("import-local");
const runCLI = require("../lib/bootstrap");
const utils = require("../lib/utils");

if (!process.env.WEBPACK_CLI_SKIP_IMPORT_LOCAL) {
// Prefer the local installation of `webpack-cli`
Expand All @@ -21,26 +20,4 @@ if (!process.env.WEBPACK_CLI_SKIP_IMPORT_LOCAL) {

process.title = "webpack";

if (utils.packageExists("webpack")) {
runCLI(process.argv, originalModuleCompile);
} else {
const { promptInstallation, logger, colors } = utils;

promptInstallation("webpack", () => {
utils.logger.error(`It looks like ${colors.bold("webpack")} is not installed.`);
})
.then(() => {
logger.success(`${colors.bold("webpack")} was installed successfully.`);

runCLI(process.argv, originalModuleCompile);
})
.catch(() => {
logger.error(
`Action Interrupted, Please try once again or install ${colors.bold(
"webpack",
)} manually.`,
);

process.exit(2);
});
}
runCLI(process.argv, originalModuleCompile);
69 changes: 47 additions & 22 deletions packages/webpack-cli/lib/webpack-cli.js
Expand Up @@ -8,8 +8,6 @@ const utils = require("./utils");

class WebpackCLI {
constructor() {
// Global
this.webpack = require(process.env.WEBPACK_PACKAGE || "webpack");
this.logger = utils.logger;
this.utils = utils;

Expand Down Expand Up @@ -76,19 +74,27 @@ class WebpackCLI {
return result;
}

loadJSONFile(pathToFile) {
loadJSONFile(pathToFile, handleError = true) {
let result;

try {
result = require(pathToFile);
} catch (error) {
this.logger.error(error);
process.exit(2);
if (handleError) {
this.logger.error(error);
process.exit(2);
} else {
throw error;
}
}

return result;
}

async loadWebpack(handleError = true) {
return this.tryRequireThenImport(process.env.WEBPACK_PACKAGE || "webpack", handleError);
}

async makeCommand(commandOptions, options, action) {
const alreadyLoaded = this.program.commands.find(
(command) =>
Expand Down Expand Up @@ -148,7 +154,7 @@ class WebpackCLI {
this.logger.error(
`For using '${colors.green(
commandOptions.name.split(" ")[0],
)}' command you need to install: '${colors.green(dependency)}' package`,
)}' command you need to install: '${colors.green(dependency)}' package.`,
);
});
}
Expand All @@ -162,11 +168,11 @@ class WebpackCLI {
commandOptions.description
} To see all available options you need to install ${commandOptions.dependencies
.map((dependency) => `'${dependency}'`)
.join(",")}.`,
.join(", ")}.`,
);
options = [];
} else {
options = options();
options = await options();
}
}

Expand Down Expand Up @@ -727,12 +733,14 @@ class WebpackCLI {
alias: ["bundle", "b"],
description: "Run webpack (default command, can be omitted).",
usage: "[entries...] [options]",
dependencies: ["webpack"],
};
const watchCommandOptions = {
name: "watch [entries...]",
alias: "w",
description: "Run webpack and watch for files changes.",
usage: "[entries...] [options]",
dependencies: ["webpack"],
};
const versionCommandOptions = {
name: "version [commands...]",
Expand Down Expand Up @@ -835,13 +843,15 @@ class WebpackCLI {
const isWatchCommandUsed = isCommand(commandName, watchCommandOptions);

if (isBuildCommandUsed || isWatchCommandUsed) {
const options = this.getBuiltInOptions();

await this.makeCommand(
isBuildCommandUsed ? buildCommandOptions : watchCommandOptions,
isWatchCommandUsed
? options.filter((option) => option.name !== "watch")
: options,
async () => {
this.webpack = await this.loadWebpack();

return isWatchCommandUsed
? this.getBuiltInOptions().filter((option) => option.name !== "watch")
: this.getBuiltInOptions();
},
async (entries, options) => {
if (entries.length > 0) {
options.entry = [...entries, ...(options.entry || [])];
Expand All @@ -854,7 +864,7 @@ class WebpackCLI {
// Stub for the `help` command
this.makeCommand(helpCommandOptions, [], () => {});
} else if (isCommand(commandName, versionCommandOptions)) {
// Stub for the `help` command
// Stub for the `version` command
this.makeCommand(versionCommandOptions, [], () => {});
} else {
const builtInExternalCommandInfo = externalBuiltInCommandsInfo.find(
Expand Down Expand Up @@ -884,7 +894,7 @@ class WebpackCLI {
this.logger.error(
`For using this command you need to install: '${colors.green(
pkg,
)}' package`,
)}' package.`,
);
});
}
Expand Down Expand Up @@ -1048,17 +1058,32 @@ class WebpackCLI {
}
}

let webpack;

try {
webpack = await this.loadWebpack(false);
} catch (_error) {
// Nothing
}

this.logger.raw(`webpack: ${webpack ? webpack.version : "not installed"}`);

const pkgJSON = this.loadJSONFile("../package.json");

this.logger.raw(`webpack ${this.webpack.version}`);
this.logger.raw(`webpack-cli ${pkgJSON.version}`);
this.logger.raw(`webpack-cli: ${pkgJSON.version}`);

if (this.utils.packageExists("webpack-dev-server")) {
const { version } = this.loadJSONFile("webpack-dev-server/package.json");
let devServer;

this.logger.raw(`webpack-dev-server ${version}`);
try {
devServer = await this.loadJSONFile("webpack-dev-server/package.json", false);
} catch (_error) {
// Nothing
}

this.logger.raw(
`webpack-dev-server ${devServer ? devServer.version : "not installed"}`,
);

process.exit(0);
};
this.program.option(
Expand Down Expand Up @@ -1276,12 +1301,12 @@ class WebpackCLI {
);
if (typeof builtInCommandUsed !== "undefined") {
this.logger.error(
`For using '${name}' command you need to install '${builtInCommandUsed.pkg}' package`,
`For using '${name}' command you need to install '${builtInCommandUsed.pkg}' package.`,
);
} else {
this.logger.error(`Can't find and load command '${name}'`);
this.logger.error(
"Run 'webpack --help' to see available commands and options",
"Run 'webpack --help' to see available commands and options.",
);
}
process.exit(2);
Expand Down

0 comments on commit 463bf5e

Please sign in to comment.