From a82f8d8b1f68f10ec467f9b8d5f64564e484c87b Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 27 May 2020 16:51:51 +0200 Subject: [PATCH] feat(generator): `export:route` hook and `setPayload` (#7422) * feat(generator): shared payload support for `nuxt export` * feat: add `export:` hooks for upward compatibility * fix: use setPayload to avoid breaking usage * test: update test * fix: deep assign * chore: update tests * fix: route payload has more periority than shared one * test: update generator hook tests * lint: remove unnecessary import --- packages/generator/src/generator.js | 38 ++++++++++++++----- packages/generator/test/__utils__/index.js | 4 ++ packages/generator/test/generator.gen.test.js | 1 - .../generator/test/generator.init.test.js | 19 ++++------ .../generator/test/generator.route.test.js | 11 +++--- test/fixtures/full-static/nuxt.config.js | 17 ++++++++- test/fixtures/full-static/pages/payload.vue | 13 +++++++ 7 files changed, 75 insertions(+), 28 deletions(-) create mode 100644 test/fixtures/full-static/pages/payload.vue diff --git a/packages/generator/src/generator.js b/packages/generator/src/generator.js index 1341859b0b..6f2b3ab710 100644 --- a/packages/generator/src/generator.js +++ b/packages/generator/src/generator.js @@ -2,6 +2,7 @@ import path from 'path' import chalk from 'chalk' import consola from 'consola' import fsExtra from 'fs-extra' +import defu from 'defu' import htmlMinifier from 'html-minifier' import { parse } from 'node-html-parser' @@ -23,6 +24,12 @@ export default class Generator { isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath ) this.generatedRoutes = new Set() + + // Shared payload + this._payload = null + this.setPayload = (payload) => { + this._payload = defu(payload, this._payload) + } } async generate ({ build = true, init = true } = {}) { @@ -47,6 +54,7 @@ export default class Generator { // Done hook await this.nuxt.callHook('generate:done', this, errors) + await this.nuxt.callHook('export:done', this, { errors }) return { errors } } @@ -57,6 +65,7 @@ export default class Generator { // Call before hook await this.nuxt.callHook('generate:before', this, this.options.generate) + await this.nuxt.callHook('export:before', this) if (build) { // Add flag to set process.static @@ -115,6 +124,7 @@ export default class Generator { // extendRoutes hook await this.nuxt.callHook('generate:extendRoutes', routes) + await this.nuxt.callHook('export:extendRoutes', { routes }) return routes } @@ -223,6 +233,7 @@ export default class Generator { consola.info(`Generating output directory: ${path.basename(this.distPath)}/`) await this.nuxt.callHook('generate:distRemoved', this) + await this.nuxt.callHook('export:distCopied', this) // Copy static and built files if (await fsExtra.exists(this.staticRoutes)) { @@ -241,6 +252,7 @@ export default class Generator { fsExtra.writeFile(nojekyllPath, '') await this.nuxt.callHook('generate:distCopied', this) + await this.nuxt.callHook('export:distCopied', this) } decorateWithPayloads (routes, generateRoutes) { @@ -265,6 +277,18 @@ export default class Generator { let html const pageErrors = [] + const setPayload = (_payload) => { + payload = defu(_payload, payload) + } + + // Apply shared payload + if (this._payload) { + payload = defu(payload, this._payload) + } + + await this.nuxt.callHook('generate:route', { route, setPayload }) + await this.nuxt.callHook('export:route', { route, setPayload }) + try { const renderContext = { payload, @@ -301,10 +325,8 @@ export default class Generator { pageErrors.push({ type: 'unhandled', route, error: err }) errors.push(...pageErrors) - await this.nuxt.callHook('generate:routeFailed', { - route, - errors: pageErrors - }) + await this.nuxt.callHook('generate:routeFailed', { route, errors: pageErrors }) + await this.nuxt.callHook('export:routeFailed', { route, errors: pageErrors }) consola.error(this._formatErrors(pageErrors)) return false @@ -332,6 +354,7 @@ export default class Generator { // Call hook to let user update the path & html const page = { route, path: fileName, html } await this.nuxt.callHook('generate:page', page) + await this.nuxt.callHook('export:page', { page }) page.path = path.join(this.distPath, page.path) @@ -339,11 +362,8 @@ export default class Generator { await fsExtra.mkdirp(path.dirname(page.path)) await fsExtra.writeFile(page.path, page.html, 'utf8') - await this.nuxt.callHook('generate:routeCreated', { - route, - path: page.path, - errors: pageErrors - }) + await this.nuxt.callHook('generate:routeCreated', { route, path: page.path, errors: pageErrors }) + await this.nuxt.callHook('export:routeCreated', { route, path: page.path, errors: pageErrors }) if (pageErrors.length) { consola.error('Error generating ' + route) diff --git a/packages/generator/test/__utils__/index.js b/packages/generator/test/__utils__/index.js index 8d573aa5fa..69d003f0a0 100644 --- a/packages/generator/test/__utils__/index.js +++ b/packages/generator/test/__utils__/index.js @@ -14,3 +14,7 @@ export const createNuxt = () => ({ render: {} } }) + +export function hookCalls (nuxt, name) { + return nuxt.callHook.mock.calls.filter(c => c[0] === name).map(c => c.splice(1)) +} diff --git a/packages/generator/test/generator.gen.test.js b/packages/generator/test/generator.gen.test.js index fb2752515c..951b7c86c7 100644 --- a/packages/generator/test/generator.gen.test.js +++ b/packages/generator/test/generator.gen.test.js @@ -57,7 +57,6 @@ describe('generator: generate routes', () => { expect(generator.generateRoutes).toBeCalledTimes(1) expect(generator.generateRoutes).toBeCalledWith(routes) expect(generator.afterGenerate).toBeCalledTimes(1) - expect(nuxt.callHook).toBeCalledTimes(1) expect(nuxt.callHook).toBeCalledWith('generate:done', generator, errors) }) diff --git a/packages/generator/test/generator.init.test.js b/packages/generator/test/generator.init.test.js index 487274fd30..1cf042f9fe 100644 --- a/packages/generator/test/generator.init.test.js +++ b/packages/generator/test/generator.init.test.js @@ -4,7 +4,7 @@ import fsExtra from 'fs-extra' import { flatRoutes, isString, isUrl, promisifyRoute } from '@nuxt/utils' import Generator from '../src/generator' -import { createNuxt } from './__utils__' +import { createNuxt, hookCalls } from './__utils__' jest.mock('path') jest.mock('fs-extra') @@ -63,8 +63,7 @@ describe('generator: initialize', () => { await generator.initiate() expect(nuxt.ready).toBeCalledTimes(1) - expect(nuxt.callHook).toBeCalledTimes(1) - expect(nuxt.callHook).toBeCalledWith('generate:before', generator, { dir: generator.distPath }) + expect(hookCalls(nuxt, 'generate:before')[0]).toMatchObject([generator, { dir: generator.distPath }]) expect(builder.forGenerate).toBeCalledTimes(1) expect(builder.build).toBeCalledTimes(1) expect(generator.initDist).toBeCalledTimes(1) @@ -82,8 +81,7 @@ describe('generator: initialize', () => { await generator.initiate({ build: false, init: false }) expect(nuxt.ready).toBeCalledTimes(1) - expect(nuxt.callHook).toBeCalledTimes(1) - expect(nuxt.callHook).toBeCalledWith('generate:before', generator, { dir: generator.distPath }) + expect(hookCalls(nuxt, 'generate:before')[0]).toMatchObject([generator, { dir: generator.distPath }]) expect(builder.forGenerate).not.toBeCalled() expect(builder.build).not.toBeCalled() expect(generator.initDist).not.toBeCalled() @@ -117,8 +115,7 @@ describe('generator: initialize', () => { expect(flatRoutes).toBeCalledWith(['/index', '/about', '/test']) expect(generator.decorateWithPayloads).toBeCalledTimes(1) expect(generator.decorateWithPayloads).toBeCalledWith(['/index', '/about'], ['/foo', '/foo/bar']) - expect(nuxt.callHook).toBeCalledTimes(1) - expect(nuxt.callHook).toBeCalledWith('generate:extendRoutes', 'decoratedRoutes') + expect(hookCalls(nuxt, 'generate:extendRoutes')[0][0]).toBe('decoratedRoutes') expect(routes).toEqual('decoratedRoutes') }) @@ -147,8 +144,7 @@ describe('generator: initialize', () => { expect(flatRoutes).not.toBeCalled() expect(generator.decorateWithPayloads).toBeCalledTimes(1) expect(generator.decorateWithPayloads).toBeCalledWith(['/'], []) - expect(nuxt.callHook).toBeCalledTimes(1) - expect(nuxt.callHook).toBeCalledWith('generate:extendRoutes', 'decoratedRoutes') + expect(hookCalls(nuxt, 'generate:extendRoutes')[0][0]).toBe('decoratedRoutes') expect(routes).toEqual('decoratedRoutes') promisifyRoute.mockReset() @@ -184,8 +180,7 @@ describe('generator: initialize', () => { expect(fsExtra.emptyDir).toBeCalledTimes(1) expect(fsExtra.emptyDir).toBeCalledWith(generator.distPath) - expect(nuxt.callHook).toBeCalledTimes(2) - expect(nuxt.callHook).nthCalledWith(1, 'generate:distRemoved', generator) + expect(hookCalls(nuxt, 'generate:distRemoved')[0][0]).toMatchObject(generator) expect(fsExtra.exists).toBeCalledTimes(1) expect(fsExtra.exists).toBeCalledWith(generator.staticRoutes) expect(fsExtra.copy).toBeCalledTimes(1) @@ -194,7 +189,7 @@ describe('generator: initialize', () => { expect(path.resolve).toBeCalledWith(generator.distPath, '.nojekyll') expect(fsExtra.writeFile).toBeCalledTimes(1) expect(fsExtra.writeFile).toBeCalledWith(`resolve(${generator.distPath}, .nojekyll)`, '') - expect(nuxt.callHook).nthCalledWith(2, 'generate:distCopied', generator) + expect(hookCalls(nuxt, 'generate:distCopied')[0][0]).toMatchObject(generator) }) test('should copy static routes if path exists', async () => { diff --git a/packages/generator/test/generator.route.test.js b/packages/generator/test/generator.route.test.js index cfbd023bcf..62f84083d5 100644 --- a/packages/generator/test/generator.route.test.js +++ b/packages/generator/test/generator.route.test.js @@ -4,7 +4,7 @@ import fsExtra from 'fs-extra' import htmlMinifier from 'html-minifier' import Generator from '../src/generator' -import { createNuxt } from './__utils__' +import { createNuxt, hookCalls } from './__utils__' jest.mock('path') jest.mock('fs-extra') @@ -47,17 +47,19 @@ describe('generator: generate route', () => { expect(path.join).toBeCalledTimes(2) expect(path.join).nthCalledWith(1, '[sep]', '/foo.html') expect(path.join).nthCalledWith(2, generator.distPath, 'join([sep], /foo.html)') - expect(nuxt.callHook).toBeCalledTimes(2) - expect(nuxt.callHook).nthCalledWith(1, 'generate:page', { + + expect(hookCalls(nuxt, 'generate:page')[0][0]).toMatchObject({ route, html: 'rendered html', path: `join(${generator.distPath}, join([sep], /foo.html))` }) - expect(nuxt.callHook).nthCalledWith(2, 'generate:routeCreated', { + + expect(hookCalls(nuxt, 'generate:routeCreated')[0][0]).toMatchObject({ route, errors: [], path: `join(${generator.distPath}, join([sep], /foo.html))` }) + expect(fsExtra.mkdirp).toBeCalledTimes(1) expect(fsExtra.mkdirp).toBeCalledWith(`dirname(join(${generator.distPath}, join([sep], /foo.html)))`) expect(fsExtra.writeFile).toBeCalledTimes(1) @@ -82,7 +84,6 @@ describe('generator: generate route', () => { expect(nuxt.server.renderRoute).toBeCalledTimes(1) expect(nuxt.server.renderRoute).toBeCalledWith('/foo', { payload }) - expect(nuxt.callHook).toBeCalledTimes(1) expect(nuxt.callHook).toBeCalledWith('generate:routeFailed', { route, errors: [{ type: 'unhandled', route, error }] diff --git a/test/fixtures/full-static/nuxt.config.js b/test/fixtures/full-static/nuxt.config.js index 325cfa7fab..985a66b63e 100644 --- a/test/fixtures/full-static/nuxt.config.js +++ b/test/fixtures/full-static/nuxt.config.js @@ -1,3 +1,18 @@ export default { - target: 'static' + target: 'static', + export: { + payload: { + config: true + } + }, + hooks: { + export: { + before ({ setPayload }) { + setPayload({ shared: true }) + }, + route ({ route, setPayload }) { + setPayload({ myRoute: route }) + } + } + } } diff --git a/test/fixtures/full-static/pages/payload.vue b/test/fixtures/full-static/pages/payload.vue new file mode 100644 index 0000000000..4243a3f509 --- /dev/null +++ b/test/fixtures/full-static/pages/payload.vue @@ -0,0 +1,13 @@ + + +