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
This commit is contained in:
Pooya Parsa 2020-05-27 16:51:51 +02:00 committed by GitHub
parent 618eb5fad0
commit a82f8d8b1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 28 deletions

View File

@ -2,6 +2,7 @@ import path from 'path'
import chalk from 'chalk' import chalk from 'chalk'
import consola from 'consola' import consola from 'consola'
import fsExtra from 'fs-extra' import fsExtra from 'fs-extra'
import defu from 'defu'
import htmlMinifier from 'html-minifier' import htmlMinifier from 'html-minifier'
import { parse } from 'node-html-parser' import { parse } from 'node-html-parser'
@ -23,6 +24,12 @@ export default class Generator {
isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath
) )
this.generatedRoutes = new Set() this.generatedRoutes = new Set()
// Shared payload
this._payload = null
this.setPayload = (payload) => {
this._payload = defu(payload, this._payload)
}
} }
async generate ({ build = true, init = true } = {}) { async generate ({ build = true, init = true } = {}) {
@ -47,6 +54,7 @@ export default class Generator {
// Done hook // Done hook
await this.nuxt.callHook('generate:done', this, errors) await this.nuxt.callHook('generate:done', this, errors)
await this.nuxt.callHook('export:done', this, { errors })
return { errors } return { errors }
} }
@ -57,6 +65,7 @@ export default class Generator {
// Call before hook // Call before hook
await this.nuxt.callHook('generate:before', this, this.options.generate) await this.nuxt.callHook('generate:before', this, this.options.generate)
await this.nuxt.callHook('export:before', this)
if (build) { if (build) {
// Add flag to set process.static // Add flag to set process.static
@ -115,6 +124,7 @@ export default class Generator {
// extendRoutes hook // extendRoutes hook
await this.nuxt.callHook('generate:extendRoutes', routes) await this.nuxt.callHook('generate:extendRoutes', routes)
await this.nuxt.callHook('export:extendRoutes', { routes })
return routes return routes
} }
@ -223,6 +233,7 @@ export default class Generator {
consola.info(`Generating output directory: ${path.basename(this.distPath)}/`) consola.info(`Generating output directory: ${path.basename(this.distPath)}/`)
await this.nuxt.callHook('generate:distRemoved', this) await this.nuxt.callHook('generate:distRemoved', this)
await this.nuxt.callHook('export:distCopied', this)
// Copy static and built files // Copy static and built files
if (await fsExtra.exists(this.staticRoutes)) { if (await fsExtra.exists(this.staticRoutes)) {
@ -241,6 +252,7 @@ export default class Generator {
fsExtra.writeFile(nojekyllPath, '') fsExtra.writeFile(nojekyllPath, '')
await this.nuxt.callHook('generate:distCopied', this) await this.nuxt.callHook('generate:distCopied', this)
await this.nuxt.callHook('export:distCopied', this)
} }
decorateWithPayloads (routes, generateRoutes) { decorateWithPayloads (routes, generateRoutes) {
@ -265,6 +277,18 @@ export default class Generator {
let html let html
const pageErrors = [] 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 { try {
const renderContext = { const renderContext = {
payload, payload,
@ -301,10 +325,8 @@ export default class Generator {
pageErrors.push({ type: 'unhandled', route, error: err }) pageErrors.push({ type: 'unhandled', route, error: err })
errors.push(...pageErrors) errors.push(...pageErrors)
await this.nuxt.callHook('generate:routeFailed', { await this.nuxt.callHook('generate:routeFailed', { route, errors: pageErrors })
route, await this.nuxt.callHook('export:routeFailed', { route, errors: pageErrors })
errors: pageErrors
})
consola.error(this._formatErrors(pageErrors)) consola.error(this._formatErrors(pageErrors))
return false return false
@ -332,6 +354,7 @@ export default class Generator {
// Call hook to let user update the path & html // Call hook to let user update the path & html
const page = { route, path: fileName, html } const page = { route, path: fileName, html }
await this.nuxt.callHook('generate:page', page) await this.nuxt.callHook('generate:page', page)
await this.nuxt.callHook('export:page', { page })
page.path = path.join(this.distPath, page.path) 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.mkdirp(path.dirname(page.path))
await fsExtra.writeFile(page.path, page.html, 'utf8') await fsExtra.writeFile(page.path, page.html, 'utf8')
await this.nuxt.callHook('generate:routeCreated', { await this.nuxt.callHook('generate:routeCreated', { route, path: page.path, errors: pageErrors })
route, await this.nuxt.callHook('export:routeCreated', { route, path: page.path, errors: pageErrors })
path: page.path,
errors: pageErrors
})
if (pageErrors.length) { if (pageErrors.length) {
consola.error('Error generating ' + route) consola.error('Error generating ' + route)

View File

@ -14,3 +14,7 @@ export const createNuxt = () => ({
render: {} render: {}
} }
}) })
export function hookCalls (nuxt, name) {
return nuxt.callHook.mock.calls.filter(c => c[0] === name).map(c => c.splice(1))
}

View File

@ -57,7 +57,6 @@ describe('generator: generate routes', () => {
expect(generator.generateRoutes).toBeCalledTimes(1) expect(generator.generateRoutes).toBeCalledTimes(1)
expect(generator.generateRoutes).toBeCalledWith(routes) expect(generator.generateRoutes).toBeCalledWith(routes)
expect(generator.afterGenerate).toBeCalledTimes(1) expect(generator.afterGenerate).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledWith('generate:done', generator, errors) expect(nuxt.callHook).toBeCalledWith('generate:done', generator, errors)
}) })

View File

@ -4,7 +4,7 @@ import fsExtra from 'fs-extra'
import { flatRoutes, isString, isUrl, promisifyRoute } from '@nuxt/utils' import { flatRoutes, isString, isUrl, promisifyRoute } from '@nuxt/utils'
import Generator from '../src/generator' import Generator from '../src/generator'
import { createNuxt } from './__utils__' import { createNuxt, hookCalls } from './__utils__'
jest.mock('path') jest.mock('path')
jest.mock('fs-extra') jest.mock('fs-extra')
@ -63,8 +63,7 @@ describe('generator: initialize', () => {
await generator.initiate() await generator.initiate()
expect(nuxt.ready).toBeCalledTimes(1) expect(nuxt.ready).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledTimes(1) expect(hookCalls(nuxt, 'generate:before')[0]).toMatchObject([generator, { dir: generator.distPath }])
expect(nuxt.callHook).toBeCalledWith('generate:before', generator, { dir: generator.distPath })
expect(builder.forGenerate).toBeCalledTimes(1) expect(builder.forGenerate).toBeCalledTimes(1)
expect(builder.build).toBeCalledTimes(1) expect(builder.build).toBeCalledTimes(1)
expect(generator.initDist).toBeCalledTimes(1) expect(generator.initDist).toBeCalledTimes(1)
@ -82,8 +81,7 @@ describe('generator: initialize', () => {
await generator.initiate({ build: false, init: false }) await generator.initiate({ build: false, init: false })
expect(nuxt.ready).toBeCalledTimes(1) expect(nuxt.ready).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledTimes(1) expect(hookCalls(nuxt, 'generate:before')[0]).toMatchObject([generator, { dir: generator.distPath }])
expect(nuxt.callHook).toBeCalledWith('generate:before', generator, { dir: generator.distPath })
expect(builder.forGenerate).not.toBeCalled() expect(builder.forGenerate).not.toBeCalled()
expect(builder.build).not.toBeCalled() expect(builder.build).not.toBeCalled()
expect(generator.initDist).not.toBeCalled() expect(generator.initDist).not.toBeCalled()
@ -117,8 +115,7 @@ describe('generator: initialize', () => {
expect(flatRoutes).toBeCalledWith(['/index', '/about', '/test']) expect(flatRoutes).toBeCalledWith(['/index', '/about', '/test'])
expect(generator.decorateWithPayloads).toBeCalledTimes(1) expect(generator.decorateWithPayloads).toBeCalledTimes(1)
expect(generator.decorateWithPayloads).toBeCalledWith(['/index', '/about'], ['/foo', '/foo/bar']) expect(generator.decorateWithPayloads).toBeCalledWith(['/index', '/about'], ['/foo', '/foo/bar'])
expect(nuxt.callHook).toBeCalledTimes(1) expect(hookCalls(nuxt, 'generate:extendRoutes')[0][0]).toBe('decoratedRoutes')
expect(nuxt.callHook).toBeCalledWith('generate:extendRoutes', 'decoratedRoutes')
expect(routes).toEqual('decoratedRoutes') expect(routes).toEqual('decoratedRoutes')
}) })
@ -147,8 +144,7 @@ describe('generator: initialize', () => {
expect(flatRoutes).not.toBeCalled() expect(flatRoutes).not.toBeCalled()
expect(generator.decorateWithPayloads).toBeCalledTimes(1) expect(generator.decorateWithPayloads).toBeCalledTimes(1)
expect(generator.decorateWithPayloads).toBeCalledWith(['/'], []) expect(generator.decorateWithPayloads).toBeCalledWith(['/'], [])
expect(nuxt.callHook).toBeCalledTimes(1) expect(hookCalls(nuxt, 'generate:extendRoutes')[0][0]).toBe('decoratedRoutes')
expect(nuxt.callHook).toBeCalledWith('generate:extendRoutes', 'decoratedRoutes')
expect(routes).toEqual('decoratedRoutes') expect(routes).toEqual('decoratedRoutes')
promisifyRoute.mockReset() promisifyRoute.mockReset()
@ -184,8 +180,7 @@ describe('generator: initialize', () => {
expect(fsExtra.emptyDir).toBeCalledTimes(1) expect(fsExtra.emptyDir).toBeCalledTimes(1)
expect(fsExtra.emptyDir).toBeCalledWith(generator.distPath) expect(fsExtra.emptyDir).toBeCalledWith(generator.distPath)
expect(nuxt.callHook).toBeCalledTimes(2) expect(hookCalls(nuxt, 'generate:distRemoved')[0][0]).toMatchObject(generator)
expect(nuxt.callHook).nthCalledWith(1, 'generate:distRemoved', generator)
expect(fsExtra.exists).toBeCalledTimes(1) expect(fsExtra.exists).toBeCalledTimes(1)
expect(fsExtra.exists).toBeCalledWith(generator.staticRoutes) expect(fsExtra.exists).toBeCalledWith(generator.staticRoutes)
expect(fsExtra.copy).toBeCalledTimes(1) expect(fsExtra.copy).toBeCalledTimes(1)
@ -194,7 +189,7 @@ describe('generator: initialize', () => {
expect(path.resolve).toBeCalledWith(generator.distPath, '.nojekyll') expect(path.resolve).toBeCalledWith(generator.distPath, '.nojekyll')
expect(fsExtra.writeFile).toBeCalledTimes(1) expect(fsExtra.writeFile).toBeCalledTimes(1)
expect(fsExtra.writeFile).toBeCalledWith(`resolve(${generator.distPath}, .nojekyll)`, '') 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 () => { test('should copy static routes if path exists', async () => {

View File

@ -4,7 +4,7 @@ import fsExtra from 'fs-extra'
import htmlMinifier from 'html-minifier' import htmlMinifier from 'html-minifier'
import Generator from '../src/generator' import Generator from '../src/generator'
import { createNuxt } from './__utils__' import { createNuxt, hookCalls } from './__utils__'
jest.mock('path') jest.mock('path')
jest.mock('fs-extra') jest.mock('fs-extra')
@ -47,17 +47,19 @@ describe('generator: generate route', () => {
expect(path.join).toBeCalledTimes(2) expect(path.join).toBeCalledTimes(2)
expect(path.join).nthCalledWith(1, '[sep]', '/foo.html') expect(path.join).nthCalledWith(1, '[sep]', '/foo.html')
expect(path.join).nthCalledWith(2, generator.distPath, 'join([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, route,
html: 'rendered html', html: 'rendered html',
path: `join(${generator.distPath}, join([sep], /foo.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, route,
errors: [], errors: [],
path: `join(${generator.distPath}, join([sep], /foo.html))` path: `join(${generator.distPath}, join([sep], /foo.html))`
}) })
expect(fsExtra.mkdirp).toBeCalledTimes(1) expect(fsExtra.mkdirp).toBeCalledTimes(1)
expect(fsExtra.mkdirp).toBeCalledWith(`dirname(join(${generator.distPath}, join([sep], /foo.html)))`) expect(fsExtra.mkdirp).toBeCalledWith(`dirname(join(${generator.distPath}, join([sep], /foo.html)))`)
expect(fsExtra.writeFile).toBeCalledTimes(1) expect(fsExtra.writeFile).toBeCalledTimes(1)
@ -82,7 +84,6 @@ describe('generator: generate route', () => {
expect(nuxt.server.renderRoute).toBeCalledTimes(1) expect(nuxt.server.renderRoute).toBeCalledTimes(1)
expect(nuxt.server.renderRoute).toBeCalledWith('/foo', { payload }) expect(nuxt.server.renderRoute).toBeCalledWith('/foo', { payload })
expect(nuxt.callHook).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledWith('generate:routeFailed', { expect(nuxt.callHook).toBeCalledWith('generate:routeFailed', {
route, route,
errors: [{ type: 'unhandled', route, error }] errors: [{ type: 'unhandled', route, error }]

View File

@ -1,3 +1,18 @@
export default { export default {
target: 'static' target: 'static',
export: {
payload: {
config: true
}
},
hooks: {
export: {
before ({ setPayload }) {
setPayload({ shared: true })
},
route ({ route, setPayload }) {
setPayload({ myRoute: route })
}
}
}
} }

View File

@ -0,0 +1,13 @@
<template>
<div v-text="JSON.stringify(payload)" />
</template>
<script>
export default {
asyncData ({ payload }) {
return {
payload
}
}
}
</script>