Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lock minor versions when creating projects / adding plugins #5134

Merged
merged 7 commits into from Feb 4, 2020
Expand Up @@ -188,7 +188,10 @@ function install ({ id, type, range }, context) {
}

const pm = new PackageManager({ context: cwd.get() })
await pm.add(arg, type === 'devDependencies')
await pm.add(arg, {
tilde: !range && isPlugin(id),
dev: type === 'devDependencies'
})

logs.add({
message: `Dependency ${id} installed`,
Expand Down
19 changes: 4 additions & 15 deletions packages/@vue/cli/lib/Creator.js
Expand Up @@ -27,7 +27,6 @@ const {
const {
chalk,
execa,
semver,

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

// get latest CLI version
const { current, latest } = await getVersions()
let latestMinor = `${semver.major(latest)}.${semver.minor(latest)}.0`

if (
// if the latest version contains breaking changes
/major/.test(semver.diff(current, latest)) ||
// or if using `next` branch of cli
(semver.gte(current, latest) && semver.prerelease(current))
) {
// fallback to the current cli version number
latestMinor = current
}
// get latest CLI plugin version
const { latestMinor } = await getVersions()

// generate package.json with plugin dependencies
const pkg = {
name,
Expand All @@ -161,7 +150,7 @@ module.exports = class Creator extends EventEmitter {
// Other `@vue/*` packages' version may not be in sync with the cli itself.
pkg.devDependencies[dep] = (
preset.plugins[dep].version ||
((/^@vue/.test(dep)) ? `^${latestMinor}` : `latest`)
((/^@vue/.test(dep)) ? `~${latestMinor}` : `latest`)
)
})

Expand Down
6 changes: 3 additions & 3 deletions packages/@vue/cli/lib/Upgrader.js
Expand Up @@ -93,7 +93,7 @@ module.exports = class Upgrader {
if (targetVersion === installed) {
log(`Already installed ${packageName}@${targetVersion}`)

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

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

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

if (pluginMigrator) {
Expand Down
9 changes: 5 additions & 4 deletions packages/@vue/cli/lib/add.js
Expand Up @@ -7,6 +7,7 @@ const {
loadModule
} = require('@vue/cli-shared-utils')

const getVersions = require('./util/getVersions')
const PackageManager = require('./util/ProjectPackageManager')
const {
log,
Expand Down Expand Up @@ -40,12 +41,12 @@ async function add (pluginName, options = {}, context = process.cwd()) {
log()

const pm = new PackageManager({ context })
const { latestMinor } = await getVersions()

const cliVersion = require('../package.json').version
if (isOfficialPlugin(packageName) && semver.prerelease(cliVersion)) {
await pm.add(`${packageName}@^${cliVersion}`)
if (isOfficialPlugin(packageName)) {
await pm.add(`${packageName}@~${latestMinor}`)
} else {
await pm.add(packageName)
await pm.add(packageName, { tilde: true })
}

log(`${chalk.green('✔')} Successfully installed plugin: ${chalk.cyan(packageName)}`)
Expand Down
47 changes: 28 additions & 19 deletions packages/@vue/cli/lib/util/ProjectPackageManager.js
Expand Up @@ -235,36 +235,48 @@ class PackageManager {
} catch (e) {}
}

async runCommand (args) {
async runCommand (command, args) {
await this.setRegistryEnvs()
await executeCommand(this.bin, args, this.context)
return await executeCommand(
this.bin,
[
...PACKAGE_MANAGER_CONFIG[this.bin][command],
...(args || [])
],
this.context
)
}

async install () {
if (process.env.VUE_CLI_TEST) {
try {
await this.runCommand([PACKAGE_MANAGER_CONFIG[this.bin].install, '--offline'])
await this.runCommand('install', ['--offline'])
} catch (e) {
await this.runCommand([PACKAGE_MANAGER_CONFIG[this.bin].install])
await this.runCommand('install')
}
}

return this.runCommand([PACKAGE_MANAGER_CONFIG[this.bin].install])
return await this.runCommand('install')
}

async add (packageName, isDev = true) {
return this.runCommand([
...PACKAGE_MANAGER_CONFIG[this.bin].add,
packageName,
...(isDev ? ['-D'] : [])
])
async add (packageName, {
tilde = false,
dev = true
} = {}) {
const args = dev ? ['-D'] : []
if (tilde) {
if (this.bin === 'yarn') {
args.push('--tilde')
} else {
process.env.npm_config_save_prefix = '~'
}
}

return await this.runCommand('add', [packageName, ...args])
}

async remove (packageName) {
return this.runCommand([
...PACKAGE_MANAGER_CONFIG[this.bin].remove,
packageName
])
return await this.runCommand('remove', [packageName])
}

async upgrade (packageName) {
Expand All @@ -281,10 +293,7 @@ class PackageManager {
return
}

return this.runCommand([
...PACKAGE_MANAGER_CONFIG[this.bin].add,
packageName
])
return await this.runCommand('add', [packageName])
}
}

Expand Down
15 changes: 14 additions & 1 deletion packages/@vue/cli/lib/util/getVersions.js
Expand Up @@ -15,7 +15,8 @@ module.exports = async function getVersions () {
if (process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG) {
return (sessionCached = {
current: local,
latest: local
latest: local,
latestMinor: local
})
}

Expand Down Expand Up @@ -44,9 +45,21 @@ module.exports = async function getVersions () {
latest = cached
}

let latestMinor = `${semver.major(latest)}.${semver.minor(latest)}.0`
if (
// if the latest version contains breaking changes
/major/.test(semver.diff(local, latest)) ||
// or if using `next` branch of cli
(semver.gte(local, latest) && semver.prerelease(local))
) {
// fallback to the local cli version number
latestMinor = local
}

return (sessionCached = {
current: local,
latest,
latestMinor,
error
})
}
Expand Down