From d52cbf93d490d7e4b9be07b2cbc7efa29ef4b128 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Fri, 17 Jan 2020 14:47:20 +0800 Subject: [PATCH 1/8] refactor(migrator): rename `installed` to `baseVersion` --- packages/@vue/cli/lib/Migrator.js | 2 +- packages/@vue/cli/lib/MigratorAPI.js | 6 +++--- packages/@vue/cli/lib/Upgrader.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/@vue/cli/lib/Migrator.js b/packages/@vue/cli/lib/Migrator.js index 8bc1caf86c..58b506fffa 100644 --- a/packages/@vue/cli/lib/Migrator.js +++ b/packages/@vue/cli/lib/Migrator.js @@ -28,7 +28,7 @@ module.exports = class Migrator extends Generator { // apply migrators from plugins const api = new MigratorAPI( plugin.id, - plugin.installed, + plugin.baseVersion, this, plugin.options, this.rootOptions diff --git a/packages/@vue/cli/lib/MigratorAPI.js b/packages/@vue/cli/lib/MigratorAPI.js index 74c3e60112..78cef506ae 100644 --- a/packages/@vue/cli/lib/MigratorAPI.js +++ b/packages/@vue/cli/lib/MigratorAPI.js @@ -8,15 +8,15 @@ class MigratorAPI extends GeneratorAPI { * @param {object} options - options passed to this plugin * @param {object} rootOptions - root options (the entire preset) */ - constructor (id, installedVersion, migrator, options, rootOptions) { + constructor (id, baseVersion, migrator, options, rootOptions) { super(id, migrator, options, rootOptions) - this.installedVersion = installedVersion + this.baseVersion = baseVersion this.migrator = this.generator } fromVersion (range) { - return semver.satisfies(this.installedVersion, range) + return semver.satisfies(this.baseVersion, range) } } diff --git a/packages/@vue/cli/lib/Upgrader.js b/packages/@vue/cli/lib/Upgrader.js index a1a2c35f02..ba8d9e1820 100644 --- a/packages/@vue/cli/lib/Upgrader.js +++ b/packages/@vue/cli/lib/Upgrader.js @@ -102,7 +102,7 @@ module.exports = class Upgrader { // the cached `pkg` field won't automatically update after running `this.pm.upgrade` this.pkg[depEntry][packageName] = `^${targetVersion}` - await this.runMigrator(packageName, { installed }) + await this.runMigrator(packageName, { baseVersion: installed }) } async runMigrator (packageName, options) { @@ -112,7 +112,7 @@ module.exports = class Upgrader { const plugin = { id: packageName, apply: pluginMigrator, - installed: options.installed + baseVersion: options.baseVersion } const afterInvokeCbs = [] From 330955747d7a5a899906690fff3956d373f25b92 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sat, 18 Jan 2020 15:30:17 +0800 Subject: [PATCH 2/8] feat: `vue upgrade --from` option and a new `vue migrate` command --- packages/@vue/cli/bin/vue.js | 12 +++- packages/@vue/cli/lib/Upgrader.js | 93 ++++++------------------- packages/@vue/cli/lib/migrate.js | 109 ++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 74 deletions(-) create mode 100644 packages/@vue/cli/lib/migrate.js diff --git a/packages/@vue/cli/bin/vue.js b/packages/@vue/cli/bin/vue.js index 1ebd3cad4a..3d5fc86e6c 100755 --- a/packages/@vue/cli/bin/vue.js +++ b/packages/@vue/cli/bin/vue.js @@ -177,7 +177,8 @@ program program .command('upgrade [plugin-name]') .description('(experimental) upgrade vue cli service / plugins') - .option('-t, --to ', 'upgrade to a version that is not latest') + .option('-t, --to ', 'Upgrade to a version that is not latest') + .option('-f, --from ', 'Skip probing installed plugin, assuming it is upgraded from the designated version') .option('-r, --registry ', 'Use specified npm registry when installing dependencies') .option('--all', 'Upgrade all plugins') .option('--next', 'Also check for alpha / beta / rc versions when upgrading') @@ -185,6 +186,15 @@ program require('../lib/upgrade')(packageName, cleanArgs(cmd)) }) +program + .command('migrate [plugin-name]') + .description('(experimental) run migrator for an already-installed cli plugin') + // TODO: use `requiredOption` after upgrading to commander 4.x + .option('-f, --from ', 'The base version for the migrator to migrate from') + .action((packageName, cmd) => { + require('../lib/migrate')(packageName, cleanArgs(cmd)) + }) + program .command('info') .description('print debugging information about your environment') diff --git a/packages/@vue/cli/lib/Upgrader.js b/packages/@vue/cli/lib/Upgrader.js index ba8d9e1820..2b7f4f3aa2 100644 --- a/packages/@vue/cli/lib/Upgrader.js +++ b/packages/@vue/cli/lib/Upgrader.js @@ -11,18 +11,15 @@ const { isPlugin, resolvePluginId, + loadModule } = require('@vue/cli-shared-utils') -const Migrator = require('./Migrator') const tryGetNewerRange = require('./util/tryGetNewerRange') -const readFiles = require('./util/readFiles') -const getChangedFiles = require('./util/getChangedFiles') - const getPackageJson = require('./util/getPackageJson') const PackageManager = require('./util/ProjectPackageManager') -const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG +const { runMigrator } = require('./migrate') module.exports = class Upgrader { constructor (context = process.cwd()) { @@ -65,6 +62,14 @@ module.exports = class Upgrader { throw new Error(`Can't find ${chalk.yellow(packageName)} in ${chalk.yellow('package.json')}`) } + const installed = options.from || this.pm.getInstalledVersion(packageName) + if (installed === 'N/A') { + throw new Error( + `Can't find ${chalk.yellow(packageName)} in ${chalk.yellow('node_modules')}. Please install the dependencies first.\n` + + `Or to force upgrade, you can specify your current plugin version with the ${chalk.cyan('--from')} option` + ) + } + let targetVersion = options.to || 'latest' // if the targetVersion is not an exact version if (!/\d+\.\d+\.\d+/.test(targetVersion)) { @@ -84,7 +89,6 @@ module.exports = class Upgrader { stopSpinner() } - const installed = this.pm.getInstalledVersion(packageName) if (targetVersion === installed) { log(`Already installed ${packageName}@${targetVersion}`) @@ -102,76 +106,19 @@ module.exports = class Upgrader { // the cached `pkg` field won't automatically update after running `this.pm.upgrade` this.pkg[depEntry][packageName] = `^${targetVersion}` - await this.runMigrator(packageName, { baseVersion: installed }) - } - - async runMigrator (packageName, options) { const pluginMigrator = loadModule(`${packageName}/migrator`, this.context) - if (!pluginMigrator) { return } - - const plugin = { - id: packageName, - apply: pluginMigrator, - baseVersion: options.baseVersion - } - - const afterInvokeCbs = [] - const migrator = new Migrator(this.context, { - plugin: plugin, - - pkg: this.pkg, - files: await readFiles(this.context), - afterInvokeCbs, - invoking: true - }) - log(`🚀 Running migrator of ${packageName}`) - await migrator.generate({ - extractConfigFiles: true, - checkExisting: true - }) - - const newDeps = migrator.pkg.dependencies - const newDevDeps = migrator.pkg.devDependencies - const depsChanged = - JSON.stringify(newDeps) !== JSON.stringify(this.pkg.dependencies) || - JSON.stringify(newDevDeps) !== JSON.stringify(this.pkg.devDependencies) - - if (!isTestOrDebug && depsChanged) { - log(`📦 Installing additional dependencies...`) - log() - await this.pm.install() - } - - if (afterInvokeCbs.length) { - logWithSpinner('⚓', `Running completion hooks...`) - for (const cb of afterInvokeCbs) { - await cb() - } - stopSpinner() - log() - } - - log( - `${chalk.green( - '✔' - )} Successfully invoked migrator for plugin: ${chalk.cyan(plugin.id)}` - ) - - const changedFiles = getChangedFiles(this.context) - if (changedFiles.length) { - log(` The following files have been updated / added:\n`) - log(chalk.red(changedFiles.map(line => ` ${line}`).join('\n'))) - log() - log( - ` You should review these changes with ${chalk.cyan( - 'git diff' - )} and commit them.` + if (pluginMigrator) { + await runMigrator( + this.context, + { + id: packageName, + apply: pluginMigrator, + baseVersion: installed + }, + this.pkg ) - log() } - - migrator.printExitLogs() } async getUpgradable (includeNext) { @@ -189,7 +136,7 @@ module.exports = class Upgrader { const wanted = await this.pm.getRemoteVersion(name, range) if (installed === 'N/A') { - throw new Error('At least one dependency is not installed. Please run npm install or yarn before trying to upgrade') + throw new Error(`At least one dependency can't be found. Please install the dependencies before trying to upgrade`) } let latest = await this.pm.getRemoteVersion(name) diff --git a/packages/@vue/cli/lib/migrate.js b/packages/@vue/cli/lib/migrate.js new file mode 100644 index 0000000000..42e1409c7a --- /dev/null +++ b/packages/@vue/cli/lib/migrate.js @@ -0,0 +1,109 @@ +const { + chalk, + + log, + error, + logWithSpinner, + stopSpinner, + + loadModule, + resolvePluginId +} = require('@vue/cli-shared-utils') + +const Migrator = require('./Migrator') +const PackageManager = require('./util/ProjectPackageManager') + +const readFiles = require('./util/readFiles') +const getPackageJson = require('./util/getPackageJson') +const getChangedFiles = require('./util/getChangedFiles') + +const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG + +async function runMigrator (context, plugin, pkg = getPackageJson(context)) { + const afterInvokeCbs = [] + const migrator = new Migrator(context, { + plugin, + pkg, + files: await readFiles(context), + afterInvokeCbs + }) + + log(`🚀 Running migrator of ${plugin.id}`) + await migrator.generate({ + extractConfigFiles: true, + checkExisting: true + }) + + const newDeps = migrator.pkg.dependencies + const newDevDeps = migrator.pkg.devDependencies + const depsChanged = + JSON.stringify(newDeps) !== JSON.stringify(pkg.dependencies) || + JSON.stringify(newDevDeps) !== JSON.stringify(pkg.devDependencies) + if (!isTestOrDebug && depsChanged) { + log(`📦 Installing additional dependencies...`) + log() + + const pm = new PackageManager({ context }) + await pm.install() + } + + if (afterInvokeCbs.length) { + logWithSpinner('⚓', `Running completion hooks...`) + for (const cb of afterInvokeCbs) { + await cb() + } + stopSpinner() + log() + } + + log( + `${chalk.green( + '✔' + )} Successfully invoked migrator for plugin: ${chalk.cyan(plugin.id)}` + ) + + const changedFiles = getChangedFiles(context) + if (changedFiles.length) { + log(` The following files have been updated / added:\n`) + log(chalk.red(changedFiles.map(line => ` ${line}`).join('\n'))) + log() + log( + ` You should review these changes with ${chalk.cyan( + 'git diff' + )} and commit them.` + ) + log() + } + + migrator.printExitLogs() +} + +async function migrate (pluginId, { from }, context = process.cwd()) { + // TODO: remove this after upgrading to commander 4.x + if (!from) { + throw new Error(`Required option 'from' not specified`) + } + + const pluginName = resolvePluginId(pluginId) + const pluginMigrator = loadModule(`${pluginName}/migrator`, context) + if (!pluginMigrator) { + log(`There's no migrator in ${pluginName}`) + return + } + await runMigrator(context, { + id: pluginName, + apply: pluginMigrator, + baseVersion: from + }) +} + +module.exports = (...args) => { + return migrate(...args).catch(err => { + error(err) + if (!process.env.VUE_CLI_TEST) { + process.exit(1) + } + }) +} + +module.exports.runMigrator = runMigrator From 93b897cd37a6c00e7d34977c6e06f43508c17c73 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sat, 18 Jan 2020 22:22:52 +0800 Subject: [PATCH 3/8] fix: fix support for `vuePlugins.resolveFrom` option --- packages/@vue/cli/__tests__/Upgrader.spec.js | 2 ++ packages/@vue/cli/__tests__/invoke.spec.js | 2 ++ packages/@vue/cli/lib/Upgrader.js | 7 ++++--- packages/@vue/cli/lib/invoke.js | 15 +------------ packages/@vue/cli/lib/migrate.js | 4 ++-- .../cli/lib/util/ProjectPackageManager.js | 21 ++++++++++++++++++- packages/@vue/cli/lib/util/getPkg.js | 13 ++++++++++++ 7 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 packages/@vue/cli/lib/util/getPkg.js diff --git a/packages/@vue/cli/__tests__/Upgrader.spec.js b/packages/@vue/cli/__tests__/Upgrader.spec.js index 3b831296de..552187693f 100644 --- a/packages/@vue/cli/__tests__/Upgrader.spec.js +++ b/packages/@vue/cli/__tests__/Upgrader.spec.js @@ -77,3 +77,5 @@ test('upgrade: should add eslint to devDependencies', async () => { const updatedPkg = JSON.parse(await project.read('package.json')) expect(updatedPkg.devDependencies.eslint).toMatch('^4') }) + +test.todo('upgrade: should respect plugin resolveFrom') diff --git a/packages/@vue/cli/__tests__/invoke.spec.js b/packages/@vue/cli/__tests__/invoke.spec.js index e8e2432b1b..cb7f883e86 100644 --- a/packages/@vue/cli/__tests__/invoke.spec.js +++ b/packages/@vue/cli/__tests__/invoke.spec.js @@ -166,3 +166,5 @@ test('should prompt if invoking in a git repository with uncommited changes', as ]) await invoke(`babel`, {}, project.dir) }) + +test.todo('invoke: should respect plugin resolveFrom') diff --git a/packages/@vue/cli/lib/Upgrader.js b/packages/@vue/cli/lib/Upgrader.js index 2b7f4f3aa2..b3381cb7bf 100644 --- a/packages/@vue/cli/lib/Upgrader.js +++ b/packages/@vue/cli/lib/Upgrader.js @@ -16,7 +16,7 @@ const { } = require('@vue/cli-shared-utils') const tryGetNewerRange = require('./util/tryGetNewerRange') -const getPackageJson = require('./util/getPackageJson') +const getPkg = require('./util/getPkg') const PackageManager = require('./util/ProjectPackageManager') const { runMigrator } = require('./migrate') @@ -24,7 +24,7 @@ const { runMigrator } = require('./migrate') module.exports = class Upgrader { constructor (context = process.cwd()) { this.context = context - this.pkg = getPackageJson(this.context) + this.pkg = getPkg(this.context) this.pm = new PackageManager({ context }) } @@ -40,7 +40,8 @@ module.exports = class Upgrader { } for (const p of upgradable) { - this.pkg = getPackageJson(this.context) + // reread to avoid accidentally writing outdated package.json back + this.pkg = getPkg(this.context) await this.upgrade(p.name, { to: p.latest }) } diff --git a/packages/@vue/cli/lib/invoke.js b/packages/@vue/cli/lib/invoke.js index 7062bb9457..7f013138b2 100644 --- a/packages/@vue/cli/lib/invoke.js +++ b/packages/@vue/cli/lib/invoke.js @@ -1,5 +1,3 @@ -const fs = require('fs-extra') -const path = require('path') const inquirer = require('inquirer') const { chalk, @@ -18,21 +16,10 @@ const Generator = require('./Generator') const confirmIfGitDirty = require('./util/confirmIfGitDirty') const readFiles = require('./util/readFiles') +const getPkg = require('./util/getPkg') const getChangedFiles = require('./util/getChangedFiles') const PackageManager = require('./util/ProjectPackageManager') -function getPkg (context) { - const pkgPath = path.resolve(context, 'package.json') - if (!fs.existsSync(pkgPath)) { - throw new Error(`package.json not found in ${chalk.yellow(context)}`) - } - const pkg = fs.readJsonSync(pkgPath) - if (pkg.vuePlugins && pkg.vuePlugins.resolveFrom) { - return getPkg(path.resolve(context, pkg.vuePlugins.resolveFrom)) - } - return pkg -} - async function invoke (pluginName, options = {}, context = process.cwd()) { if (!(await confirmIfGitDirty(context))) { return diff --git a/packages/@vue/cli/lib/migrate.js b/packages/@vue/cli/lib/migrate.js index 42e1409c7a..68475cb733 100644 --- a/packages/@vue/cli/lib/migrate.js +++ b/packages/@vue/cli/lib/migrate.js @@ -14,12 +14,12 @@ const Migrator = require('./Migrator') const PackageManager = require('./util/ProjectPackageManager') const readFiles = require('./util/readFiles') -const getPackageJson = require('./util/getPackageJson') +const getPkg = require('./util/getPkg') const getChangedFiles = require('./util/getChangedFiles') const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG -async function runMigrator (context, plugin, pkg = getPackageJson(context)) { +async function runMigrator (context, plugin, pkg = getPkg(context)) { const afterInvokeCbs = [] const migrator = new Migrator(context, { plugin, diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index 4ea1f8c5b7..04078dde2b 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -16,6 +16,7 @@ const { hasPnpmVersionOrLater, hasProjectPnpm, + isPlugin, isOfficialPlugin, resolvePluginId, @@ -220,7 +221,25 @@ class PackageManager { ) return packageJson.version } catch (e) { - return 'N/A' + if (!isPlugin(packageName)) { + return 'N/A' + } + + // plugin may be located in another location if `resolveFrom` presents + const projectPkg = getPackageJson(this.context) + const resolveFrom = projectPkg.vuePlugins && projectPkg.vuePlugins.resolveFrom + + if (!resolveFrom) { + return 'N/A' + } + + try { + return getPackageJson( + path.resolve(this.context, projectPkg.vuePlugins.resolveFrom, 'node_modules', packageName) + ) + } catch (err) { + return 'N/A' + } } } diff --git a/packages/@vue/cli/lib/util/getPkg.js b/packages/@vue/cli/lib/util/getPkg.js new file mode 100644 index 0000000000..08b8e9f029 --- /dev/null +++ b/packages/@vue/cli/lib/util/getPkg.js @@ -0,0 +1,13 @@ +// Get the package.json containing all the `vue-cli-pluin-*` dependencies +// See issue #1815 + +const path = require('path') +const getPackageJson = require('./getPackageJson') + +module.exports = function getPkg (context) { + const pkg = getPackageJson(context) + if (pkg.vuePlugins && pkg.vuePlugins.resolveFrom) { + return getPackageJson(path.resolve(context, pkg.vuePlugins.resolveFrom)) + } + return pkg +} From 2c393249f6bc3b96b6f399eabf7fbf142c7d6936 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sat, 18 Jan 2020 22:29:26 +0800 Subject: [PATCH 4/8] chore: add a fixme comment --- packages/@vue/cli/lib/util/ProjectPackageManager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index 04078dde2b..f315c849ce 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -213,6 +213,7 @@ class PackageManager { return semver.maxSatisfying(versions, versionRange) } + // FIXME: use `createRequire` instead of hard-coded path getInstalledVersion (packageName) { // for first level deps, read package.json directly is way faster than `npm list` try { From fa4113e7fe52440804b4c2f8b6ad71bb361f6a5c Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sun, 19 Jan 2020 00:21:28 +0800 Subject: [PATCH 5/8] fix: use loadModule instead of manually calculating the package.json path This also fixes support for monorepo. (TODO: tests) --- packages/@vue/cli/lib/Upgrader.js | 6 +++--- .../cli/lib/util/ProjectPackageManager.js | 21 +++++++++---------- packages/@vue/cli/lib/util/getPackageJson.js | 21 ------------------- packages/@vue/cli/lib/util/getPkg.js | 21 ++++++++++++++++++- 4 files changed, 33 insertions(+), 36 deletions(-) delete mode 100644 packages/@vue/cli/lib/util/getPackageJson.js diff --git a/packages/@vue/cli/lib/Upgrader.js b/packages/@vue/cli/lib/Upgrader.js index b3381cb7bf..d5985df596 100644 --- a/packages/@vue/cli/lib/Upgrader.js +++ b/packages/@vue/cli/lib/Upgrader.js @@ -64,7 +64,7 @@ module.exports = class Upgrader { } const installed = options.from || this.pm.getInstalledVersion(packageName) - if (installed === 'N/A') { + if (!installed) { throw new Error( `Can't find ${chalk.yellow(packageName)} in ${chalk.yellow('node_modules')}. Please install the dependencies first.\n` + `Or to force upgrade, you can specify your current plugin version with the ${chalk.cyan('--from')} option` @@ -136,7 +136,7 @@ module.exports = class Upgrader { const installed = await this.pm.getInstalledVersion(name) const wanted = await this.pm.getRemoteVersion(name, range) - if (installed === 'N/A') { + if (!installed) { throw new Error(`At least one dependency can't be found. Please install the dependencies before trying to upgrade`) } @@ -190,7 +190,7 @@ module.exports = class Upgrader { for (const p of upgradable) { const fields = [ p.name, - p.installed, + p.installed || 'N/A', p.wanted, p.latest, `vue upgrade ${p.name}${includeNext ? ' --next' : ''}` diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index f315c849ce..799ef7dab8 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -9,6 +9,7 @@ const { execa, semver, request, + loadModule, hasYarn, hasProjectYarn, @@ -26,7 +27,6 @@ const { } = require('@vue/cli-shared-utils') const { loadOptions } = require('../options') -const getPackageJson = require('./getPackageJson') const { executeCommand } = require('./executeCommand') const registries = require('./registries') @@ -213,33 +213,32 @@ class PackageManager { return semver.maxSatisfying(versions, versionRange) } - // FIXME: use `createRequire` instead of hard-coded path getInstalledVersion (packageName) { // for first level deps, read package.json directly is way faster than `npm list` try { - const packageJson = getPackageJson( - path.resolve(this.context, 'node_modules', packageName) - ) + const packageJson = loadModule(`${packageName}/package.json`, this.context) return packageJson.version } catch (e) { if (!isPlugin(packageName)) { - return 'N/A' + return } // plugin may be located in another location if `resolveFrom` presents - const projectPkg = getPackageJson(this.context) + const projectPkg = loadModule('./package.json', this.context) const resolveFrom = projectPkg.vuePlugins && projectPkg.vuePlugins.resolveFrom if (!resolveFrom) { - return 'N/A' + return } try { - return getPackageJson( - path.resolve(this.context, projectPkg.vuePlugins.resolveFrom, 'node_modules', packageName) + const packageJson = loadModule( + `${packageName}/package.json`, + path.resolve(this.context, resolveFrom) ) + return packageJson.version } catch (err) { - return 'N/A' + return } } } diff --git a/packages/@vue/cli/lib/util/getPackageJson.js b/packages/@vue/cli/lib/util/getPackageJson.js deleted file mode 100644 index 7049cc39e5..0000000000 --- a/packages/@vue/cli/lib/util/getPackageJson.js +++ /dev/null @@ -1,21 +0,0 @@ -const fs = require('fs') -const path = require('path') - -module.exports = function getPackageJson (projectPath) { - const packagePath = path.join(projectPath, 'package.json') - - let packageJson - try { - packageJson = fs.readFileSync(packagePath, 'utf-8') - } catch (err) { - throw new Error(`${packagePath} not exist`) - } - - try { - packageJson = JSON.parse(packageJson) - } catch (err) { - throw new Error('The package.json is malformed') - } - - return packageJson -} diff --git a/packages/@vue/cli/lib/util/getPkg.js b/packages/@vue/cli/lib/util/getPkg.js index 08b8e9f029..2a66980557 100644 --- a/packages/@vue/cli/lib/util/getPkg.js +++ b/packages/@vue/cli/lib/util/getPkg.js @@ -1,8 +1,27 @@ // Get the package.json containing all the `vue-cli-pluin-*` dependencies // See issue #1815 +const fs = require('fs') const path = require('path') -const getPackageJson = require('./getPackageJson') + +function getPackageJson (projectPath) { + const packagePath = path.join(projectPath, 'package.json') + + let packageJson + try { + packageJson = fs.readFileSync(packagePath, 'utf-8') + } catch (err) { + throw new Error(`${packagePath} not exist`) + } + + try { + packageJson = JSON.parse(packageJson) + } catch (err) { + throw new Error('The package.json is malformed') + } + + return packageJson +} module.exports = function getPkg (context) { const pkg = getPackageJson(context) From 6a8885004be4107b3ec5d6c9a5bd9df0d73f59bd Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sun, 19 Jan 2020 12:49:57 +0800 Subject: [PATCH 6/8] fix: treat `resolveFrom` as `context`, fixing edge cases --- .../cli/lib/util/ProjectPackageManager.js | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index 799ef7dab8..9d7bb5fa7c 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -17,7 +17,6 @@ const { hasPnpmVersionOrLater, hasProjectPnpm, - isPlugin, isOfficialPlugin, resolvePluginId, @@ -101,6 +100,17 @@ class PackageManager { ) PACKAGE_MANAGER_CONFIG[this.bin] = PACKAGE_MANAGER_CONFIG.npm } + + try { + // plugin may be located in another location if `resolveFrom` presents + const projectPkg = loadModule('./package.json', this.context) + const resolveFrom = projectPkg.vuePlugins && projectPkg.vuePlugins.resolveFrom + + // Logically, `resolveFrom` and `context` are distinct fields. + // But in Vue CLI we only care about plugins. + // So it is fine to let all other operations take place in the `resolveFrom` directory. + this.context = path.resolve(context, resolveFrom) + } catch (e) {} } // Any command that implemented registry-related feature should support @@ -219,27 +229,6 @@ class PackageManager { const packageJson = loadModule(`${packageName}/package.json`, this.context) return packageJson.version } catch (e) { - if (!isPlugin(packageName)) { - return - } - - // plugin may be located in another location if `resolveFrom` presents - const projectPkg = loadModule('./package.json', this.context) - const resolveFrom = projectPkg.vuePlugins && projectPkg.vuePlugins.resolveFrom - - if (!resolveFrom) { - return - } - - try { - const packageJson = loadModule( - `${packageName}/package.json`, - path.resolve(this.context, resolveFrom) - ) - return packageJson.version - } catch (err) { - return - } } } From fe1dddc730e23b74efd4c2c8481a3b31bd44034a Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sun, 19 Jan 2020 13:56:08 +0800 Subject: [PATCH 7/8] fix: use read-pkg instead of loadModule, avoid messing up require cache --- .../cli/lib/util/ProjectPackageManager.js | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index 9d7bb5fa7c..3e87aa169c 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -9,7 +9,8 @@ const { execa, semver, request, - loadModule, + + resolvePkg, hasYarn, hasProjectYarn, @@ -81,7 +82,7 @@ function stripVersion (packageName) { class PackageManager { constructor ({ context, forcePackageManager } = {}) { - this.context = context + this.context = context || process.cwd() if (forcePackageManager) { this.bin = forcePackageManager @@ -101,16 +102,16 @@ class PackageManager { PACKAGE_MANAGER_CONFIG[this.bin] = PACKAGE_MANAGER_CONFIG.npm } - try { - // plugin may be located in another location if `resolveFrom` presents - const projectPkg = loadModule('./package.json', this.context) - const resolveFrom = projectPkg.vuePlugins && projectPkg.vuePlugins.resolveFrom + // Plugin may be located in another location if `resolveFrom` presents. + const projectPkg = resolvePkg(this.context) + const resolveFrom = projectPkg && projectPkg.vuePlugins && projectPkg.vuePlugins.resolveFrom - // Logically, `resolveFrom` and `context` are distinct fields. - // But in Vue CLI we only care about plugins. - // So it is fine to let all other operations take place in the `resolveFrom` directory. + // Logically, `resolveFrom` and `context` are distinct fields. + // But in Vue CLI we only care about plugins. + // So it is fine to let all other operations take place in the `resolveFrom` directory. + if (resolveFrom) { this.context = path.resolve(context, resolveFrom) - } catch (e) {} + } } // Any command that implemented registry-related feature should support @@ -225,11 +226,8 @@ class PackageManager { getInstalledVersion (packageName) { // for first level deps, read package.json directly is way faster than `npm list` - try { - const packageJson = loadModule(`${packageName}/package.json`, this.context) - return packageJson.version - } catch (e) { - } + const packageJson = resolvePkg(path.resolve(this.context, packageName)) + return packageJson.version } async install () { From 65f70601a0f0c847435b0fbee57a58a0992ebc39 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Sun, 19 Jan 2020 14:11:15 +0800 Subject: [PATCH 8/8] fix: getInstalledVersion still requires `loadModule` to support monorepo --- packages/@vue/cli/lib/util/ProjectPackageManager.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index 3e87aa169c..07853da077 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -11,6 +11,7 @@ const { request, resolvePkg, + loadModule, hasYarn, hasProjectYarn, @@ -226,8 +227,10 @@ class PackageManager { getInstalledVersion (packageName) { // for first level deps, read package.json directly is way faster than `npm list` - const packageJson = resolvePkg(path.resolve(this.context, packageName)) - return packageJson.version + try { + const packageJson = loadModule(`${packageName}/package.json`, this.context, true) + return packageJson.version + } catch (e) {} } async install () {