UNPKG

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