diff --git a/packages/@vue/cli/__tests__/Generator.spec.js b/packages/@vue/cli/__tests__/Generator.spec.js index 8e169b3e43..452582ee72 100644 --- a/packages/@vue/cli/__tests__/Generator.spec.js +++ b/packages/@vue/cli/__tests__/Generator.spec.js @@ -658,6 +658,54 @@ test('api: afterInvoke', async () => { expect(cbs).toContain(fn) }) +test('api: afterAnyInvoke and afterInvoke in hooks', async () => { + const fooAnyInvokeHandler = () => {} + const fooInvokeHandler = () => {} + const barAnyInvokeHandler = () => {} + const barInvokeHandler = () => {} + + const getGeneratorFn = (invokeHandler, anyInvokeHandler) => { + const generatorFn = () => {} + generatorFn.hooks = api => { + api.afterInvoke(invokeHandler) + api.afterAnyInvoke(anyInvokeHandler) + } + return generatorFn + } + + jest.doMock('vue-cli-plugin-foo-hooks/generator', () => { + return getGeneratorFn(fooInvokeHandler, fooAnyInvokeHandler) + }, { virtual: true }) + + jest.doMock('vue-cli-plugin-bar-hooks/generator', () => { + return getGeneratorFn(barInvokeHandler, barAnyInvokeHandler) + }, { virtual: true }) + + const afterAnyInvokeCbs = [] + const afterInvokeCbs = [] + const generator = new Generator('/', { + pkg: { + devDependencies: { + 'vue-cli-plugin-foo-hooks': '1.0.0', + 'vue-cli-plugin-bar-hooks': '1.0.0' + } + }, + plugins: [ + { + id: 'vue-cli-plugin-foo-hooks', + apply: getGeneratorFn(fooInvokeHandler, fooAnyInvokeHandler) + } + ], + afterInvokeCbs, + afterAnyInvokeCbs + }) + + await generator.generate() + + expect(afterAnyInvokeCbs).toEqual([fooAnyInvokeHandler, barAnyInvokeHandler]) + expect(afterInvokeCbs).toEqual([fooInvokeHandler]) +}) + test('api: resolve', () => { new Generator('/foo/bar', { plugins: [ { diff --git a/packages/@vue/cli/lib/Generator.js b/packages/@vue/cli/lib/Generator.js index 929998ee18..5b292424dd 100644 --- a/packages/@vue/cli/lib/Generator.js +++ b/packages/@vue/cli/lib/Generator.js @@ -90,9 +90,7 @@ module.exports = class Generator { this.pm = new PackageManager({ context }) this.imports = {} this.rootOptions = {} - // we don't load the passed afterInvokes yet because we want to ignore them from other plugins - this.passedAfterInvokeCbs = afterInvokeCbs - this.afterInvokeCbs = [] + this.afterInvokeCbs = afterInvokeCbs this.afterAnyInvokeCbs = afterAnyInvokeCbs this.configTransforms = {} this.defaultConfigTransforms = defaultConfigTransforms @@ -124,7 +122,10 @@ module.exports = class Generator { const { rootOptions, invoking } = this const pluginIds = this.plugins.map(p => p.id) - // apply hooks from all plugins + // avoid modifying the passed afterInvokes, because we want to ignore them from other plugins + const passedAfterInvokeCbs = this.afterInvokeCbs + this.afterInvokeCbs = [] + // apply hooks from all plugins to collect 'afterAnyHooks' for (const id of this.allPluginIds) { const api = new GeneratorAPI(id, this, {}, rootOptions) const pluginGenerator = loadModule(`${id}/generator`, this.context) @@ -139,7 +140,7 @@ module.exports = class Generator { const afterAnyInvokeCbsFromPlugins = this.afterAnyInvokeCbs // reset hooks - this.afterInvokeCbs = this.passedAfterInvokeCbs + this.afterInvokeCbs = passedAfterInvokeCbs this.afterAnyInvokeCbs = [] this.postProcessFilesCbs = [] @@ -155,10 +156,9 @@ module.exports = class Generator { // because `afterAnyHooks` is already determined by the `allPluginIds` loop above await apply.hooks(api, options, rootOptions, pluginIds) } - - // restore "any" hooks - this.afterAnyInvokeCbs = afterAnyInvokeCbsFromPlugins } + // restore "any" hooks + this.afterAnyInvokeCbs = afterAnyInvokeCbsFromPlugins } async generate ({