Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: the minimum supported webpack version is v5.0.0 #3342

Merged
merged 5 commits into from Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
326 changes: 92 additions & 234 deletions packages/webpack-cli/src/webpack-cli.ts
Expand Up @@ -856,110 +856,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 +870,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 +1575,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 +1987,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);
const kebabName = this.toKebabCase(name);

return rv;
}, {});
};
const problemsByPath = groupBy(problems, "path");
if (args[kebabName]) {
accumulator[kebabName] = options[name as keyof typeof options as string];
}

for (const path in problemsByPath) {
const problems = problemsByPath[path];
return accumulator;
},
{},
);

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}'` : ""
}`,
);
const problems: Problem[] | null = this.webpack.cli.processArguments(args, item, values);

if (problem.expected) {
this.logger.error(`Expected: '${problem.expected}'`);
}
});
}
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);

process.exit(2);
}

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);

if (configPath) {
if (!item.cache.buildDependencies) {
item.cache.buildDependencies = {};
}
for (const path in problemsByPath) {
const problems = problemsByPath[path];

if (!item.cache.buildDependencies.defaultConfig) {
item.cache.buildDependencies.defaultConfig = [];
}
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 (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 (problem.expected) {
this.logger.error(`Expected: '${problem.expected}'`);
}
}
});
}
}

// 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