Skip to content

Commit

Permalink
refactor!: the minimum supported webpack version is v5.0.0 (#3342)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: webpack-cli no longer supports webpack v4, the minimum supported version is webpack v5.0.0
  • Loading branch information
snitin315 authored and alexander-akait committed Nov 15, 2022
1 parent c737383 commit b1af0dc
Show file tree
Hide file tree
Showing 7 changed files with 657 additions and 753 deletions.
331 changes: 97 additions & 234 deletions packages/webpack-cli/src/webpack-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ class WebpackCLI implements IWebpackCLI {
makeOption(command: WebpackCLICommand, option: WebpackCLIBuiltInOption) {
let mainOption: WebpackCLIMainOption;
let negativeOption;
const flagsWithAlias = ["devtool", "output-path", "target", "watch"];

if (flagsWithAlias.includes(option.name)) {
option.alias = option.name[0];
}

if (option.configs) {
let needNegativeOption = false;
Expand Down Expand Up @@ -856,110 +861,6 @@ class WebpackCLI implements IWebpackCLI {
alias: "j",
description: "Prints result as JSON or store it in a file.",
},

// For webpack@4
{
name: "entry",
configs: [
{
type: "string",
},
],
multiple: true,
description: "The entry point(s) of your application e.g. ./src/main.js.",
},
{
name: "output-path",
alias: "o",
configs: [
{
type: "string",
},
],
description: "Output location of the file generated by webpack e.g. ./dist/.",
},
{
name: "target",
alias: "t",
configs: [
{
type: "string",
},
],
multiple: this.webpack.cli !== undefined,
description: "Sets the build target e.g. node.",
},
{
name: "devtool",
configs: [
{
type: "string",
},
{
type: "enum",
values: [false],
},
],
negative: true,
alias: "d",
description: "Determine source maps to use.",
negatedDescription: "Do not generate source maps.",
},
{
name: "mode",
configs: [
{
type: "string",
},
],
description: "Defines the mode to pass to webpack.",
},
{
name: "name",
configs: [
{
type: "string",
},
],
description: "Name of the configuration. Used when loading multiple configurations.",
},
{
name: "stats",
configs: [
{
type: "string",
},
{
type: "boolean",
},
],
negative: true,
description: "It instructs webpack on how to treat the stats e.g. verbose.",
negatedDescription: "Disable stats output.",
},
{
name: "watch",
configs: [
{
type: "boolean",
},
],
negative: true,
alias: "w",
description: "Watch for files changes.",
negatedDescription: "Do not watch for file changes.",
},
{
name: "watch-options-stdin",
configs: [
{
type: "boolean",
},
],
negative: true,
description: "Stop watching when stdin stream has ended.",
negatedDescription: "Do not stop watching when stdin stream has ended.",
},
{
name: "fail-on-warnings",
configs: [
Expand All @@ -974,32 +875,31 @@ class WebpackCLI implements IWebpackCLI {

// Extract all the flags being exported from core.
// A list of cli flags generated by core can be found here https://github.com/webpack/webpack/blob/master/test/__snapshots__/Cli.test.js.snap
const coreFlags = this.webpack.cli
? Object.entries(this.webpack.cli.getArguments()).map(([flag, meta]) => {
const inBuiltIn = builtInFlags.find((builtInFlag) => builtInFlag.name === flag);

if (inBuiltIn) {
return {
...meta,
// @ts-expect-error this might be overwritten
name: flag,
group: "core",
...inBuiltIn,
configs: meta.configs || [],
};
}
const coreArguments = Object.entries(this.webpack.cli.getArguments()).map(([flag, meta]) => {
const inBuiltIn = builtInFlags.find((builtInFlag) => builtInFlag.name === flag);

if (inBuiltIn) {
return {
...meta,
// @ts-expect-error this might be overwritten
name: flag,
group: "core",
...inBuiltIn,
configs: meta.configs || [],
};
}

return { ...meta, name: flag, group: "core" };
})
: [];
return { ...meta, name: flag, group: "core" };
});

const options: WebpackCLIBuiltInOption[] = ([] as WebpackCLIBuiltInFlag[])
.concat(
builtInFlags.filter(
(builtInFlag) => !coreFlags.find((coreFlag) => builtInFlag.name === coreFlag.name),
(builtInFlag) =>
!coreArguments.find((coreArgument) => builtInFlag.name === coreArgument.name),
),
)
.concat(coreFlags)
.concat(coreArguments)
.map((option): WebpackCLIBuiltInOption => {
(option as WebpackCLIBuiltInOption).helpLevel = minimumHelpFlags.includes(option.name)
? "minimum"
Expand Down Expand Up @@ -1680,6 +1580,8 @@ class WebpackCLI implements IWebpackCLI {
// Default action
this.program.usage("[options]");
this.program.allowUnknownOption(true);

// Basic command for lazy loading other commands
this.program.action(async (options, program: WebpackCLICommand) => {
if (!isInternalActionCalled) {
isInternalActionCalled = true;
Expand Down Expand Up @@ -2090,139 +1992,100 @@ class WebpackCLI implements IWebpackCLI {
}

// Apply options
if (this.webpack.cli) {
const args: Record<string, Argument> = this.getBuiltInOptions()
.filter((flag) => flag.group === "core")
.reduce((accumulator: Record<string, Argument>, flag) => {
accumulator[flag.name] = flag as unknown as Argument;
const args: Record<string, Argument> = this.getBuiltInOptions()
.filter((flag) => flag.group === "core")
.reduce((accumulator: Record<string, Argument>, flag) => {
accumulator[flag.name] = flag as unknown as Argument;
return accumulator;
}, {});

const values: ProcessedArguments = Object.keys(options).reduce(
(accumulator: ProcessedArguments, name) => {
if (name === "argv") {
return accumulator;
}, {});

const values: ProcessedArguments = Object.keys(options).reduce(
(accumulator: ProcessedArguments, name) => {
if (name === "argv") {
return accumulator;
}

const kebabName = this.toKebabCase(name);

if (args[kebabName]) {
accumulator[kebabName] = options[name as keyof typeof options as string];
}

return accumulator;
},
{},
);

const problems: Problem[] | null = this.webpack.cli.processArguments(args, item, values);

if (problems) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const groupBy = (xs: Record<string, any>[], key: string) => {
return xs.reduce((rv, x) => {
(rv[x[key]] = rv[x[key]] || []).push(x);
}

return rv;
}, {});
};
const problemsByPath = groupBy(problems, "path");
const kebabName = this.toKebabCase(name);

for (const path in problemsByPath) {
const problems = problemsByPath[path];
if (args[kebabName]) {
accumulator[kebabName] = options[name as keyof typeof options as string];
}

problems.forEach((problem: Problem) => {
this.logger.error(
`${this.capitalizeFirstLetter(problem.type.replace(/-/g, " "))}${
problem.value ? ` '${problem.value}'` : ""
} for the '--${problem.argument}' option${
problem.index ? ` by index '${problem.index}'` : ""
}`,
);
return accumulator;
},
{},
);

if (problem.expected) {
this.logger.error(`Expected: '${problem.expected}'`);
}
});
}
const problems: Problem[] | null = this.webpack.cli.processArguments(args, item, values);

process.exit(2);
}
if (problems) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const groupBy = (xs: Record<string, any>[], key: string) => {
return xs.reduce((rv, x) => {
(rv[x[key]] = rv[x[key]] || []).push(x);

const isFileSystemCacheOptions = (
config: WebpackConfiguration,
): config is FileSystemCacheOptions => {
return (
Boolean(config.cache) && (config as FileSystemCacheOptions).cache.type === "filesystem"
);
return rv;
}, {});
};
const problemsByPath = groupBy(problems, "path");

// Setup default cache options
if (isFileSystemCacheOptions(item)) {
const configPath = config.path.get(item);
for (const path in problemsByPath) {
const problems = problemsByPath[path];

if (configPath) {
if (!item.cache.buildDependencies) {
item.cache.buildDependencies = {};
}
problems.forEach((problem: Problem) => {
this.logger.error(
`${this.capitalizeFirstLetter(problem.type.replace(/-/g, " "))}${
problem.value ? ` '${problem.value}'` : ""
} for the '--${problem.argument}' option${
problem.index ? ` by index '${problem.index}'` : ""
}`,
);

if (!item.cache.buildDependencies.defaultConfig) {
item.cache.buildDependencies.defaultConfig = [];
if (problem.expected) {
this.logger.error(`Expected: '${problem.expected}'`);
}

if (Array.isArray(configPath)) {
configPath.forEach((oneOfConfigPath) => {
(
item.cache.buildDependencies as NonNullable<
FileSystemCacheOptions["cache"]["buildDependencies"]
>
).defaultConfig.push(oneOfConfigPath);
});
} else {
item.cache.buildDependencies.defaultConfig.push(configPath);
}
}
});
}
}

// Setup legacy logic for webpack@4
// TODO respect `--entry-reset` in th next major release
// TODO drop in the next major release
if (options.entry) {
item.entry = options.entry;
}

if (options.outputPath) {
item.output = { ...item.output, ...{ path: path.resolve(options.outputPath) } };
}

if (options.target) {
item.target = options.target;
process.exit(2);
}

if (typeof options.devtool !== "undefined") {
item.devtool = options.devtool;
}
const isFileSystemCacheOptions = (
config: WebpackConfiguration,
): config is FileSystemCacheOptions => {
return (
Boolean(config.cache) && (config as FileSystemCacheOptions).cache.type === "filesystem"
);
};

if (options.name) {
item.name = options.name;
}
// Setup default cache options
if (isFileSystemCacheOptions(item)) {
const configPath = config.path.get(item);

if (typeof options.stats !== "undefined") {
item.stats = options.stats;
}
if (configPath) {
if (!item.cache.buildDependencies) {
item.cache.buildDependencies = {};
}

if (typeof options.watch !== "undefined") {
item.watch = options.watch;
}
if (!item.cache.buildDependencies.defaultConfig) {
item.cache.buildDependencies.defaultConfig = [];
}

if (typeof options.watchOptionsStdin !== "undefined") {
item.watchOptions = { ...item.watchOptions, ...{ stdin: options.watchOptionsStdin } };
if (Array.isArray(configPath)) {
configPath.forEach((oneOfConfigPath) => {
(
item.cache.buildDependencies as NonNullable<
FileSystemCacheOptions["cache"]["buildDependencies"]
>
).defaultConfig.push(oneOfConfigPath);
});
} else {
item.cache.buildDependencies.defaultConfig.push(configPath);
}
}
}

if (options.mode) {
item.mode = options.mode;
}
// TODO respect `--entry-reset` in th next major release

// Respect `process.env.NODE_ENV`
if (
Expand Down
Loading

0 comments on commit b1af0dc

Please sign in to comment.