vue.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #!/usr/bin/env node
  2. // Check node version before requiring/doing anything else
  3. // The user may be on a very old node version
  4. const { chalk, semver } = require('@vue/cli-shared-utils')
  5. const requiredVersion = require('../package.json').engines.node
  6. const didYouMean = require('didyoumean')
  7. // Setting edit distance to 60% of the input string's length
  8. didYouMean.threshold = 0.6
  9. function checkNodeVersion (wanted, id) {
  10. if (!semver.satisfies(process.version, wanted)) {
  11. console.log(chalk.red(
  12. 'You are using Node ' + process.version + ', but this version of ' + id +
  13. ' requires Node ' + wanted + '.\nPlease upgrade your Node version.'
  14. ))
  15. process.exit(1)
  16. }
  17. }
  18. checkNodeVersion(requiredVersion, '@vue/cli')
  19. if (semver.satisfies(process.version, '9.x')) {
  20. console.log(chalk.red(
  21. `You are using Node ${process.version}.\n` +
  22. `Node.js 9.x has already reached end-of-life and will not be supported in future major releases.\n` +
  23. `It's strongly recommended to use an active LTS version instead.`
  24. ))
  25. }
  26. const fs = require('fs')
  27. const path = require('path')
  28. const slash = require('slash')
  29. const minimist = require('minimist')
  30. // enter debug mode when creating test repo
  31. if (
  32. slash(process.cwd()).indexOf('/packages/test') > 0 && (
  33. fs.existsSync(path.resolve(process.cwd(), '../@vue')) ||
  34. fs.existsSync(path.resolve(process.cwd(), '../../@vue'))
  35. )
  36. ) {
  37. process.env.VUE_CLI_DEBUG = true
  38. }
  39. const program = require('commander')
  40. const loadCommand = require('../lib/util/loadCommand')
  41. program
  42. .version(`@vue/cli ${require('../package').version}`)
  43. .usage('<command> [options]')
  44. program
  45. .command('create <app-name>')
  46. .description('create a new project powered by vue-cli-service')
  47. .option('-p, --preset <presetName>', 'Skip prompts and use saved or remote preset')
  48. .option('-d, --default', 'Skip prompts and use default preset')
  49. .option('-i, --inlinePreset <json>', 'Skip prompts and use inline JSON string as preset')
  50. .option('-m, --packageManager <command>', 'Use specified npm client when installing dependencies')
  51. .option('-r, --registry <url>', 'Use specified npm registry when installing dependencies (only for npm)')
  52. .option('-g, --git [message]', 'Force git initialization with initial commit message')
  53. .option('-n, --no-git', 'Skip git initialization')
  54. .option('-f, --force', 'Overwrite target directory if it exists')
  55. .option('--merge', 'Merge target directory if it exists')
  56. .option('-c, --clone', 'Use git clone when fetching remote preset')
  57. .option('-x, --proxy', 'Use specified proxy when creating project')
  58. .option('-b, --bare', 'Scaffold project without beginner instructions')
  59. .option('--skipGetStarted', 'Skip displaying "Get started" instructions')
  60. .action((name, cmd) => {
  61. const options = cleanArgs(cmd)
  62. if (minimist(process.argv.slice(3))._.length > 1) {
  63. console.log(chalk.yellow('\n Info: You provided more than one argument. The first one will be used as the app\'s name, the rest are ignored.'))
  64. }
  65. // --git makes commander to default git to true
  66. if (process.argv.includes('-g') || process.argv.includes('--git')) {
  67. options.forceGit = true
  68. }
  69. require('../lib/create')(name, options)
  70. })
  71. program
  72. .command('add <plugin> [pluginOptions]')
  73. .description('install a plugin and invoke its generator in an already created project')
  74. .option('--registry <url>', 'Use specified npm registry when installing dependencies (only for npm)')
  75. .allowUnknownOption()
  76. .action((plugin) => {
  77. require('../lib/add')(plugin, minimist(process.argv.slice(3)))
  78. })
  79. program
  80. .command('invoke <plugin> [pluginOptions]')
  81. .description('invoke the generator of a plugin in an already created project')
  82. .option('--registry <url>', 'Use specified npm registry when installing dependencies (only for npm)')
  83. .allowUnknownOption()
  84. .action((plugin) => {
  85. require('../lib/invoke')(plugin, minimist(process.argv.slice(3)))
  86. })
  87. program
  88. .command('inspect [paths...]')
  89. .description('inspect the webpack config in a project with vue-cli-service')
  90. .option('--mode <mode>')
  91. .option('--rule <ruleName>', 'inspect a specific module rule')
  92. .option('--plugin <pluginName>', 'inspect a specific plugin')
  93. .option('--rules', 'list all module rule names')
  94. .option('--plugins', 'list all plugin names')
  95. .option('-v --verbose', 'Show full function definitions in output')
  96. .action((paths, cmd) => {
  97. require('../lib/inspect')(paths, cleanArgs(cmd))
  98. })
  99. program
  100. .command('serve [entry]')
  101. .description('serve a .js or .vue file in development mode with zero config')
  102. .option('-o, --open', 'Open browser')
  103. .option('-c, --copy', 'Copy local url to clipboard')
  104. .option('-p, --port <port>', 'Port used by the server (default: 8080 or next available port)')
  105. .action((entry, cmd) => {
  106. loadCommand('serve', '@vue/cli-service-global').serve(entry, cleanArgs(cmd))
  107. })
  108. program
  109. .command('build [entry]')
  110. .description('build a .js or .vue file in production mode with zero config')
  111. .option('-t, --target <target>', 'Build target (app | lib | wc | wc-async, default: app)')
  112. .option('-n, --name <name>', 'name for lib or web-component mode (default: entry filename)')
  113. .option('-d, --dest <dir>', 'output directory (default: dist)')
  114. .action((entry, cmd) => {
  115. loadCommand('build', '@vue/cli-service-global').build(entry, cleanArgs(cmd))
  116. })
  117. program
  118. .command('ui')
  119. .description('start and open the vue-cli ui')
  120. .option('-H, --host <host>', 'Host used for the UI server (default: localhost)')
  121. .option('-p, --port <port>', 'Port used for the UI server (by default search for available port)')
  122. .option('-D, --dev', 'Run in dev mode')
  123. .option('--quiet', `Don't output starting messages`)
  124. .option('--headless', `Don't open browser on start and output port`)
  125. .action((cmd) => {
  126. checkNodeVersion('>=8.6', 'vue ui')
  127. require('../lib/ui')(cleanArgs(cmd))
  128. })
  129. program
  130. .command('init <template> <app-name>')
  131. .description('generate a project from a remote template (legacy API, requires @vue/cli-init)')
  132. .option('-c, --clone', 'Use git clone when fetching remote template')
  133. .option('--offline', 'Use cached template')
  134. .action(() => {
  135. loadCommand('init', '@vue/cli-init')
  136. })
  137. program
  138. .command('config [value]')
  139. .description('inspect and modify the config')
  140. .option('-g, --get <path>', 'get value from option')
  141. .option('-s, --set <path> <value>', 'set option value')
  142. .option('-d, --delete <path>', 'delete option from config')
  143. .option('-e, --edit', 'open config with default editor')
  144. .option('--json', 'outputs JSON result only')
  145. .action((value, cmd) => {
  146. require('../lib/config')(value, cleanArgs(cmd))
  147. })
  148. program
  149. .command('outdated')
  150. .description('(experimental) check for outdated vue cli service / plugins')
  151. .option('--next', 'Also check for alpha / beta / rc versions when upgrading')
  152. .action((cmd) => {
  153. require('../lib/outdated')(cleanArgs(cmd))
  154. })
  155. program
  156. .command('upgrade [plugin-name]')
  157. .description('(experimental) upgrade vue cli service / plugins')
  158. .option('-t, --to <version>', 'Upgrade <package-name> to a version that is not latest')
  159. .option('-f, --from <version>', 'Skip probing installed plugin, assuming it is upgraded from the designated version')
  160. .option('-r, --registry <url>', 'Use specified npm registry when installing dependencies')
  161. .option('--all', 'Upgrade all plugins')
  162. .option('--next', 'Also check for alpha / beta / rc versions when upgrading')
  163. .action((packageName, cmd) => {
  164. require('../lib/upgrade')(packageName, cleanArgs(cmd))
  165. })
  166. program
  167. .command('migrate [plugin-name]')
  168. .description('(experimental) run migrator for an already-installed cli plugin')
  169. // TODO: use `requiredOption` after upgrading to commander 4.x
  170. .option('-f, --from <version>', 'The base version for the migrator to migrate from')
  171. .action((packageName, cmd) => {
  172. require('../lib/migrate')(packageName, cleanArgs(cmd))
  173. })
  174. program
  175. .command('info')
  176. .description('print debugging information about your environment')
  177. .action((cmd) => {
  178. console.log(chalk.bold('\nEnvironment Info:'))
  179. require('envinfo').run(
  180. {
  181. System: ['OS', 'CPU'],
  182. Binaries: ['Node', 'Yarn', 'npm'],
  183. Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
  184. npmPackages: '/**/{typescript,*vue*,@vue/*/}',
  185. npmGlobalPackages: ['@vue/cli']
  186. },
  187. {
  188. showNotFound: true,
  189. duplicates: true,
  190. fullTree: true
  191. }
  192. ).then(console.log)
  193. })
  194. // output help information on unknown commands
  195. program
  196. .arguments('<command>')
  197. .action((cmd) => {
  198. program.outputHelp()
  199. console.log(` ` + chalk.red(`Unknown command ${chalk.yellow(cmd)}.`))
  200. console.log()
  201. suggestCommands(cmd)
  202. })
  203. // add some useful info on help
  204. program.on('--help', () => {
  205. console.log()
  206. console.log(` Run ${chalk.cyan(`vue <command> --help`)} for detailed usage of given command.`)
  207. console.log()
  208. })
  209. program.commands.forEach(c => c.on('--help', () => console.log()))
  210. // enhance common error messages
  211. const enhanceErrorMessages = require('../lib/util/enhanceErrorMessages')
  212. enhanceErrorMessages('missingArgument', argName => {
  213. return `Missing required argument ${chalk.yellow(`<${argName}>`)}.`
  214. })
  215. enhanceErrorMessages('unknownOption', optionName => {
  216. return `Unknown option ${chalk.yellow(optionName)}.`
  217. })
  218. enhanceErrorMessages('optionMissingArgument', (option, flag) => {
  219. return `Missing required argument for option ${chalk.yellow(option.flags)}` + (
  220. flag ? `, got ${chalk.yellow(flag)}` : ``
  221. )
  222. })
  223. program.parse(process.argv)
  224. if (!process.argv.slice(2).length) {
  225. program.outputHelp()
  226. }
  227. function suggestCommands (unknownCommand) {
  228. const availableCommands = program.commands.map(cmd => cmd._name)
  229. const suggestion = didYouMean(unknownCommand, availableCommands)
  230. if (suggestion) {
  231. console.log(` ` + chalk.red(`Did you mean ${chalk.yellow(suggestion)}?`))
  232. }
  233. }
  234. function camelize (str) {
  235. return str.replace(/-(\w)/g, (_, c) => c ? c.toUpperCase() : '')
  236. }
  237. // commander passes the Command object itself as options,
  238. // extract only actual options into a fresh object.
  239. function cleanArgs (cmd) {
  240. const args = {}
  241. cmd.options.forEach(o => {
  242. const key = camelize(o.long.replace(/^--/, ''))
  243. // if an option is not present and Command has a method with the same name
  244. // it should not be copied
  245. if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') {
  246. args[key] = cmd[key]
  247. }
  248. })
  249. return args
  250. }