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 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)

View File

@ -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))
}

View File

@ -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)
})

View File

@ -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 () => {

View File

@ -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 }]

View File

@ -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 })
}
}
}
}

View File

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