175 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| Object.defineProperty(exports, "__esModule", { value: true });
 | |
| const WEBPACK_PACKAGE = process.env.WEBPACK_PACKAGE || "webpack";
 | |
| const WEBPACK_DEV_SERVER_PACKAGE = process.env.WEBPACK_DEV_SERVER_PACKAGE || "webpack-dev-server";
 | |
| class ServeCommand {
 | |
|     async apply(cli) {
 | |
|         const loadDevServerOptions = () => {
 | |
|             // eslint-disable-next-line @typescript-eslint/no-var-requires
 | |
|             const devServer = require(WEBPACK_DEV_SERVER_PACKAGE);
 | |
|             // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|             const options = 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({
 | |
|             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, options) => {
 | |
|             const builtInOptions = cli.getBuiltInOptions();
 | |
|             let devServerFlags = [];
 | |
|             try {
 | |
|                 devServerFlags = loadDevServerOptions();
 | |
|             }
 | |
|             catch (error) {
 | |
|                 // Nothing, to prevent future updates
 | |
|             }
 | |
|             // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|             const webpackCLIOptions = {};
 | |
|             // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|             const devServerCLIOptions = {};
 | |
|             // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|             const processors = [];
 | |
|             for (const optionName in options) {
 | |
|                 const kebabedOption = cli.toKebabCase(optionName);
 | |
|                 const isBuiltInOption = builtInOptions.find(
 | |
|                 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|                 (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) => 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 = Object.assign(Object.assign({}, options), { env: Object.assign({ WEBPACK_SERVE: true }, options.env) });
 | |
|             webpackCLIOptions.isWatchingLikeCommand = true;
 | |
|             const compiler = await cli.createCompiler(webpackCLIOptions);
 | |
|             if (!compiler) {
 | |
|                 return;
 | |
|             }
 | |
|             const servers = [];
 | |
|             if (cli.needWatchStdin(compiler)) {
 | |
|                 process.stdin.on("end", () => {
 | |
|                     Promise.all(servers.map((server) => {
 | |
|                         return server.stop();
 | |
|                     })).then(() => {
 | |
|                         process.exit(0);
 | |
|                     });
 | |
|                 });
 | |
|                 process.stdin.resume();
 | |
|             }
 | |
|             // eslint-disable-next-line @typescript-eslint/no-var-requires
 | |
|             const DevServer = require(WEBPACK_DEV_SERVER_PACKAGE);
 | |
|             try {
 | |
|                 // eslint-disable-next-line @typescript-eslint/no-var-requires
 | |
|                 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.options.devServer);
 | |
|             const compilersForDevServer = possibleCompilers.length > 0 ? possibleCompilers : [compilers[0]];
 | |
|             const usedPorts = [];
 | |
|             for (const compilerForDevServer of compilersForDevServer) {
 | |
|                 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|                 const args = devServerFlags.reduce((accumulator, flag) => {
 | |
|                     accumulator[flag.name] = flag;
 | |
|                     return accumulator;
 | |
|                 }, {});
 | |
|                 const values = Object.keys(devServerCLIOptions).reduce(
 | |
|                 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|                 (accumulator, name) => {
 | |
|                     const kebabName = cli.toKebabCase(name);
 | |
|                     if (args[kebabName]) {
 | |
|                         accumulator[kebabName] = options[name];
 | |
|                     }
 | |
|                     return accumulator;
 | |
|                 }, {});
 | |
|                 const result = Object.assign({}, (compilerForDevServer.options.devServer || {}));
 | |
|                 const problems = (cli.webpack.cli && typeof cli.webpack.cli.processArguments === "function"
 | |
|                     ? cli.webpack.cli
 | |
|                     : DevServer.cli).processArguments(args, result, values);
 | |
|                 if (problems) {
 | |
|                     const groupBy = (xs, key) => {
 | |
|                         return xs.reduce((rv, x) => {
 | |
|                             (rv[x[key]] = rv[x[key]] || []).push(x);
 | |
|                             return rv;
 | |
|                         }, {});
 | |
|                     };
 | |
|                     const problemsByPath = groupBy(problems, "path");
 | |
|                     for (const path in problemsByPath) {
 | |
|                         const problems = problemsByPath[path];
 | |
|                         for (const problem of problems) {
 | |
|                             cli.logger.error(`${cli.capitalizeFirstLetter(problem.type.replace(/-/g, " "))}${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 = result;
 | |
|                 if (devServerOptions.port) {
 | |
|                     const portNumber = Number(devServerOptions.port);
 | |
|                     if (usedPorts.find((port) => portNumber === port)) {
 | |
|                         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)) {
 | |
|                         cli.logger.error(error.message);
 | |
|                     }
 | |
|                     else {
 | |
|                         cli.logger.error(error);
 | |
|                     }
 | |
|                     process.exit(2);
 | |
|                 }
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| }
 | |
| exports.default = ServeCommand;
 |