cli.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. import path from 'node:path';
  2. import fs from 'node:fs';
  3. import { performance } from 'node:perf_hooks';
  4. import { EventEmitter } from 'events';
  5. import { C as colors, D as bindShortcuts, x as createLogger, h as resolveConfig } from './chunks/dep-75f53616.js';
  6. import { VERSION } from './constants.js';
  7. import 'node:fs/promises';
  8. import 'node:url';
  9. import 'node:util';
  10. import 'node:module';
  11. import 'tty';
  12. import 'esbuild';
  13. import 'path';
  14. import 'fs';
  15. import 'assert';
  16. import 'util';
  17. import 'net';
  18. import 'url';
  19. import 'http';
  20. import 'stream';
  21. import 'os';
  22. import 'child_process';
  23. import 'node:os';
  24. import 'node:child_process';
  25. import 'node:crypto';
  26. import 'node:dns';
  27. import 'crypto';
  28. import 'node:buffer';
  29. import 'module';
  30. import 'node:assert';
  31. import 'node:process';
  32. import 'node:v8';
  33. import 'rollup';
  34. import 'worker_threads';
  35. import 'node:http';
  36. import 'node:https';
  37. import 'zlib';
  38. import 'buffer';
  39. import 'https';
  40. import 'tls';
  41. import 'querystring';
  42. import 'node:readline';
  43. import 'node:zlib';
  44. function toArr(any) {
  45. return any == null ? [] : Array.isArray(any) ? any : [any];
  46. }
  47. function toVal(out, key, val, opts) {
  48. var x, old=out[key], nxt=(
  49. !!~opts.string.indexOf(key) ? (val == null || val === true ? '' : String(val))
  50. : typeof val === 'boolean' ? val
  51. : !!~opts.boolean.indexOf(key) ? (val === 'false' ? false : val === 'true' || (out._.push((x = +val,x * 0 === 0) ? x : val),!!val))
  52. : (x = +val,x * 0 === 0) ? x : val
  53. );
  54. out[key] = old == null ? nxt : (Array.isArray(old) ? old.concat(nxt) : [old, nxt]);
  55. }
  56. function mri2 (args, opts) {
  57. args = args || [];
  58. opts = opts || {};
  59. var k, arr, arg, name, val, out={ _:[] };
  60. var i=0, j=0, idx=0, len=args.length;
  61. const alibi = opts.alias !== void 0;
  62. const strict = opts.unknown !== void 0;
  63. const defaults = opts.default !== void 0;
  64. opts.alias = opts.alias || {};
  65. opts.string = toArr(opts.string);
  66. opts.boolean = toArr(opts.boolean);
  67. if (alibi) {
  68. for (k in opts.alias) {
  69. arr = opts.alias[k] = toArr(opts.alias[k]);
  70. for (i=0; i < arr.length; i++) {
  71. (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);
  72. }
  73. }
  74. }
  75. for (i=opts.boolean.length; i-- > 0;) {
  76. arr = opts.alias[opts.boolean[i]] || [];
  77. for (j=arr.length; j-- > 0;) opts.boolean.push(arr[j]);
  78. }
  79. for (i=opts.string.length; i-- > 0;) {
  80. arr = opts.alias[opts.string[i]] || [];
  81. for (j=arr.length; j-- > 0;) opts.string.push(arr[j]);
  82. }
  83. if (defaults) {
  84. for (k in opts.default) {
  85. name = typeof opts.default[k];
  86. arr = opts.alias[k] = opts.alias[k] || [];
  87. if (opts[name] !== void 0) {
  88. opts[name].push(k);
  89. for (i=0; i < arr.length; i++) {
  90. opts[name].push(arr[i]);
  91. }
  92. }
  93. }
  94. }
  95. const keys = strict ? Object.keys(opts.alias) : [];
  96. for (i=0; i < len; i++) {
  97. arg = args[i];
  98. if (arg === '--') {
  99. out._ = out._.concat(args.slice(++i));
  100. break;
  101. }
  102. for (j=0; j < arg.length; j++) {
  103. if (arg.charCodeAt(j) !== 45) break; // "-"
  104. }
  105. if (j === 0) {
  106. out._.push(arg);
  107. } else if (arg.substring(j, j + 3) === 'no-') {
  108. name = arg.substring(j + 3);
  109. if (strict && !~keys.indexOf(name)) {
  110. return opts.unknown(arg);
  111. }
  112. out[name] = false;
  113. } else {
  114. for (idx=j+1; idx < arg.length; idx++) {
  115. if (arg.charCodeAt(idx) === 61) break; // "="
  116. }
  117. name = arg.substring(j, idx);
  118. val = arg.substring(++idx) || (i+1 === len || (''+args[i+1]).charCodeAt(0) === 45 || args[++i]);
  119. arr = (j === 2 ? [name] : name);
  120. for (idx=0; idx < arr.length; idx++) {
  121. name = arr[idx];
  122. if (strict && !~keys.indexOf(name)) return opts.unknown('-'.repeat(j) + name);
  123. toVal(out, name, (idx + 1 < arr.length) || val, opts);
  124. }
  125. }
  126. }
  127. if (defaults) {
  128. for (k in opts.default) {
  129. if (out[k] === void 0) {
  130. out[k] = opts.default[k];
  131. }
  132. }
  133. }
  134. if (alibi) {
  135. for (k in out) {
  136. arr = opts.alias[k] || [];
  137. while (arr.length > 0) {
  138. out[arr.shift()] = out[k];
  139. }
  140. }
  141. }
  142. return out;
  143. }
  144. const removeBrackets = (v) => v.replace(/[<[].+/, "").trim();
  145. const findAllBrackets = (v) => {
  146. const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
  147. const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
  148. const res = [];
  149. const parse = (match) => {
  150. let variadic = false;
  151. let value = match[1];
  152. if (value.startsWith("...")) {
  153. value = value.slice(3);
  154. variadic = true;
  155. }
  156. return {
  157. required: match[0].startsWith("<"),
  158. value,
  159. variadic
  160. };
  161. };
  162. let angledMatch;
  163. while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {
  164. res.push(parse(angledMatch));
  165. }
  166. let squareMatch;
  167. while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {
  168. res.push(parse(squareMatch));
  169. }
  170. return res;
  171. };
  172. const getMriOptions = (options) => {
  173. const result = {alias: {}, boolean: []};
  174. for (const [index, option] of options.entries()) {
  175. if (option.names.length > 1) {
  176. result.alias[option.names[0]] = option.names.slice(1);
  177. }
  178. if (option.isBoolean) {
  179. if (option.negated) {
  180. const hasStringTypeOption = options.some((o, i) => {
  181. return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === "boolean";
  182. });
  183. if (!hasStringTypeOption) {
  184. result.boolean.push(option.names[0]);
  185. }
  186. } else {
  187. result.boolean.push(option.names[0]);
  188. }
  189. }
  190. }
  191. return result;
  192. };
  193. const findLongest = (arr) => {
  194. return arr.sort((a, b) => {
  195. return a.length > b.length ? -1 : 1;
  196. })[0];
  197. };
  198. const padRight = (str, length) => {
  199. return str.length >= length ? str : `${str}${" ".repeat(length - str.length)}`;
  200. };
  201. const camelcase = (input) => {
  202. return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {
  203. return p1 + p2.toUpperCase();
  204. });
  205. };
  206. const setDotProp = (obj, keys, val) => {
  207. let i = 0;
  208. let length = keys.length;
  209. let t = obj;
  210. let x;
  211. for (; i < length; ++i) {
  212. x = t[keys[i]];
  213. t = t[keys[i]] = i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(".") || !(+keys[i + 1] > -1) ? {} : [];
  214. }
  215. };
  216. const setByType = (obj, transforms) => {
  217. for (const key of Object.keys(transforms)) {
  218. const transform = transforms[key];
  219. if (transform.shouldTransform) {
  220. obj[key] = Array.prototype.concat.call([], obj[key]);
  221. if (typeof transform.transformFunction === "function") {
  222. obj[key] = obj[key].map(transform.transformFunction);
  223. }
  224. }
  225. }
  226. };
  227. const getFileName = (input) => {
  228. const m = /([^\\\/]+)$/.exec(input);
  229. return m ? m[1] : "";
  230. };
  231. const camelcaseOptionName = (name) => {
  232. return name.split(".").map((v, i) => {
  233. return i === 0 ? camelcase(v) : v;
  234. }).join(".");
  235. };
  236. class CACError extends Error {
  237. constructor(message) {
  238. super(message);
  239. this.name = this.constructor.name;
  240. if (typeof Error.captureStackTrace === "function") {
  241. Error.captureStackTrace(this, this.constructor);
  242. } else {
  243. this.stack = new Error(message).stack;
  244. }
  245. }
  246. }
  247. class Option {
  248. constructor(rawName, description, config) {
  249. this.rawName = rawName;
  250. this.description = description;
  251. this.config = Object.assign({}, config);
  252. rawName = rawName.replace(/\.\*/g, "");
  253. this.negated = false;
  254. this.names = removeBrackets(rawName).split(",").map((v) => {
  255. let name = v.trim().replace(/^-{1,2}/, "");
  256. if (name.startsWith("no-")) {
  257. this.negated = true;
  258. name = name.replace(/^no-/, "");
  259. }
  260. return camelcaseOptionName(name);
  261. }).sort((a, b) => a.length > b.length ? 1 : -1);
  262. this.name = this.names[this.names.length - 1];
  263. if (this.negated && this.config.default == null) {
  264. this.config.default = true;
  265. }
  266. if (rawName.includes("<")) {
  267. this.required = true;
  268. } else if (rawName.includes("[")) {
  269. this.required = false;
  270. } else {
  271. this.isBoolean = true;
  272. }
  273. }
  274. }
  275. const processArgs = process.argv;
  276. const platformInfo = `${process.platform}-${process.arch} node-${process.version}`;
  277. class Command {
  278. constructor(rawName, description, config = {}, cli) {
  279. this.rawName = rawName;
  280. this.description = description;
  281. this.config = config;
  282. this.cli = cli;
  283. this.options = [];
  284. this.aliasNames = [];
  285. this.name = removeBrackets(rawName);
  286. this.args = findAllBrackets(rawName);
  287. this.examples = [];
  288. }
  289. usage(text) {
  290. this.usageText = text;
  291. return this;
  292. }
  293. allowUnknownOptions() {
  294. this.config.allowUnknownOptions = true;
  295. return this;
  296. }
  297. ignoreOptionDefaultValue() {
  298. this.config.ignoreOptionDefaultValue = true;
  299. return this;
  300. }
  301. version(version, customFlags = "-v, --version") {
  302. this.versionNumber = version;
  303. this.option(customFlags, "Display version number");
  304. return this;
  305. }
  306. example(example) {
  307. this.examples.push(example);
  308. return this;
  309. }
  310. option(rawName, description, config) {
  311. const option = new Option(rawName, description, config);
  312. this.options.push(option);
  313. return this;
  314. }
  315. alias(name) {
  316. this.aliasNames.push(name);
  317. return this;
  318. }
  319. action(callback) {
  320. this.commandAction = callback;
  321. return this;
  322. }
  323. isMatched(name) {
  324. return this.name === name || this.aliasNames.includes(name);
  325. }
  326. get isDefaultCommand() {
  327. return this.name === "" || this.aliasNames.includes("!");
  328. }
  329. get isGlobalCommand() {
  330. return this instanceof GlobalCommand;
  331. }
  332. hasOption(name) {
  333. name = name.split(".")[0];
  334. return this.options.find((option) => {
  335. return option.names.includes(name);
  336. });
  337. }
  338. outputHelp() {
  339. const {name, commands} = this.cli;
  340. const {
  341. versionNumber,
  342. options: globalOptions,
  343. helpCallback
  344. } = this.cli.globalCommand;
  345. let sections = [
  346. {
  347. body: `${name}${versionNumber ? `/${versionNumber}` : ""}`
  348. }
  349. ];
  350. sections.push({
  351. title: "Usage",
  352. body: ` $ ${name} ${this.usageText || this.rawName}`
  353. });
  354. const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
  355. if (showCommands) {
  356. const longestCommandName = findLongest(commands.map((command) => command.rawName));
  357. sections.push({
  358. title: "Commands",
  359. body: commands.map((command) => {
  360. return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
  361. }).join("\n")
  362. });
  363. sections.push({
  364. title: `For more info, run any command with the \`--help\` flag`,
  365. body: commands.map((command) => ` $ ${name}${command.name === "" ? "" : ` ${command.name}`} --help`).join("\n")
  366. });
  367. }
  368. let options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];
  369. if (!this.isGlobalCommand && !this.isDefaultCommand) {
  370. options = options.filter((option) => option.name !== "version");
  371. }
  372. if (options.length > 0) {
  373. const longestOptionName = findLongest(options.map((option) => option.rawName));
  374. sections.push({
  375. title: "Options",
  376. body: options.map((option) => {
  377. return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? "" : `(default: ${option.config.default})`}`;
  378. }).join("\n")
  379. });
  380. }
  381. if (this.examples.length > 0) {
  382. sections.push({
  383. title: "Examples",
  384. body: this.examples.map((example) => {
  385. if (typeof example === "function") {
  386. return example(name);
  387. }
  388. return example;
  389. }).join("\n")
  390. });
  391. }
  392. if (helpCallback) {
  393. sections = helpCallback(sections) || sections;
  394. }
  395. console.log(sections.map((section) => {
  396. return section.title ? `${section.title}:
  397. ${section.body}` : section.body;
  398. }).join("\n\n"));
  399. }
  400. outputVersion() {
  401. const {name} = this.cli;
  402. const {versionNumber} = this.cli.globalCommand;
  403. if (versionNumber) {
  404. console.log(`${name}/${versionNumber} ${platformInfo}`);
  405. }
  406. }
  407. checkRequiredArgs() {
  408. const minimalArgsCount = this.args.filter((arg) => arg.required).length;
  409. if (this.cli.args.length < minimalArgsCount) {
  410. throw new CACError(`missing required args for command \`${this.rawName}\``);
  411. }
  412. }
  413. checkUnknownOptions() {
  414. const {options, globalCommand} = this.cli;
  415. if (!this.config.allowUnknownOptions) {
  416. for (const name of Object.keys(options)) {
  417. if (name !== "--" && !this.hasOption(name) && !globalCommand.hasOption(name)) {
  418. throw new CACError(`Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``);
  419. }
  420. }
  421. }
  422. }
  423. checkOptionValue() {
  424. const {options: parsedOptions, globalCommand} = this.cli;
  425. const options = [...globalCommand.options, ...this.options];
  426. for (const option of options) {
  427. const value = parsedOptions[option.name.split(".")[0]];
  428. if (option.required) {
  429. const hasNegated = options.some((o) => o.negated && o.names.includes(option.name));
  430. if (value === true || value === false && !hasNegated) {
  431. throw new CACError(`option \`${option.rawName}\` value is missing`);
  432. }
  433. }
  434. }
  435. }
  436. }
  437. class GlobalCommand extends Command {
  438. constructor(cli) {
  439. super("@@global@@", "", {}, cli);
  440. }
  441. }
  442. var __assign = Object.assign;
  443. class CAC extends EventEmitter {
  444. constructor(name = "") {
  445. super();
  446. this.name = name;
  447. this.commands = [];
  448. this.rawArgs = [];
  449. this.args = [];
  450. this.options = {};
  451. this.globalCommand = new GlobalCommand(this);
  452. this.globalCommand.usage("<command> [options]");
  453. }
  454. usage(text) {
  455. this.globalCommand.usage(text);
  456. return this;
  457. }
  458. command(rawName, description, config) {
  459. const command = new Command(rawName, description || "", config, this);
  460. command.globalCommand = this.globalCommand;
  461. this.commands.push(command);
  462. return command;
  463. }
  464. option(rawName, description, config) {
  465. this.globalCommand.option(rawName, description, config);
  466. return this;
  467. }
  468. help(callback) {
  469. this.globalCommand.option("-h, --help", "Display this message");
  470. this.globalCommand.helpCallback = callback;
  471. this.showHelpOnExit = true;
  472. return this;
  473. }
  474. version(version, customFlags = "-v, --version") {
  475. this.globalCommand.version(version, customFlags);
  476. this.showVersionOnExit = true;
  477. return this;
  478. }
  479. example(example) {
  480. this.globalCommand.example(example);
  481. return this;
  482. }
  483. outputHelp() {
  484. if (this.matchedCommand) {
  485. this.matchedCommand.outputHelp();
  486. } else {
  487. this.globalCommand.outputHelp();
  488. }
  489. }
  490. outputVersion() {
  491. this.globalCommand.outputVersion();
  492. }
  493. setParsedInfo({args, options}, matchedCommand, matchedCommandName) {
  494. this.args = args;
  495. this.options = options;
  496. if (matchedCommand) {
  497. this.matchedCommand = matchedCommand;
  498. }
  499. if (matchedCommandName) {
  500. this.matchedCommandName = matchedCommandName;
  501. }
  502. return this;
  503. }
  504. unsetMatchedCommand() {
  505. this.matchedCommand = void 0;
  506. this.matchedCommandName = void 0;
  507. }
  508. parse(argv = processArgs, {
  509. run = true
  510. } = {}) {
  511. this.rawArgs = argv;
  512. if (!this.name) {
  513. this.name = argv[1] ? getFileName(argv[1]) : "cli";
  514. }
  515. let shouldParse = true;
  516. for (const command of this.commands) {
  517. const parsed = this.mri(argv.slice(2), command);
  518. const commandName = parsed.args[0];
  519. if (command.isMatched(commandName)) {
  520. shouldParse = false;
  521. const parsedInfo = __assign(__assign({}, parsed), {
  522. args: parsed.args.slice(1)
  523. });
  524. this.setParsedInfo(parsedInfo, command, commandName);
  525. this.emit(`command:${commandName}`, command);
  526. }
  527. }
  528. if (shouldParse) {
  529. for (const command of this.commands) {
  530. if (command.name === "") {
  531. shouldParse = false;
  532. const parsed = this.mri(argv.slice(2), command);
  533. this.setParsedInfo(parsed, command);
  534. this.emit(`command:!`, command);
  535. }
  536. }
  537. }
  538. if (shouldParse) {
  539. const parsed = this.mri(argv.slice(2));
  540. this.setParsedInfo(parsed);
  541. }
  542. if (this.options.help && this.showHelpOnExit) {
  543. this.outputHelp();
  544. run = false;
  545. this.unsetMatchedCommand();
  546. }
  547. if (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {
  548. this.outputVersion();
  549. run = false;
  550. this.unsetMatchedCommand();
  551. }
  552. const parsedArgv = {args: this.args, options: this.options};
  553. if (run) {
  554. this.runMatchedCommand();
  555. }
  556. if (!this.matchedCommand && this.args[0]) {
  557. this.emit("command:*");
  558. }
  559. return parsedArgv;
  560. }
  561. mri(argv, command) {
  562. const cliOptions = [
  563. ...this.globalCommand.options,
  564. ...command ? command.options : []
  565. ];
  566. const mriOptions = getMriOptions(cliOptions);
  567. let argsAfterDoubleDashes = [];
  568. const doubleDashesIndex = argv.indexOf("--");
  569. if (doubleDashesIndex > -1) {
  570. argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);
  571. argv = argv.slice(0, doubleDashesIndex);
  572. }
  573. let parsed = mri2(argv, mriOptions);
  574. parsed = Object.keys(parsed).reduce((res, name) => {
  575. return __assign(__assign({}, res), {
  576. [camelcaseOptionName(name)]: parsed[name]
  577. });
  578. }, {_: []});
  579. const args = parsed._;
  580. const options = {
  581. "--": argsAfterDoubleDashes
  582. };
  583. const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;
  584. let transforms = Object.create(null);
  585. for (const cliOption of cliOptions) {
  586. if (!ignoreDefault && cliOption.config.default !== void 0) {
  587. for (const name of cliOption.names) {
  588. options[name] = cliOption.config.default;
  589. }
  590. }
  591. if (Array.isArray(cliOption.config.type)) {
  592. if (transforms[cliOption.name] === void 0) {
  593. transforms[cliOption.name] = Object.create(null);
  594. transforms[cliOption.name]["shouldTransform"] = true;
  595. transforms[cliOption.name]["transformFunction"] = cliOption.config.type[0];
  596. }
  597. }
  598. }
  599. for (const key of Object.keys(parsed)) {
  600. if (key !== "_") {
  601. const keys = key.split(".");
  602. setDotProp(options, keys, parsed[key]);
  603. setByType(options, transforms);
  604. }
  605. }
  606. return {
  607. args,
  608. options
  609. };
  610. }
  611. runMatchedCommand() {
  612. const {args, options, matchedCommand: command} = this;
  613. if (!command || !command.commandAction)
  614. return;
  615. command.checkUnknownOptions();
  616. command.checkOptionValue();
  617. command.checkRequiredArgs();
  618. const actionArgs = [];
  619. command.args.forEach((arg, index) => {
  620. if (arg.variadic) {
  621. actionArgs.push(args.slice(index));
  622. } else {
  623. actionArgs.push(args[index]);
  624. }
  625. });
  626. actionArgs.push(options);
  627. return command.commandAction.apply(this, actionArgs);
  628. }
  629. }
  630. const cac = (name = "") => new CAC(name);
  631. const cli = cac('vite');
  632. let profileSession = global.__vite_profile_session;
  633. let profileCount = 0;
  634. const stopProfiler = (log) => {
  635. if (!profileSession)
  636. return;
  637. return new Promise((res, rej) => {
  638. profileSession.post('Profiler.stop', (err, { profile }) => {
  639. // Write profile to disk, upload, etc.
  640. if (!err) {
  641. const outPath = path.resolve(`./vite-profile-${profileCount++}.cpuprofile`);
  642. fs.writeFileSync(outPath, JSON.stringify(profile));
  643. log(colors.yellow(`CPU profile written to ${colors.white(colors.dim(outPath))}`));
  644. profileSession = undefined;
  645. res();
  646. }
  647. else {
  648. rej(err);
  649. }
  650. });
  651. });
  652. };
  653. const filterDuplicateOptions = (options) => {
  654. for (const [key, value] of Object.entries(options)) {
  655. if (Array.isArray(value)) {
  656. options[key] = value[value.length - 1];
  657. }
  658. }
  659. };
  660. /**
  661. * removing global flags before passing as command specific sub-configs
  662. */
  663. function cleanOptions(options) {
  664. const ret = { ...options };
  665. delete ret['--'];
  666. delete ret.c;
  667. delete ret.config;
  668. delete ret.base;
  669. delete ret.l;
  670. delete ret.logLevel;
  671. delete ret.clearScreen;
  672. delete ret.d;
  673. delete ret.debug;
  674. delete ret.f;
  675. delete ret.filter;
  676. delete ret.m;
  677. delete ret.mode;
  678. // convert the sourcemap option to a boolean if necessary
  679. if ('sourcemap' in ret) {
  680. const sourcemap = ret.sourcemap;
  681. ret.sourcemap =
  682. sourcemap === 'true'
  683. ? true
  684. : sourcemap === 'false'
  685. ? false
  686. : ret.sourcemap;
  687. }
  688. return ret;
  689. }
  690. cli
  691. .option('-c, --config <file>', `[string] use specified config file`)
  692. .option('--base <path>', `[string] public base path (default: /)`)
  693. .option('-l, --logLevel <level>', `[string] info | warn | error | silent`)
  694. .option('--clearScreen', `[boolean] allow/disable clear screen when logging`)
  695. .option('-d, --debug [feat]', `[string | boolean] show debug logs`)
  696. .option('-f, --filter <filter>', `[string] filter debug logs`)
  697. .option('-m, --mode <mode>', `[string] set env mode`);
  698. // dev
  699. cli
  700. .command('[root]', 'start dev server') // default command
  701. .alias('serve') // the command is called 'serve' in Vite's API
  702. .alias('dev') // alias to align with the script name
  703. .option('--host [host]', `[string] specify hostname`)
  704. .option('--port <port>', `[number] specify port`)
  705. .option('--https', `[boolean] use TLS + HTTP/2`)
  706. .option('--open [path]', `[boolean | string] open browser on startup`)
  707. .option('--cors', `[boolean] enable CORS`)
  708. .option('--strictPort', `[boolean] exit if specified port is already in use`)
  709. .option('--force', `[boolean] force the optimizer to ignore the cache and re-bundle`)
  710. .action(async (root, options) => {
  711. filterDuplicateOptions(options);
  712. // output structure is preserved even after bundling so require()
  713. // is ok here
  714. const { createServer } = await import('./chunks/dep-75f53616.js').then(function (n) { return n.I; });
  715. try {
  716. const server = await createServer({
  717. root,
  718. base: options.base,
  719. mode: options.mode,
  720. configFile: options.config,
  721. logLevel: options.logLevel,
  722. clearScreen: options.clearScreen,
  723. optimizeDeps: { force: options.force },
  724. server: cleanOptions(options),
  725. });
  726. if (!server.httpServer) {
  727. throw new Error('HTTP server not available');
  728. }
  729. await server.listen();
  730. const info = server.config.logger.info;
  731. const viteStartTime = global.__vite_start_time ?? false;
  732. const startupDurationString = viteStartTime
  733. ? colors.dim(`ready in ${colors.reset(colors.bold(Math.ceil(performance.now() - viteStartTime)))} ms`)
  734. : '';
  735. info(`\n ${colors.green(`${colors.bold('VITE')} v${VERSION}`)} ${startupDurationString}\n`, { clear: !server.config.logger.hasWarned });
  736. server.printUrls();
  737. bindShortcuts(server, {
  738. print: true,
  739. customShortcuts: [
  740. profileSession && {
  741. key: 'p',
  742. description: 'start/stop the profiler',
  743. async action(server) {
  744. if (profileSession) {
  745. await stopProfiler(server.config.logger.info);
  746. }
  747. else {
  748. const inspector = await import('node:inspector').then((r) => r.default);
  749. await new Promise((res) => {
  750. profileSession = new inspector.Session();
  751. profileSession.connect();
  752. profileSession.post('Profiler.enable', () => {
  753. profileSession.post('Profiler.start', () => {
  754. server.config.logger.info('Profiler started');
  755. res();
  756. });
  757. });
  758. });
  759. }
  760. },
  761. },
  762. ],
  763. });
  764. }
  765. catch (e) {
  766. const logger = createLogger(options.logLevel);
  767. logger.error(colors.red(`error when starting dev server:\n${e.stack}`), {
  768. error: e,
  769. });
  770. stopProfiler(logger.info);
  771. process.exit(1);
  772. }
  773. });
  774. // build
  775. cli
  776. .command('build [root]', 'build for production')
  777. .option('--target <target>', `[string] transpile target (default: 'modules')`)
  778. .option('--outDir <dir>', `[string] output directory (default: dist)`)
  779. .option('--assetsDir <dir>', `[string] directory under outDir to place assets in (default: assets)`)
  780. .option('--assetsInlineLimit <number>', `[number] static asset base64 inline threshold in bytes (default: 4096)`)
  781. .option('--ssr [entry]', `[string] build specified entry for server-side rendering`)
  782. .option('--sourcemap [output]', `[boolean | "inline" | "hidden"] output source maps for build (default: false)`)
  783. .option('--minify [minifier]', `[boolean | "terser" | "esbuild"] enable/disable minification, ` +
  784. `or specify minifier to use (default: esbuild)`)
  785. .option('--manifest [name]', `[boolean | string] emit build manifest json`)
  786. .option('--ssrManifest [name]', `[boolean | string] emit ssr manifest json`)
  787. .option('--force', `[boolean] force the optimizer to ignore the cache and re-bundle (experimental)`)
  788. .option('--emptyOutDir', `[boolean] force empty outDir when it's outside of root`)
  789. .option('-w, --watch', `[boolean] rebuilds when modules have changed on disk`)
  790. .action(async (root, options) => {
  791. filterDuplicateOptions(options);
  792. const { build } = await import('./chunks/dep-75f53616.js').then(function (n) { return n.H; });
  793. const buildOptions = cleanOptions(options);
  794. try {
  795. await build({
  796. root,
  797. base: options.base,
  798. mode: options.mode,
  799. configFile: options.config,
  800. logLevel: options.logLevel,
  801. clearScreen: options.clearScreen,
  802. optimizeDeps: { force: options.force },
  803. build: buildOptions,
  804. });
  805. }
  806. catch (e) {
  807. createLogger(options.logLevel).error(colors.red(`error during build:\n${e.stack}`), { error: e });
  808. process.exit(1);
  809. }
  810. finally {
  811. stopProfiler((message) => createLogger(options.logLevel).info(message));
  812. }
  813. });
  814. // optimize
  815. cli
  816. .command('optimize [root]', 'pre-bundle dependencies')
  817. .option('--force', `[boolean] force the optimizer to ignore the cache and re-bundle`)
  818. .action(async (root, options) => {
  819. filterDuplicateOptions(options);
  820. const { optimizeDeps } = await import('./chunks/dep-75f53616.js').then(function (n) { return n.G; });
  821. try {
  822. const config = await resolveConfig({
  823. root,
  824. base: options.base,
  825. configFile: options.config,
  826. logLevel: options.logLevel,
  827. mode: options.mode,
  828. }, 'serve');
  829. await optimizeDeps(config, options.force, true);
  830. }
  831. catch (e) {
  832. createLogger(options.logLevel).error(colors.red(`error when optimizing deps:\n${e.stack}`), { error: e });
  833. process.exit(1);
  834. }
  835. });
  836. // preview
  837. cli
  838. .command('preview [root]', 'locally preview production build')
  839. .option('--host [host]', `[string] specify hostname`)
  840. .option('--port <port>', `[number] specify port`)
  841. .option('--strictPort', `[boolean] exit if specified port is already in use`)
  842. .option('--https', `[boolean] use TLS + HTTP/2`)
  843. .option('--open [path]', `[boolean | string] open browser on startup`)
  844. .option('--outDir <dir>', `[string] output directory (default: dist)`)
  845. .action(async (root, options) => {
  846. filterDuplicateOptions(options);
  847. const { preview } = await import('./chunks/dep-75f53616.js').then(function (n) { return n.J; });
  848. try {
  849. const server = await preview({
  850. root,
  851. base: options.base,
  852. configFile: options.config,
  853. logLevel: options.logLevel,
  854. mode: options.mode,
  855. build: {
  856. outDir: options.outDir,
  857. },
  858. preview: {
  859. port: options.port,
  860. strictPort: options.strictPort,
  861. host: options.host,
  862. https: options.https,
  863. open: options.open,
  864. },
  865. });
  866. server.printUrls();
  867. bindShortcuts(server, { print: true });
  868. }
  869. catch (e) {
  870. createLogger(options.logLevel).error(colors.red(`error when starting preview server:\n${e.stack}`), { error: e });
  871. process.exit(1);
  872. }
  873. finally {
  874. stopProfiler((message) => createLogger(options.logLevel).info(message));
  875. }
  876. });
  877. cli.help();
  878. cli.version(VERSION);
  879. cli.parse();
  880. export { stopProfiler };