Skip to content

feat: support PNPM as a package manager #1531

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

Merged
merged 3 commits into from
Apr 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/@vue/cli-service/lib/commands/serve.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {
info,
hasProjectYarn,
hasPnpm,
openBrowser,
IpcMessenger
} = require('@vue/cli-shared-utils')
Expand Down Expand Up @@ -234,7 +235,7 @@ module.exports = (api, options) => {
isFirstCompile = false

if (!isProduction) {
const buildCommand = hasProjectYarn(api.getCwd()) ? `yarn build` : `npm run build`
const buildCommand = hasProjectYarn(api.getCwd()) ? `yarn build` : hasPnpm() ? `pnpm run build` : `npm run build`
console.log(` Note that the development build is not optimized.`)
console.log(` To create a production build, run ${chalk.cyan(buildCommand)}.`)
} else {
Expand Down
21 changes: 21 additions & 0 deletions packages/@vue/cli-shared-utils/lib/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { execSync } = require('child_process')
const fs = require('fs')
const path = require('path')
const LRU = require('lru-cache')
const semver = require('semver')

let _hasYarn
const _yarnProjects = new LRU({
Expand All @@ -13,6 +14,7 @@ const _gitProjects = new LRU({
max: 10,
maxAge: 1000
})
let _hasPnpm

// env detection
exports.hasYarn = () => {
Expand Down Expand Up @@ -77,6 +79,25 @@ exports.hasProjectGit = (cwd) => {
return result
}

exports.hasPnpm = () => {
if (process.env.VUE_CLI_TEST) {
return true
}
if (_hasPnpm != null) {
return _hasPnpm
}
try {
const pnpmVersion = execSync('pnpm --version').toString()
// there's a critical bug in pnpm 2
// https://github.com/pnpm/pnpm/issues/1678#issuecomment-469981972
// so we only support pnpm >= 3.0.0
_hasPnpm = semver.gte(pnpmVersion, '3.0.0')
return _hasPnpm
} catch (e) {
return (_hasPnpm = false)
}
}

// OS
exports.isWindows = process.platform === 'win32'
exports.isMacintosh = process.platform === 'darwin'
Expand Down
1 change: 1 addition & 0 deletions packages/@vue/cli-ui/apollo-server/type-defs.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ scalar JSON
enum PackageManager {
npm
yarn
pnpm
}

interface DescribedEntity {
Expand Down
7 changes: 4 additions & 3 deletions packages/@vue/cli-ui/apollo-server/util/command.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const {
hasYarn,
hasProjectYarn
hasProjectYarn,
hasPnpm
} = require('@vue/cli-shared-utils')
const { loadOptions } = require('@vue/cli/lib/options')

exports.getCommand = function (cwd = undefined) {
if (!cwd) {
return loadOptions().packageManager || (hasYarn() ? 'yarn' : 'npm')
return loadOptions().packageManager || (hasYarn() ? 'yarn' : hasPnpm() ? 'pnpm' : 'npm')
}
return hasProjectYarn(cwd) ? 'yarn' : 'npm'
return hasProjectYarn(cwd) ? 'yarn' : hasPnpm() ? 'pnpm' : 'npm'
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@
value="yarn"
label="yarn"
/>
<VueSelectButton
value="pnpm"
label="pnpm"
/>
</VueSelect>
</VueFormField>

Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/cli/__tests__/Creator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ test('default', async () => {
},
{
message: 'package manager',
choices: ['Yarn', 'NPM'],
choices: ['Yarn', 'PNPM', 'NPM'],
choose: 0
}
]
Expand Down
45 changes: 30 additions & 15 deletions packages/@vue/cli/lib/Creator.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const {
hasGit,
hasProjectGit,
hasYarn,
hasPnpm,
logWithSpinner,
stopSpinner,
exit,
Expand Down Expand Up @@ -97,7 +98,8 @@ module.exports = class Creator extends EventEmitter {
const packageManager = (
cliOptions.packageManager ||
loadOptions().packageManager ||
(hasYarn() ? 'yarn' : 'npm')
(hasYarn() ? 'yarn' : null) ||
(hasPnpm() ? 'pnpm' : 'npm')
)

await clearConsole()
Expand Down Expand Up @@ -214,7 +216,7 @@ module.exports = class Creator extends EventEmitter {
log(
`👉 Get started with the following commands:\n\n` +
(this.context === process.cwd() ? `` : chalk.cyan(` ${chalk.gray('$')} cd ${name}\n`)) +
chalk.cyan(` ${chalk.gray('$')} ${packageManager === 'yarn' ? 'yarn serve' : 'npm run serve'}`)
chalk.cyan(` ${chalk.gray('$')} ${packageManager === 'yarn' ? 'yarn serve' : packageManager === 'pnpm' ? 'pnpm run serve' : 'npm run serve'}`)
)
}
log()
Expand Down Expand Up @@ -410,23 +412,36 @@ module.exports = class Creator extends EventEmitter {

// ask for packageManager once
const savedOptions = loadOptions()
if (!savedOptions.packageManager && hasYarn()) {
if (!savedOptions.packageManager && (hasYarn() || hasPnpm())) {
const packageManagerChoices = []

if (hasYarn()) {
packageManagerChoices.push({
name: 'Use Yarn',
value: 'yarn',
short: 'Yarn'
})
}

if (hasPnpm()) {
packageManagerChoices.push({
name: 'Use PNPM',
value: 'pnpm',
short: 'PNPM'
})
}

packageManagerChoices.push({
name: 'Use NPM',
value: 'npm',
short: 'NPM'
})

outroPrompts.push({
name: 'packageManager',
type: 'list',
message: 'Pick the package manager to use when installing dependencies:',
choices: [
{
name: 'Use Yarn',
value: 'yarn',
short: 'Yarn'
},
{
name: 'Use NPM',
value: 'npm',
short: 'NPM'
}
]
choices: packageManagerChoices
})
}

Expand Down
3 changes: 2 additions & 1 deletion packages/@vue/cli/lib/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const {
log,
error,
hasProjectYarn,
hasPnpm,
resolvePluginId,
resolveModule,
loadModule
Expand All @@ -26,7 +27,7 @@ async function add (pluginName, options = {}, context = process.cwd()) {
log(`📦 Installing ${chalk.cyan(packageName)}...`)
log()

const packageManager = loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : 'npm')
const packageManager = loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : hasPnpm() ? 'pnpm' : 'npm')
await installPackage(context, packageManager, options.registry, packageName)

log(`${chalk.green('✔')} Successfully installed plugin: ${chalk.cyan(packageName)}`)
Expand Down
3 changes: 2 additions & 1 deletion packages/@vue/cli/lib/invoke.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
error,
hasProjectYarn,
hasProjectGit,
hasPnpm,
logWithSpinner,
stopSpinner,
resolvePluginId,
Expand Down Expand Up @@ -138,7 +139,7 @@ async function runGenerator (context, plugin, pkg = getPkg(context)) {
log(`📦 Installing additional dependencies...`)
log()
const packageManager =
loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : 'npm')
loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : hasPnpm() ? 'pnpm' : 'npm')
await installDeps(context, packageManager, plugin.options && plugin.options.registry)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/cli/lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const presetSchema = createSchema(joi => joi.object().keys({
const schema = createSchema(joi => joi.object().keys({
latestVersion: joi.string().regex(/^\d+\.\d+\.\d+$/),
lastChecked: joi.date().timestamp(),
packageManager: joi.string().only(['yarn', 'npm']),
packageManager: joi.string().only(['yarn', 'npm', 'pnpm']),
useTaobaoRegistry: joi.boolean(),
presets: joi.object().pattern(/^/, presetSchema)
}))
Expand Down
10 changes: 5 additions & 5 deletions packages/@vue/cli/lib/util/installDeps.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const debug = require('debug')('vue-cli:install')

const taobaoDistURL = 'https://npm.taobao.org/dist'

const supportPackageManagerList = ['npm', 'yarn']
const supportPackageManagerList = ['npm', 'yarn', 'pnpm']

class InstallProgress extends EventEmitter {
constructor () {
Expand Down Expand Up @@ -176,7 +176,7 @@ exports.installDeps = async function installDeps (targetDir, command, cliRegistr

const args = []

if (command === 'npm') {
if (command === 'npm' || command === 'pnpm') {
args.push('install', '--loglevel', 'error')
} else if (command === 'yarn') {
// do nothing
Expand All @@ -195,7 +195,7 @@ exports.installPackage = async function (targetDir, command, cliRegistry, packag

const args = []

if (command === 'npm') {
if (command === 'npm' || command === 'pnpm') {
args.push('install', '--loglevel', 'error')
} else if (command === 'yarn') {
args.push('add')
Expand All @@ -218,7 +218,7 @@ exports.uninstallPackage = async function (targetDir, command, cliRegistry, pack

const args = []

if (command === 'npm') {
if (command === 'npm' || command === 'pnpm') {
args.push('uninstall', '--loglevel', 'error')
} else if (command === 'yarn') {
args.push('remove')
Expand All @@ -239,7 +239,7 @@ exports.updatePackage = async function (targetDir, command, cliRegistry, package

const args = []

if (command === 'npm') {
if (command === 'npm' || command === 'pnpm') {
args.push('update', '--loglevel', 'error')
} else if (command === 'yarn') {
args.push('upgrade')
Expand Down
9 changes: 7 additions & 2 deletions packages/@vue/cli/lib/util/loadCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ module.exports = function loadCommand (commandName, moduleName) {
} catch (err2) {
if (isNotFoundError(err2)) {
const chalk = require('chalk')
const { hasYarn } = require('@vue/cli-shared-utils')
const installCommand = hasYarn() ? `yarn global add` : `npm install -g`
const { hasYarn, hasPnpm } = require('@vue/cli-shared-utils')
let installCommand = `npm install -g`
if (hasYarn()) {
installCommand = `yarn global add`
} else if (hasPnpm()) {
installCommand = `pnpm install -g`
}
console.log()
console.log(
` Command ${chalk.cyan(`vue ${commandName}`)} requires a global addon to be installed.\n` +
Expand Down
3 changes: 2 additions & 1 deletion packages/@vue/cli/lib/util/registries.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const registries = {
npm: 'https://registry.npmjs.org',
yarn: 'https://registry.yarnpkg.com',
taobao: 'https://registry.npm.taobao.org'
taobao: 'https://registry.npm.taobao.org',
pnpm: 'https://registry.npmjs.org'
}

module.exports = registries