Skip to content

Commit 773f8a4

Browse files
authored
feat: lock minor versions when creating projects / adding plugins (#5134)
* feat: lock minor versions when creating projects / adding plugins closes #5012 * refactor: also calculate latestMinor version * feat: support add packages with tilde version range * refactor: make the `runCommand` invocations more concise * refactor: use the `getVersions` utility function to get latestMinor * feat: when adding plugins, use tilde range by default * fix: allow empty args
1 parent c8cecff commit 773f8a4

File tree

6 files changed

+58
-43
lines changed

6 files changed

+58
-43
lines changed

packages/@vue/cli-ui/apollo-server/connectors/dependencies.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,10 @@ function install ({ id, type, range }, context) {
188188
}
189189

190190
const pm = new PackageManager({ context: cwd.get() })
191-
await pm.add(arg, type === 'devDependencies')
191+
await pm.add(arg, {
192+
tilde: !range && isPlugin(id),
193+
dev: type === 'devDependencies'
194+
})
192195

193196
logs.add({
194197
message: `Dependency ${id} installed`,

packages/@vue/cli/lib/Creator.js

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ const {
2727
const {
2828
chalk,
2929
execa,
30-
semver,
3130

3231
log,
3332
warn,
@@ -129,19 +128,9 @@ module.exports = class Creator extends EventEmitter {
129128
logWithSpinner(`✨`, `Creating project in ${chalk.yellow(context)}.`)
130129
this.emit('creation', { event: 'creating' })
131130

132-
// get latest CLI version
133-
const { current, latest } = await getVersions()
134-
let latestMinor = `${semver.major(latest)}.${semver.minor(latest)}.0`
135-
136-
if (
137-
// if the latest version contains breaking changes
138-
/major/.test(semver.diff(current, latest)) ||
139-
// or if using `next` branch of cli
140-
(semver.gte(current, latest) && semver.prerelease(current))
141-
) {
142-
// fallback to the current cli version number
143-
latestMinor = current
144-
}
131+
// get latest CLI plugin version
132+
const { latestMinor } = await getVersions()
133+
145134
// generate package.json with plugin dependencies
146135
const pkg = {
147136
name,
@@ -161,7 +150,7 @@ module.exports = class Creator extends EventEmitter {
161150
// Other `@vue/*` packages' version may not be in sync with the cli itself.
162151
pkg.devDependencies[dep] = (
163152
preset.plugins[dep].version ||
164-
((/^@vue/.test(dep)) ? `^${latestMinor}` : `latest`)
153+
((/^@vue/.test(dep)) ? `~${latestMinor}` : `latest`)
165154
)
166155
})
167156

packages/@vue/cli/lib/Upgrader.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ module.exports = class Upgrader {
9393
if (targetVersion === installed) {
9494
log(`Already installed ${packageName}@${targetVersion}`)
9595

96-
const newRange = tryGetNewerRange(`^${targetVersion}`, required)
96+
const newRange = tryGetNewerRange(`~${targetVersion}`, required)
9797
if (newRange !== required) {
9898
this.pkg[depEntry][packageName] = newRange
9999
fs.writeFileSync(path.resolve(this.context, 'package.json'), JSON.stringify(this.pkg, null, 2))
@@ -103,10 +103,10 @@ module.exports = class Upgrader {
103103
}
104104

105105
log(`Upgrading ${packageName} from ${installed} to ${targetVersion}`)
106-
await this.pm.upgrade(`${packageName}@^${targetVersion}`)
106+
await this.pm.upgrade(`${packageName}@~${targetVersion}`)
107107

108108
// the cached `pkg` field won't automatically update after running `this.pm.upgrade`
109-
this.pkg[depEntry][packageName] = `^${targetVersion}`
109+
this.pkg[depEntry][packageName] = `~${targetVersion}`
110110
const pluginMigrator = loadModule(`${packageName}/migrator`, this.context)
111111

112112
if (pluginMigrator) {

packages/@vue/cli/lib/add.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const {
77
loadModule
88
} = require('@vue/cli-shared-utils')
99

10+
const getVersions = require('./util/getVersions')
1011
const PackageManager = require('./util/ProjectPackageManager')
1112
const {
1213
log,
@@ -40,12 +41,12 @@ async function add (pluginName, options = {}, context = process.cwd()) {
4041
log()
4142

4243
const pm = new PackageManager({ context })
44+
const { latestMinor } = await getVersions()
4345

44-
const cliVersion = require('../package.json').version
45-
if (isOfficialPlugin(packageName) && semver.prerelease(cliVersion)) {
46-
await pm.add(`${packageName}@^${cliVersion}`)
46+
if (isOfficialPlugin(packageName)) {
47+
await pm.add(`${packageName}@~${latestMinor}`)
4748
} else {
48-
await pm.add(packageName)
49+
await pm.add(packageName, { tilde: true })
4950
}
5051

5152
log(`${chalk.green('✔')} Successfully installed plugin: ${chalk.cyan(packageName)}`)

packages/@vue/cli/lib/util/ProjectPackageManager.js

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -235,36 +235,48 @@ class PackageManager {
235235
} catch (e) {}
236236
}
237237

238-
async runCommand (args) {
238+
async runCommand (command, args) {
239239
await this.setRegistryEnvs()
240-
await executeCommand(this.bin, args, this.context)
240+
return await executeCommand(
241+
this.bin,
242+
[
243+
...PACKAGE_MANAGER_CONFIG[this.bin][command],
244+
...(args || [])
245+
],
246+
this.context
247+
)
241248
}
242249

243250
async install () {
244251
if (process.env.VUE_CLI_TEST) {
245252
try {
246-
await this.runCommand([PACKAGE_MANAGER_CONFIG[this.bin].install, '--offline'])
253+
await this.runCommand('install', ['--offline'])
247254
} catch (e) {
248-
await this.runCommand([PACKAGE_MANAGER_CONFIG[this.bin].install])
255+
await this.runCommand('install')
249256
}
250257
}
251258

252-
return this.runCommand([PACKAGE_MANAGER_CONFIG[this.bin].install])
259+
return await this.runCommand('install')
253260
}
254261

255-
async add (packageName, isDev = true) {
256-
return this.runCommand([
257-
...PACKAGE_MANAGER_CONFIG[this.bin].add,
258-
packageName,
259-
...(isDev ? ['-D'] : [])
260-
])
262+
async add (packageName, {
263+
tilde = false,
264+
dev = true
265+
} = {}) {
266+
const args = dev ? ['-D'] : []
267+
if (tilde) {
268+
if (this.bin === 'yarn') {
269+
args.push('--tilde')
270+
} else {
271+
process.env.npm_config_save_prefix = '~'
272+
}
273+
}
274+
275+
return await this.runCommand('add', [packageName, ...args])
261276
}
262277

263278
async remove (packageName) {
264-
return this.runCommand([
265-
...PACKAGE_MANAGER_CONFIG[this.bin].remove,
266-
packageName
267-
])
279+
return await this.runCommand('remove', [packageName])
268280
}
269281

270282
async upgrade (packageName) {
@@ -281,10 +293,7 @@ class PackageManager {
281293
return
282294
}
283295

284-
return this.runCommand([
285-
...PACKAGE_MANAGER_CONFIG[this.bin].add,
286-
packageName
287-
])
296+
return await this.runCommand('add', [packageName])
288297
}
289298
}
290299

packages/@vue/cli/lib/util/getVersions.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ module.exports = async function getVersions () {
1515
if (process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG) {
1616
return (sessionCached = {
1717
current: local,
18-
latest: local
18+
latest: local,
19+
latestMinor: local
1920
})
2021
}
2122

@@ -44,9 +45,21 @@ module.exports = async function getVersions () {
4445
latest = cached
4546
}
4647

48+
let latestMinor = `${semver.major(latest)}.${semver.minor(latest)}.0`
49+
if (
50+
// if the latest version contains breaking changes
51+
/major/.test(semver.diff(local, latest)) ||
52+
// or if using `next` branch of cli
53+
(semver.gte(local, latest) && semver.prerelease(local))
54+
) {
55+
// fallback to the local cli version number
56+
latestMinor = local
57+
}
58+
4759
return (sessionCached = {
4860
current: local,
4961
latest,
62+
latestMinor,
5063
error
5164
})
5265
}

0 commit comments

Comments
 (0)