From b5d7593e8ca25c02b553cd6a54112acd65ebeff3 Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Mon, 23 Feb 2026 20:40:12 +0300 Subject: [PATCH 1/3] refactor: move serve into core --- packages/webpack-cli/src/webpack-cli.ts | 245 +++++++++++++++++- smoketests/index.js | 1 - .../missing-command-packages/serve.test.js | 23 -- tsconfig.json | 3 - 4 files changed, 238 insertions(+), 34 deletions(-) delete mode 100644 smoketests/missing-command-packages/serve.test.js diff --git a/packages/webpack-cli/src/webpack-cli.ts b/packages/webpack-cli/src/webpack-cli.ts index 288dc7e4927..24cf15b5bf3 100644 --- a/packages/webpack-cli/src/webpack-cli.ts +++ b/packages/webpack-cli/src/webpack-cli.ts @@ -1145,6 +1145,14 @@ class WebpackCLI implements IWebpackCLI { usage: "[entries...] [options]", dependencies: [WEBPACK_PACKAGE], }, + serve: { + rawName: "serve", + name: "serve [entries...]", + alias: ["server", "s"], + description: "Run the webpack dev server and watch for source file changes while serving.", + usage: "[entries...] [options]", + dependencies: [WEBPACK_PACKAGE, WEBPACK_DEV_SERVER_PACKAGE], + }, version: { rawName: "version", name: "version", @@ -1166,13 +1174,6 @@ class WebpackCLI implements IWebpackCLI { alias: "h", description: "Display help for commands and options.", }, - serve: { - rawName: "serve", - external: true, - name: "serve [entries...]", - alias: ["server", "s"], - pkg: "@webpack-cli/serve", - }, configtest: { rawName: "configtest", name: "configtest [config-path]", @@ -1229,6 +1230,236 @@ class WebpackCLI implements IWebpackCLI { await this.runWebpack(options, isWatchCommandUsed); }, ); + } else if (this.#isCommand(commandName, WebpackCLI.#commands.serve)) { + const loadDevServerOptions = () => { + const devServer = require(WEBPACK_DEV_SERVER_PACKAGE); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const options: Record = this.webpack.cli.getArguments(devServer.schema); + + // New options format + // { flag1: {}, flag2: {} } + return Object.keys(options).map((key) => { + options[key].name = key; + + return options[key]; + }); + }; + + this.makeCommand( + WebpackCLI.#commands.serve, + async () => { + let devServerFlags = []; + + this.webpack = await this.loadWebpack(); + + try { + devServerFlags = loadDevServerOptions(); + } catch (error) { + this.logger.error( + `You need to install 'webpack-dev-server' for running 'webpack serve'.\n${error}`, + ); + process.exit(2); + } + + const builtInOptions = this.getBuiltInOptions(); + + return [...builtInOptions, ...devServerFlags]; + }, + async (entries: string[], options) => { + const builtInOptions = this.getBuiltInOptions(); + let devServerFlags = []; + + try { + devServerFlags = loadDevServerOptions(); + } catch { + // Nothing, to prevent future updates + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const webpackCLIOptions: Record = {}; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const devServerCLIOptions: Record = {}; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const processors: ((opts: Record) => void)[] = []; + + for (const optionName in options) { + const kebabedOption = this.toKebabCase(optionName); + const isBuiltInOption = builtInOptions.find( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (builtInOption: any) => builtInOption.name === kebabedOption, + ); + + if (isBuiltInOption) { + webpackCLIOptions[optionName] = options[optionName]; + } else { + const needToProcess = devServerFlags.find( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (devServerOption: any) => + devServerOption.name === kebabedOption && devServerOption.processor, + ); + + if (needToProcess) { + processors.push(needToProcess.processor); + } + + devServerCLIOptions[optionName] = options[optionName]; + } + } + + for (const processor of processors) { + processor(devServerCLIOptions); + } + + if (entries.length > 0) { + webpackCLIOptions.entry = [...entries, ...(webpackCLIOptions.entry || [])]; + } + + webpackCLIOptions.argv = { + ...options, + env: { WEBPACK_SERVE: true, ...options.env }, + }; + + webpackCLIOptions.isWatchingLikeCommand = true; + + const compiler = await this.createCompiler(webpackCLIOptions); + + if (!compiler) { + return; + } + + const servers: (typeof DevServer)[] = []; + + if (this.needWatchStdin(compiler)) { + process.stdin.on("end", () => { + Promise.all(servers.map((server) => server.stop())).then(() => { + process.exit(0); + }); + }); + process.stdin.resume(); + } + + const DevServer = require(WEBPACK_DEV_SERVER_PACKAGE); + + try { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + require(`${WEBPACK_DEV_SERVER_PACKAGE}/package.json`).version; + } catch (err) { + this.logger.error( + `You need to install 'webpack-dev-server' for running 'webpack serve'.\n${err}`, + ); + process.exit(2); + } + + const compilers = this.isMultipleCompiler(compiler) ? compiler.compilers : [compiler]; + const possibleCompilers = compilers.filter( + (compiler: Compiler) => compiler.options.devServer, + ); + const compilersForDevServer = + possibleCompilers.length > 0 ? possibleCompilers : [compilers[0]]; + const usedPorts: number[] = []; + + for (const compilerForDevServer of compilersForDevServer) { + if (compilerForDevServer.options.devServer === false) { + continue; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const args = devServerFlags.reduce((accumulator: Record, flag: any) => { + accumulator[flag.name] = flag; + + return accumulator; + }, {}); + const values = Object.keys(devServerCLIOptions).reduce( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (accumulator: Record, name: string) => { + const kebabName = this.toKebabCase(name); + + if (args[kebabName]) { + accumulator[kebabName] = options[name]; + } + + return accumulator; + }, + {}, + ); + const result = { ...compilerForDevServer.options.devServer }; + const problems = this.webpack.cli.processArguments(args, result, values); + + if (problems) { + const groupBy = >( + xs: Problem[], + key: K, + ) => + xs.reduce((rv: Record, problem: Problem) => { + const path = problem[key]; + + (rv[path] ||= []).push(problem); + + return rv; + }, {}); + + const problemsByPath = groupBy<"path">(problems, "path"); + + for (const path in problemsByPath) { + const problems = problemsByPath[path]; + + for (const problem of problems) { + this.logger.error( + `${this.capitalizeFirstLetter(problem.type.replace("-", " "))}${ + problem.value ? ` '${problem.value}'` : "" + } for the '--${problem.argument}' option${ + problem.index ? ` by index '${problem.index}'` : "" + }`, + ); + + if (problem.expected) { + this.logger.error(`Expected: '${problem.expected}'`); + } + } + } + + process.exit(2); + } + + const devServerOptions: WebpackDevServerOptions = result as WebpackDevServerOptions; + + if (devServerOptions.port) { + const portNumber = Number(devServerOptions.port); + + if (usedPorts.includes(portNumber)) { + throw new Error( + "Unique ports must be specified for each devServer option in your webpack configuration. Alternatively, run only 1 devServer config using the --config-name flag to specify your desired config.", + ); + } + + usedPorts.push(portNumber); + } + + try { + const server = new DevServer(devServerOptions, compiler); + + await server.start(); + + servers.push(server); + } catch (error) { + if (this.isValidationError(error as Error)) { + this.logger.error((error as Error).message); + } else { + this.logger.error(error); + } + + process.exit(2); + } + } + + if (servers.length === 0) { + this.logger.error("No dev server configurations to run"); + process.exit(2); + } + }, + ); } else if (this.#isCommand(commandName, WebpackCLI.#commands.help)) { this.makeCommand(WebpackCLI.#commands.help, [], () => { // Stub for the `help` command diff --git a/smoketests/index.js b/smoketests/index.js index f178f87ad24..24c1fea851e 100644 --- a/smoketests/index.js +++ b/smoketests/index.js @@ -2,7 +2,6 @@ const tests = [ require("./missing-packages/webpack-dev-server.test"), require("./missing-packages/webpack.test"), require("./missing-packages/webpack-bundle-analyzer.test"), - require("./missing-command-packages/serve.test"), ]; // eslint-disable-next-line unicorn/prefer-top-level-await diff --git a/smoketests/missing-command-packages/serve.test.js b/smoketests/missing-command-packages/serve.test.js deleted file mode 100644 index 3e8414c4e37..00000000000 --- a/smoketests/missing-command-packages/serve.test.js +++ /dev/null @@ -1,23 +0,0 @@ -"use strict"; - -const { runTest, runTestWithHelp } = require("../helpers"); - -const packageName = "serve"; -const isSubPackage = true; - -const serveTest = () => { - const args = ["serve"]; - const logMessage = "For using this command you need to install: '@webpack-cli/serve' package"; - - return runTest(packageName, args, logMessage, isSubPackage); -}; - -const serveTestWithHelp = () => { - const args = ["help", "serve"]; - const logMessage = "For using 'serve' command you need to install '@webpack-cli/serve' package"; - - return runTestWithHelp(packageName, args, logMessage, isSubPackage); -}; - -module.exports.name = "Missing @webpack-cli/serve"; -module.exports.run = [serveTest, serveTestWithHelp]; diff --git a/tsconfig.json b/tsconfig.json index b385f7cf35e..a07a3706fc7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,9 +21,6 @@ "declaration": true }, "references": [ - { - "path": "packages/serve" - }, { "path": "packages/webpack-cli" }, From 054162c3fa48e1d681fdca5f714b2ff3c0dc386a Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Mon, 23 Feb 2026 20:42:05 +0300 Subject: [PATCH 2/3] refactor: move serve into core --- packages/serve/CHANGELOG.md | 198 --------------------------- packages/serve/README.md | 32 ----- packages/serve/package.json | 34 ----- packages/serve/src/index.ts | 251 ----------------------------------- packages/serve/tsconfig.json | 13 -- 5 files changed, 528 deletions(-) delete mode 100644 packages/serve/CHANGELOG.md delete mode 100644 packages/serve/README.md delete mode 100644 packages/serve/package.json delete mode 100644 packages/serve/src/index.ts delete mode 100644 packages/serve/tsconfig.json diff --git a/packages/serve/CHANGELOG.md b/packages/serve/CHANGELOG.md deleted file mode 100644 index f9ca9461902..00000000000 --- a/packages/serve/CHANGELOG.md +++ /dev/null @@ -1,198 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [3.0.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@3.0.0...@webpack-cli/serve@3.0.1) (2024-12-20) - -### Bug Fixes - -- update peer dependencies ([#4356](https://github.com/webpack/webpack-cli/issues/4356)) ([7a7e5d9](https://github.com/webpack/webpack-cli/commit/7a7e5d9f4bd796c7d1089db228b9581e97cc897e)) - -# [3.0.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@2.0.5...@webpack-cli/serve@3.0.0) (2024-12-19) - -### Bug Fixes - -- no serve when dev-server is false ([#2947](https://github.com/webpack/webpack-cli/issues/2947)) ([a93e860](https://github.com/webpack/webpack-cli/commit/a93e8603a4c2639916152a013afed04c0e8f3a35)) - -## [2.0.5](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@2.0.4...@webpack-cli/serve@2.0.5) (2023-06-04) - -### Bug Fixes - -- improve help for some flags ([f468614](https://github.com/webpack/webpack-cli/commit/f4686141681cfcbc74d57e69a732e176decff225)) - -## [2.0.4](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@2.0.3...@webpack-cli/serve@2.0.4) (2023-05-09) - -### Bug Fixes - -- false positive warning when `--watch` used ([#3783](https://github.com/webpack/webpack-cli/issues/3783)) ([c0436ba](https://github.com/webpack/webpack-cli/commit/c0436baca2da7a8ce9e53bbbe960dd1951fe6404)) - -## [2.0.3](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@2.0.2...@webpack-cli/serve@2.0.3) (2023-05-07) - -### Performance Improvements - -- simplify logic, reduce extra loops and perf ([#3767](https://github.com/webpack/webpack-cli/issues/3767)) ([6afe1d3](https://github.com/webpack/webpack-cli/commit/6afe1d3be41e191aa7c4865919d092d952e98605)) - -## [2.0.2](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@2.0.1...@webpack-cli/serve@2.0.2) (2023-04-21) - -**Note:** Version bump only for package @webpack-cli/serve - -## [2.0.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@2.0.0...@webpack-cli/serve@2.0.1) (2022-12-05) - -**Note:** Version bump only for package @webpack-cli/serve - -# [2.0.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.7.0...@webpack-cli/serve@2.0.0) (2022-11-17) - -### BREAKING CHANGES - -- the minimum supported webpack version is v5.0.0 (#3342) ([b1af0dc](https://github.com/webpack/webpack-cli/commit/b1af0dc7ebcdf746bc37889e4c1f978c65acc4a5)), closes [#3342](https://github.com/webpack/webpack-cli/issues/3342) -- webpack-cli no longer supports webpack v4, the minimum supported version is webpack v5.0.0 -- webpack-cli no longer supports webpack-dev-server v3, the minimum supported version is webpack-dev-server v4.0.0 - -# [1.7.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.6.1...@webpack-cli/serve@1.7.0) (2022-06-13) - -### Features - -- added types ([8ec1375](https://github.com/webpack/webpack-cli/commit/8ec1375092a6f9676e82fa4231dd88b1016c2302)) - -## [1.6.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.6.0...@webpack-cli/serve@1.6.1) (2022-01-24) - -**Note:** Version bump only for package @webpack-cli/serve - -# [1.6.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.5.2...@webpack-cli/serve@1.6.0) (2021-10-06) - -### Bug Fixes - -- allow falsy values for `port` option ([#2962](https://github.com/webpack/webpack-cli/issues/2962)) ([da135dd](https://github.com/webpack/webpack-cli/commit/da135dd717e88b6aa9a0559c1e4e8acb4ee8f3c1)) - -### Features - -- allow to run commands without webpack installation where it is unnecessary ([#2907](https://github.com/webpack/webpack-cli/issues/2907)) ([603041d](https://github.com/webpack/webpack-cli/commit/603041d7e6a9b764bd79d1a8effd22a3e0f019cb)) - -## [1.5.2](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.5.1...@webpack-cli/serve@1.5.2) (2021-08-15) - -### Bug Fixes - -- ci for dev server next ([#2841](https://github.com/webpack/webpack-cli/issues/2841)) ([54d34b7](https://github.com/webpack/webpack-cli/commit/54d34b723cbeaf8cc13cff45398530be1db911e4)) -- respect dev server CLI options for multi compiler mode ([de48278](https://github.com/webpack/webpack-cli/commit/de482784a4f8cbb9eacbbe1c6b6f3c62ef60567a)) -- using new dev server API for v4 ([#2886](https://github.com/webpack/webpack-cli/issues/2886)) ([f66d01f](https://github.com/webpack/webpack-cli/commit/f66d01f0e382b0b3ffc753ac7549eb252e19e26c)) - -## [1.5.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.5.0...@webpack-cli/serve@1.5.1) (2021-06-07) - -### Bug Fixes - -- broken serve with new CLI API ([#2770](https://github.com/webpack/webpack-cli/issues/2770)) ([2d7ab35](https://github.com/webpack/webpack-cli/commit/2d7ab3549c429193b4ed5fbc6174153c847e0330)) - -# [1.5.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.4.0...@webpack-cli/serve@1.5.0) (2021-06-07) - -### Bug Fixes - -- prettier config ([#2719](https://github.com/webpack/webpack-cli/issues/2719)) ([181295f](https://github.com/webpack/webpack-cli/commit/181295fb1b1973c201c221813562219d85b845ae)) - -### Features - -- new CLI options API for serve ([#2754](https://github.com/webpack/webpack-cli/issues/2754)) ([bb7c9d3](https://github.com/webpack/webpack-cli/commit/bb7c9d3c9b0dca11242e2febcd41805c063e1317)) - -# [1.4.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.3.1...@webpack-cli/serve@1.4.0) (2021-05-06) - -### Bug Fixes - -- avoid unnecessary searching port ([#2648](https://github.com/webpack/webpack-cli/issues/2648)) ([5063ed7](https://github.com/webpack/webpack-cli/commit/5063ed7970cd12fd042308edfccca8dbf249f0fc)) -- **serve:** do not set port client port directly ([#2624](https://github.com/webpack/webpack-cli/issues/2624)) ([ec18b8e](https://github.com/webpack/webpack-cli/commit/ec18b8e478ff1a5f8d85bbddc599001dfd69eba3)) - -### Features - -- add `server` alias for `serve` command ([#2631](https://github.com/webpack/webpack-cli/issues/2631)) ([c9ee947](https://github.com/webpack/webpack-cli/commit/c9ee947618c06447bc1f949e4d401e63f737f38d)) - -## [1.3.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.3.0...@webpack-cli/serve@1.3.1) (2021-03-27) - -**Note:** Version bump only for package @webpack-cli/serve - -# [1.3.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.2.2...@webpack-cli/serve@1.3.0) (2021-02-02) - -### Bug Fixes - -- avoid deprecation message ([9d6dbda](https://github.com/webpack/webpack-cli/commit/9d6dbda93da167a1aaad03f599105a4fe7849dc3)) -- error message on invalid plugin options ([#2380](https://github.com/webpack/webpack-cli/issues/2380)) ([f9ce1d3](https://github.com/webpack/webpack-cli/commit/f9ce1d30b83bf0e0b4d91498d012c13c208e6e67)) - -### Features - -- entries syntax ([#2369](https://github.com/webpack/webpack-cli/issues/2369)) ([6b31614](https://github.com/webpack/webpack-cli/commit/6b3161479578f572f803f579c7e71073eb797184)) - -## [1.2.2](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.2.1...@webpack-cli/serve@1.2.2) (2021-01-19) - -### Bug Fixes - -- pass all `argv` to configurations when `serve` command used ([#2345](https://github.com/webpack/webpack-cli/issues/2345)) ([5070b9b](https://github.com/webpack/webpack-cli/commit/5070b9bcbd5bdac00088d0c21486ad181a4df000)) -- respect `--stats`, `--color` and `--no-color` option for serve c… ([#2312](https://github.com/webpack/webpack-cli/issues/2312)) ([73d3fec](https://github.com/webpack/webpack-cli/commit/73d3feced18b4e3708f958707326a6642a594cf2)) - -## [1.2.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.2.0...@webpack-cli/serve@1.2.1) (2020-12-31) - -### Bug Fixes - -- do not apply HotModuleReplacement plugin twice ([#2269](https://github.com/webpack/webpack-cli/issues/2269)) ([bb16d44](https://github.com/webpack/webpack-cli/commit/bb16d4481414a5f3c0cbeb18af690084b2ae4215)) -- respect the `output.publicPath` option for the `serve`command ([#2271](https://github.com/webpack/webpack-cli/issues/2271)) ([a3092ef](https://github.com/webpack/webpack-cli/commit/a3092ef2b51ece30221f7dd7b30a686626c1fd7a)) -- the `--help` option is working without `webpack-dev-server` ([#2267](https://github.com/webpack/webpack-cli/issues/2267)) ([1dae54d](https://github.com/webpack/webpack-cli/commit/1dae54da94d3220437b9257efe512447023de1d3)) -- the `--progress` option with the `serve` command ([#2265](https://github.com/webpack/webpack-cli/issues/2265)) ([952a188](https://github.com/webpack/webpack-cli/commit/952a1883b1a18c4fb38e8eb7bbbdb2aefc7942f4)) - -# [1.2.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.1.0...@webpack-cli/serve@1.2.0) (2020-12-25) - -### Bug Fixes - -- respect `--watch-options-stdin` ([2d1e001](https://github.com/webpack/webpack-cli/commit/2d1e001e7f4f560c2b36607bd1b29dfe2aa32066)) -- do not default host in webpack-dev-server v4 ([#2141](https://github.com/webpack/webpack-cli/issues/2141)) ([dbbe4d4](https://github.com/webpack/webpack-cli/commit/dbbe4d4bc93ff9147ba43fae2d2352fa3583558d)) -- do not default port in webpack-dev-server v4 ([#2126](https://github.com/webpack/webpack-cli/issues/2126)) ([cda3047](https://github.com/webpack/webpack-cli/commit/cda30471f51db4631a0f54b852c553de270f7f64)) -- set client port when using default port ([#2147](https://github.com/webpack/webpack-cli/issues/2147)) ([4b97348](https://github.com/webpack/webpack-cli/commit/4b973488a42c4e12d86e0324a4c7051d1380a6fa)) -- catch dev server import during webpack serve ([#2070](https://github.com/webpack/webpack-cli/issues/2070)) ([70bf770](https://github.com/webpack/webpack-cli/commit/70bf7708c21dffe6521f1800b9dec2a62d21cfe2)) -- respect `--color`/`--no-color` options ([#2042](https://github.com/webpack/webpack-cli/issues/2042)) ([09bd812](https://github.com/webpack/webpack-cli/commit/09bd8126e95c9675b1f6862451f629cd4c439adb)) - -# [1.1.0](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.0.1...@webpack-cli/serve@1.1.0) (2020-11-04) - -### Bug Fixes - -- resolve dev server hot options correctly ([#2022](https://github.com/webpack/webpack-cli/issues/2022)) ([7c5a2ba](https://github.com/webpack/webpack-cli/commit/7c5a2bae49625ee4982d7478b7e741968731cea2)) - -### Features - -- add WEBPACK_SERVE environment variable ([#2027](https://github.com/webpack/webpack-cli/issues/2027)) ([ea369a9](https://github.com/webpack/webpack-cli/commit/ea369a98ea5ec366b688caebcb1276d9fbe0c651)) -- export utils from core for other packages ([#2011](https://github.com/webpack/webpack-cli/issues/2011)) ([3004549](https://github.com/webpack/webpack-cli/commit/3004549c06b3fe00708d8e1eecf42419e0f72f66)) - -## [1.0.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.0.1-rc.1...@webpack-cli/serve@1.0.1) (2020-10-10) - -**Note:** Version bump only for package @webpack-cli/serve - -## [1.0.1-rc.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.0.1-alpha.5...@webpack-cli/serve@1.0.1-rc.1) (2020-10-06) - -### Bug Fixes - -- peer dependencies for `webpack serve` ([#1317](https://github.com/webpack/webpack-cli/issues/1317)) ([f8ec203](https://github.com/webpack/webpack-cli/commit/f8ec20382702450134032a65403894573b04be8d)) -- **packages:** make packages have correct main paths to index ([#1366](https://github.com/webpack/webpack-cli/issues/1366)) ([5dd7bd6](https://github.com/webpack/webpack-cli/commit/5dd7bd62046568481996e48328b15a335557f8ae)) -- **serve:** merge CLI and devServer options correctly ([#1649](https://github.com/webpack/webpack-cli/issues/1649)) ([2cdf5ce](https://github.com/webpack/webpack-cli/commit/2cdf5ce159f63ac65b33f4aca4c82fa1e959fef5)) -- **serve:** supplying help or version as an arg should throw error ([#1694](https://github.com/webpack/webpack-cli/issues/1694)) ([6eb7883](https://github.com/webpack/webpack-cli/commit/6eb78833f910135ca798c0c28f8d236ef234a76c)) - -### Features - -- allow multiple targets ([#1799](https://github.com/webpack/webpack-cli/issues/1799)) ([1724ddb](https://github.com/webpack/webpack-cli/commit/1724ddb9067d5c5ba2654d4e5473ee9de5610825)) -- serve integration ([#1712](https://github.com/webpack/webpack-cli/issues/1712)) ([d3e2936](https://github.com/webpack/webpack-cli/commit/d3e29368c40ee47e4f7a07c41281714645e20ea7)) - -## [1.0.1-alpha.5](https://github.com/ematipico/webpack-cli/compare/@webpack-cli/serve@1.0.1-alpha.4...@webpack-cli/serve@1.0.1-alpha.5) (2020-03-02) - -**Note:** Version bump only for package @webpack-cli/serve - -## [1.0.1-alpha.4](https://github.com/ematipico/webpack-cli/compare/@webpack-cli/serve@1.0.1-alpha.3...@webpack-cli/serve@1.0.1-alpha.4) (2020-02-29) - -**Note:** Version bump only for package @webpack-cli/serve - -## [1.0.1-alpha.3](https://github.com/ematipico/webpack-cli/compare/@webpack-cli/serve@1.0.1-alpha.2...@webpack-cli/serve@1.0.1-alpha.3) (2020-02-23) - -**Note:** Version bump only for package @webpack-cli/serve - -## [1.0.1-alpha.2](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.0.1-alpha.1...@webpack-cli/serve@1.0.1-alpha.2) (2020-02-23) - -**Note:** Version bump only for package @webpack-cli/serve - -## [1.0.1-alpha.1](https://github.com/webpack/webpack-cli/compare/@webpack-cli/serve@1.0.1-alpha.0...@webpack-cli/serve@1.0.1-alpha.1) (2020-02-23) - -### Bug Fixes - -- **init:** fix webpack config scaffold ([#1231](https://github.com/webpack/webpack-cli/issues/1231)) ([2dc495a](https://github.com/webpack/webpack-cli/commit/2dc495a8d050d28478c6c2533d7839e9ff78d76c)), closes [#1230](https://github.com/webpack/webpack-cli/issues/1230) diff --git a/packages/serve/README.md b/packages/serve/README.md deleted file mode 100644 index 6f1d4807e5f..00000000000 --- a/packages/serve/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# webpack-cli serve - -[![NPM Downloads][downloads]][downloads-url] - -> **Note** -> -> This package is used by webpack-cli under-the-hood and is not intended for installation - -## Description - -This package contains the logic to run [webpack-dev-server](https://github.com/webpack/webpack-dev-server) to serve your webpack app and provide live reloading. - -## Installation - -```bash -npm i -D webpack-cli @webpack-cli/serve -``` - -## Usage - -### CLI (via `webpack-cli`) - -```bash -npx webpack-cli serve -``` - -### Options - -Checkout [`SERVE-OPTIONS-v4.md`](https://github.com/webpack/webpack-cli/blob/main/SERVE-OPTIONS-v4.md) or [`SERVE-OPTIONS-v5.md`](https://github.com/webpack/webpack-cli/blob/main/SERVE-OPTIONS-v5.md) to see list of all available options for `serve` command for respective [`webpack-dev-server`](https://github.com/webpack/webpack-dev-server) version. - -[downloads]: https://img.shields.io/npm/dm/@webpack-cli/serve.svg -[downloads-url]: https://www.npmjs.com/package/@webpack-cli/serve diff --git a/packages/serve/package.json b/packages/serve/package.json deleted file mode 100644 index dcb2c407ad4..00000000000 --- a/packages/serve/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@webpack-cli/serve", - "version": "3.0.1", - "description": "", - "keywords": [], - "homepage": "https://github.com/webpack/webpack-cli/tree/main/packages/serve", - "repository": { - "type": "git", - "url": "https://github.com/webpack/webpack-cli.git" - }, - "license": "MIT", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "files": [ - "lib" - ], - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x", - "webpack-dev-server": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - }, - "engines": { - "node": ">=18.12.0" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "fb50f766851f500ca12867a2aa9de81fa6e368f9" -} diff --git a/packages/serve/src/index.ts b/packages/serve/src/index.ts deleted file mode 100644 index 9b8d8268e14..00000000000 --- a/packages/serve/src/index.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { type Compiler, type cli } from "webpack"; -import { type IWebpackCLI, type StringsKeys, type WebpackDevServerOptions } from "webpack-cli"; - -const WEBPACK_PACKAGE = process.env.WEBPACK_PACKAGE || "webpack"; -const WEBPACK_DEV_SERVER_PACKAGE = process.env.WEBPACK_DEV_SERVER_PACKAGE || "webpack-dev-server"; - -type Problem = NonNullable>[0]; - -class ServeCommand { - async apply(cli: IWebpackCLI): Promise { - const loadDevServerOptions = () => { - const devServer = require(WEBPACK_DEV_SERVER_PACKAGE); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const options: Record = cli.webpack.cli.getArguments(devServer.schema); - // New options format - // { flag1: {}, flag2: {} } - return Object.keys(options).map((key) => { - options[key].name = key; - - return options[key]; - }); - }; - - await cli.makeCommand( - { - rawName: "serve", - name: "serve [entries...]", - alias: ["server", "s"], - description: "Run the webpack dev server and watch for source file changes while serving.", - usage: "[entries...] [options]", - pkg: "@webpack-cli/serve", - dependencies: [WEBPACK_PACKAGE, WEBPACK_DEV_SERVER_PACKAGE], - }, - async () => { - let devServerFlags = []; - - cli.webpack = await cli.loadWebpack(); - - try { - devServerFlags = loadDevServerOptions(); - } catch (error) { - cli.logger.error( - `You need to install 'webpack-dev-server' for running 'webpack serve'.\n${error}`, - ); - process.exit(2); - } - - const builtInOptions = cli.getBuiltInOptions(); - - return [...builtInOptions, ...devServerFlags]; - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - async (entries: string[], options: any) => { - const builtInOptions = cli.getBuiltInOptions(); - let devServerFlags = []; - - try { - devServerFlags = loadDevServerOptions(); - } catch { - // Nothing, to prevent future updates - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const webpackCLIOptions: Record = {}; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const devServerCLIOptions: Record = {}; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const processors: ((opts: Record) => void)[] = []; - - for (const optionName in options) { - const kebabedOption = cli.toKebabCase(optionName); - const isBuiltInOption = builtInOptions.find( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (builtInOption: any) => builtInOption.name === kebabedOption, - ); - - if (isBuiltInOption) { - webpackCLIOptions[optionName] = options[optionName]; - } else { - const needToProcess = devServerFlags.find( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (devServerOption: any) => - devServerOption.name === kebabedOption && devServerOption.processor, - ); - - if (needToProcess) { - processors.push(needToProcess.processor); - } - - devServerCLIOptions[optionName] = options[optionName]; - } - } - - for (const processor of processors) { - processor(devServerCLIOptions); - } - - if (entries.length > 0) { - webpackCLIOptions.entry = [...entries, ...(webpackCLIOptions.entry || [])]; - } - - webpackCLIOptions.argv = { - ...options, - env: { WEBPACK_SERVE: true, ...options.env }, - }; - - webpackCLIOptions.isWatchingLikeCommand = true; - - const compiler = await cli.createCompiler(webpackCLIOptions); - - if (!compiler) { - return; - } - - const servers: (typeof DevServer)[] = []; - - if (cli.needWatchStdin(compiler)) { - process.stdin.on("end", () => { - Promise.all(servers.map((server) => server.stop())).then(() => { - process.exit(0); - }); - }); - process.stdin.resume(); - } - - const DevServer = require(WEBPACK_DEV_SERVER_PACKAGE); - - try { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - require(`${WEBPACK_DEV_SERVER_PACKAGE}/package.json`).version; - } catch (err) { - cli.logger.error( - `You need to install 'webpack-dev-server' for running 'webpack serve'.\n${err}`, - ); - process.exit(2); - } - - const compilers = cli.isMultipleCompiler(compiler) ? compiler.compilers : [compiler]; - const possibleCompilers = compilers.filter( - (compiler: Compiler) => compiler.options.devServer, - ); - const compilersForDevServer = - possibleCompilers.length > 0 ? possibleCompilers : [compilers[0]]; - const usedPorts: number[] = []; - - for (const compilerForDevServer of compilersForDevServer) { - if (compilerForDevServer.options.devServer === false) { - continue; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const args = devServerFlags.reduce((accumulator: Record, flag: any) => { - accumulator[flag.name] = flag; - - return accumulator; - }, {}); - const values = Object.keys(devServerCLIOptions).reduce( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (accumulator: Record, name: string) => { - const kebabName = cli.toKebabCase(name); - - if (args[kebabName]) { - accumulator[kebabName] = options[name]; - } - - return accumulator; - }, - {}, - ); - const result = { ...compilerForDevServer.options.devServer }; - const problems = cli.webpack.cli.processArguments(args, result, values); - - if (problems) { - const groupBy = >( - xs: Problem[], - key: K, - ) => - xs.reduce((rv: Record, problem: Problem) => { - const path = problem[key]; - - (rv[path] ||= []).push(problem); - - return rv; - }, {}); - - const problemsByPath = groupBy<"path">(problems, "path"); - - for (const path in problemsByPath) { - const problems = problemsByPath[path]; - - for (const problem of problems) { - cli.logger.error( - `${cli.capitalizeFirstLetter(problem.type.replace("-", " "))}${ - problem.value ? ` '${problem.value}'` : "" - } for the '--${problem.argument}' option${ - problem.index ? ` by index '${problem.index}'` : "" - }`, - ); - - if (problem.expected) { - cli.logger.error(`Expected: '${problem.expected}'`); - } - } - } - - process.exit(2); - } - - const devServerOptions: WebpackDevServerOptions = result as WebpackDevServerOptions; - - if (devServerOptions.port) { - const portNumber = Number(devServerOptions.port); - - if (usedPorts.includes(portNumber)) { - throw new Error( - "Unique ports must be specified for each devServer option in your webpack configuration. Alternatively, run only 1 devServer config using the --config-name flag to specify your desired config.", - ); - } - - usedPorts.push(portNumber); - } - - try { - const server = new DevServer(devServerOptions, compiler); - - await server.start(); - - servers.push(server); - } catch (error) { - if (cli.isValidationError(error as Error)) { - cli.logger.error((error as Error).message); - } else { - cli.logger.error(error); - } - - process.exit(2); - } - } - - if (servers.length === 0) { - cli.logger.error("No dev server configurations to run"); - process.exit(2); - } - }, - ); - } -} - -export default ServeCommand; diff --git a/packages/serve/tsconfig.json b/packages/serve/tsconfig.json deleted file mode 100644 index 1c6d02ef88c..00000000000 --- a/packages/serve/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./lib", - "rootDir": "./src" - }, - "include": ["./src"], - "references": [ - { - "path": "../webpack-cli" - } - ] -} From 23e9ed1a5c5aec04f16b1460e064721cdce7af5c Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Mon, 23 Feb 2026 21:44:41 +0300 Subject: [PATCH 3/3] refactor: code --- packages/webpack-cli/src/webpack-cli.ts | 44 +++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/webpack-cli/src/webpack-cli.ts b/packages/webpack-cli/src/webpack-cli.ts index 24cf15b5bf3..189ec5d098c 100644 --- a/packages/webpack-cli/src/webpack-cli.ts +++ b/packages/webpack-cli/src/webpack-cli.ts @@ -1246,7 +1246,7 @@ class WebpackCLI implements IWebpackCLI { }); }; - this.makeCommand( + await this.makeCommand( WebpackCLI.#commands.serve, async () => { let devServerFlags = []; @@ -1287,16 +1287,14 @@ class WebpackCLI implements IWebpackCLI { for (const optionName in options) { const kebabedOption = this.toKebabCase(optionName); const isBuiltInOption = builtInOptions.find( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (builtInOption: any) => builtInOption.name === kebabedOption, + (builtInOption) => builtInOption.name === kebabedOption, ); if (isBuiltInOption) { webpackCLIOptions[optionName] = options[optionName]; } else { const needToProcess = devServerFlags.find( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (devServerOption: any) => + (devServerOption) => devServerOption.name === kebabedOption && devServerOption.processor, ); @@ -1353,9 +1351,7 @@ class WebpackCLI implements IWebpackCLI { } const compilers = this.isMultipleCompiler(compiler) ? compiler.compilers : [compiler]; - const possibleCompilers = compilers.filter( - (compiler: Compiler) => compiler.options.devServer, - ); + const possibleCompilers = compilers.filter((compiler) => compiler.options.devServer); const compilersForDevServer = possibleCompilers.length > 0 ? possibleCompilers : [compilers[0]]; const usedPorts: number[] = []; @@ -1365,15 +1361,17 @@ class WebpackCLI implements IWebpackCLI { continue; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const args = devServerFlags.reduce((accumulator: Record, flag: any) => { - accumulator[flag.name] = flag; + const args = devServerFlags.reduce( + (accumulator, flag) => { + accumulator[flag.name] = flag; - return accumulator; - }, {}); - const values = Object.keys(devServerCLIOptions).reduce( + return accumulator; + }, // eslint-disable-next-line @typescript-eslint/no-explicit-any - (accumulator: Record, name: string) => { + {} as Record, + ); + const values = Object.keys(devServerCLIOptions).reduce( + (accumulator, name) => { const kebabName = this.toKebabCase(name); if (args[kebabName]) { @@ -1382,7 +1380,8 @@ class WebpackCLI implements IWebpackCLI { return accumulator; }, - {}, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + {} as Record, ); const result = { ...compilerForDevServer.options.devServer }; const problems = this.webpack.cli.processArguments(args, result, values); @@ -1392,13 +1391,16 @@ class WebpackCLI implements IWebpackCLI { xs: Problem[], key: K, ) => - xs.reduce((rv: Record, problem: Problem) => { - const path = problem[key]; + xs.reduce( + (rv: Record, problem: Problem) => { + const path = problem[key]; - (rv[path] ||= []).push(problem); + (rv[path] ||= []).push(problem); - return rv; - }, {}); + return rv; + }, + {} as Record, + ); const problemsByPath = groupBy<"path">(problems, "path");