From b247942c6069e54a74a94ec7aebd24e6005967ff Mon Sep 17 00:00:00 2001 From: fangbinwei Date: Wed, 28 Oct 2020 00:35:32 +0800 Subject: [PATCH 1/2] fix(generator): avoid doing redundant write operations avoid overwriting the file which is not modified when executing `vue add/invoke` re #5939 --- packages/@vue/cli/__tests__/Generator.spec.js | 46 +++++++++++++++++++ packages/@vue/cli/lib/Generator.js | 26 ++++++++++- packages/@vue/cli/lib/util/writeFileTree.js | 10 +++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/packages/@vue/cli/__tests__/Generator.spec.js b/packages/@vue/cli/__tests__/Generator.spec.js index 8e169b3e43..8dc178e36f 100644 --- a/packages/@vue/cli/__tests__/Generator.spec.js +++ b/packages/@vue/cli/__tests__/Generator.spec.js @@ -885,6 +885,52 @@ test('api: addConfigTransform transform vue warn', async () => { })).toBe(true) }) +test('avoid overwriting existing files if it is not modified', async () => { + const generator = new Generator('/', { + plugins: [ + { + id: 'test1', + apply: (api, options) => { + api.render((files, render) => { + files['foo.js'] = render('foo()') + }) + } + } + ], + files: { + // skip writing to this file + 'existFile.js': 'existFile()' + } + }) + + await generator.generate() + + expect(fs.readFileSync('/foo.js', 'utf-8')).toMatch('foo()') + expect(fs.existsSync('/existFile.js')).toBe(false) +}) + +test('overwrite existing file if it is modified', async () => { + const generator = new Generator('/', { + plugins: [ + { + id: 'test1', + apply: (api, options) => { + api.render((files, render) => { + files['existFile.js'] = render('foo()') + }) + } + } + ], + files: { + 'existFile.js': 'existFile()' + } + }) + + await generator.generate() + + expect(fs.readFileSync('/existFile.js', 'utf-8')).toMatch('foo()') +}) + test('extract config files', async () => { const configs = { vue: { diff --git a/packages/@vue/cli/lib/Generator.js b/packages/@vue/cli/lib/Generator.js index 929998ee18..162eca39a3 100644 --- a/packages/@vue/cli/lib/Generator.js +++ b/packages/@vue/cli/lib/Generator.js @@ -74,6 +74,24 @@ const ensureEOL = str => { return str } +/** + * Collect created/modified files into set + * @param {Record} files + * @param {Set} set + */ +const watchFiles = (files, set) => { + return new Proxy(files, { + set (target, key, value, receiver) { + set.add(key) + return Reflect.set(target, key, value, receiver) + }, + deleteProperty (target, key) { + set.delete(key) + return Reflect.deleteProperty(target, key) + } + }) +} + module.exports = class Generator { constructor (context, { pkg = {}, @@ -101,7 +119,11 @@ module.exports = class Generator { // for conflict resolution this.depSources = {} // virtual file tree - this.files = files + this.files = Object.keys(files).length + // when execute `vue add/invoke`, only created/modified files are written to disk + ? watchFiles(files, this.filesModifyRecord = new Set()) + // all files need to be written to disk + : files this.fileMiddlewares = [] this.postProcessFilesCbs = [] // exit messages @@ -177,7 +199,7 @@ module.exports = class Generator { this.sortPkg() this.files['package.json'] = JSON.stringify(this.pkg, null, 2) + '\n' // write/update file tree to disk - await writeFileTree(this.context, this.files, initialFiles) + await writeFileTree(this.context, this.files, initialFiles, this.filesModifyRecord) } extractConfigFiles (extractAll, checkExisting) { diff --git a/packages/@vue/cli/lib/util/writeFileTree.js b/packages/@vue/cli/lib/util/writeFileTree.js index 5eff5acde0..270080a511 100644 --- a/packages/@vue/cli/lib/util/writeFileTree.js +++ b/packages/@vue/cli/lib/util/writeFileTree.js @@ -12,7 +12,14 @@ function deleteRemovedFiles (directory, newFiles, previousFiles) { })) } -module.exports = async function writeFileTree (dir, files, previousFiles) { +/** + * + * @param {string} dir + * @param {Record} files + * @param {Record} previousFiles + * @param {Set} [include] + */ +module.exports = async function writeFileTree (dir, files, previousFiles, include) { if (process.env.VUE_CLI_SKIP_WRITE) { return } @@ -20,6 +27,7 @@ module.exports = async function writeFileTree (dir, files, previousFiles) { await deleteRemovedFiles(dir, files, previousFiles) } Object.keys(files).forEach((name) => { + if (include && !include.has(name)) return const filePath = path.join(dir, name) fs.ensureDirSync(path.dirname(filePath)) fs.writeFileSync(filePath, files[name]) From 189677ed0011a65034ce5b42033d18f07cf0ed73 Mon Sep 17 00:00:00 2001 From: fangbinwei Date: Wed, 28 Oct 2020 22:02:46 +0800 Subject: [PATCH 2/2] refactor: comment fix --- packages/@vue/cli/__tests__/Generator.spec.js | 4 ++-- packages/@vue/cli/lib/util/writeFileTree.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@vue/cli/__tests__/Generator.spec.js b/packages/@vue/cli/__tests__/Generator.spec.js index 8dc178e36f..0c48acb457 100644 --- a/packages/@vue/cli/__tests__/Generator.spec.js +++ b/packages/@vue/cli/__tests__/Generator.spec.js @@ -885,7 +885,7 @@ test('api: addConfigTransform transform vue warn', async () => { })).toBe(true) }) -test('avoid overwriting existing files if it is not modified', async () => { +test('avoid overwriting files that have not been modified', async () => { const generator = new Generator('/', { plugins: [ { @@ -909,7 +909,7 @@ test('avoid overwriting existing files if it is not modified', async () => { expect(fs.existsSync('/existFile.js')).toBe(false) }) -test('overwrite existing file if it is modified', async () => { +test('overwrite files that have been modified', async () => { const generator = new Generator('/', { plugins: [ { diff --git a/packages/@vue/cli/lib/util/writeFileTree.js b/packages/@vue/cli/lib/util/writeFileTree.js index 270080a511..4d06449c5e 100644 --- a/packages/@vue/cli/lib/util/writeFileTree.js +++ b/packages/@vue/cli/lib/util/writeFileTree.js @@ -16,7 +16,7 @@ function deleteRemovedFiles (directory, newFiles, previousFiles) { * * @param {string} dir * @param {Record} files - * @param {Record} previousFiles + * @param {Record} [previousFiles] * @param {Set} [include] */ module.exports = async function writeFileTree (dir, files, previousFiles, include) {