mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
refactor(core): use hable (#6271)
This commit is contained in:
parent
81b92b6395
commit
9ad02c4017
@ -17,6 +17,7 @@
|
||||
"debug": "^4.1.1",
|
||||
"esm": "^3.2.25",
|
||||
"fs-extra": "^8.1.0",
|
||||
"hable": "^2.2.1",
|
||||
"hash-sum": "^2.0.0",
|
||||
"std-env": "^2.2.1"
|
||||
},
|
||||
|
@ -1,71 +0,0 @@
|
||||
|
||||
import consola from 'consola'
|
||||
|
||||
import { sequence } from '@nuxt/utils'
|
||||
|
||||
export default class Hookable {
|
||||
constructor () {
|
||||
this._hooks = {}
|
||||
this._deprecatedHooks = {}
|
||||
|
||||
this.hook = this.hook.bind(this)
|
||||
this.callHook = this.callHook.bind(this)
|
||||
}
|
||||
|
||||
hook (name, fn) {
|
||||
if (!name || typeof fn !== 'function') {
|
||||
return
|
||||
}
|
||||
|
||||
if (this._deprecatedHooks[name]) {
|
||||
consola.warn(`${name} hook has been deprecated, please use ${this._deprecatedHooks[name]}`)
|
||||
name = this._deprecatedHooks[name]
|
||||
}
|
||||
|
||||
this._hooks[name] = this._hooks[name] || []
|
||||
this._hooks[name].push(fn)
|
||||
}
|
||||
|
||||
async callHook (name, ...args) {
|
||||
if (!this._hooks[name]) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await sequence(this._hooks[name], fn => fn(...args))
|
||||
} catch (err) {
|
||||
name !== 'error' && await this.callHook('error', err)
|
||||
consola.fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
clearHook (name) {
|
||||
if (name) {
|
||||
delete this._hooks[name]
|
||||
}
|
||||
}
|
||||
|
||||
clearHooks () {
|
||||
this._hooks = {}
|
||||
}
|
||||
|
||||
flatHooks (configHooks, hooks = {}, parentName) {
|
||||
Object.keys(configHooks).forEach((key) => {
|
||||
const subHook = configHooks[key]
|
||||
const name = parentName ? `${parentName}:${key}` : key
|
||||
if (typeof subHook === 'object' && subHook !== null) {
|
||||
this.flatHooks(subHook, hooks, name)
|
||||
} else {
|
||||
hooks[name] = subHook
|
||||
}
|
||||
})
|
||||
return hooks
|
||||
}
|
||||
|
||||
addHooks (configHooks) {
|
||||
const hooks = this.flatHooks(configHooks)
|
||||
Object.keys(hooks).filter(Boolean).forEach((key) => {
|
||||
[].concat(hooks[key]).forEach(h => this.hook(key, h))
|
||||
})
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
|
||||
import isPlainObject from 'lodash/isPlainObject'
|
||||
import consola from 'consola'
|
||||
import Hookable from 'hable'
|
||||
|
||||
import { defineAlias } from '@nuxt/utils'
|
||||
import { getNuxtConfig } from '@nuxt/config'
|
||||
@ -9,12 +10,11 @@ import { Server } from '@nuxt/server'
|
||||
import { version } from '../package.json'
|
||||
|
||||
import ModuleContainer from './module'
|
||||
import Hookable from './hookable'
|
||||
import Resolver from './resolver'
|
||||
|
||||
export default class Nuxt extends Hookable {
|
||||
constructor (options = {}) {
|
||||
super()
|
||||
super(consola)
|
||||
|
||||
// Assign options and apply defaults
|
||||
this.options = getNuxtConfig(options)
|
||||
@ -24,11 +24,11 @@ export default class Nuxt extends Hookable {
|
||||
this.moduleContainer = new ModuleContainer(this)
|
||||
|
||||
// Deprecated hooks
|
||||
this._deprecatedHooks = {
|
||||
this.deprecateHooks({
|
||||
'render:context': 'render:routeContext',
|
||||
'render:routeContext': 'vue-renderer:afterRender',
|
||||
'showReady': 'webpack:done' // Workaround to deprecate showReady
|
||||
}
|
||||
})
|
||||
|
||||
// Add Legacy aliases
|
||||
defineAlias(this, this.resolver, ['resolveAlias', 'resolvePath'])
|
||||
|
@ -1,161 +0,0 @@
|
||||
import consola from 'consola'
|
||||
import Hookable from '../src/hookable'
|
||||
|
||||
describe('core: hookable', () => {
|
||||
beforeEach(() => {
|
||||
consola.debug.mockClear()
|
||||
consola.log.mockClear()
|
||||
consola.error.mockClear()
|
||||
consola.fatal.mockClear()
|
||||
})
|
||||
|
||||
test('should construct hook object', () => {
|
||||
const hook = new Hookable()
|
||||
|
||||
expect(hook._hooks).toEqual({})
|
||||
expect(hook._deprecatedHooks).toEqual({})
|
||||
expect(hook.hook).toBeInstanceOf(Function)
|
||||
expect(hook.callHook).toBeInstanceOf(Function)
|
||||
})
|
||||
|
||||
test('should register hook successfully', () => {
|
||||
const hook = new Hookable()
|
||||
hook.hook('test:hook', () => {})
|
||||
hook.hook('test:hook', () => {})
|
||||
|
||||
expect(hook._hooks['test:hook']).toHaveLength(2)
|
||||
expect(hook._hooks['test:hook']).toBeInstanceOf(Array)
|
||||
expect(hook._hooks['test:hook']).toEqual([expect.any(Function), expect.any(Function)])
|
||||
})
|
||||
|
||||
test('should ignore empty hook name', () => {
|
||||
const hook = new Hookable()
|
||||
hook.hook(0, () => {})
|
||||
hook.hook('', () => {})
|
||||
hook.hook(undefined, () => {})
|
||||
|
||||
expect(hook._hooks[0]).toBeUndefined()
|
||||
expect(hook._hooks['']).toBeUndefined()
|
||||
expect(hook._hooks[undefined]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('should ignore non-function hook', () => {
|
||||
const hook = new Hookable()
|
||||
hook.hook('test:hook', '')
|
||||
hook.hook('test:hook', undefined)
|
||||
|
||||
expect(hook._hooks['test:hook']).toBeUndefined()
|
||||
})
|
||||
|
||||
test('should convert and display deprecated hook', () => {
|
||||
const hook = new Hookable()
|
||||
hook._deprecatedHooks['test:hook'] = 'test:before'
|
||||
|
||||
hook.hook('test:hook', () => {})
|
||||
|
||||
expect(consola.warn).toBeCalledWith('test:hook hook has been deprecated, please use test:before')
|
||||
expect(hook._hooks['test:hook']).toBeUndefined()
|
||||
expect(hook._hooks['test:before']).toEqual([expect.any(Function)])
|
||||
})
|
||||
|
||||
test('should call registered hook', async () => {
|
||||
const hook = new Hookable()
|
||||
hook.hook('test:hook', () => consola.log('test:hook called'))
|
||||
|
||||
await hook.callHook('test:hook')
|
||||
|
||||
expect(consola.log).toBeCalledWith('test:hook called')
|
||||
})
|
||||
|
||||
test('should ignore unregistered hook', async () => {
|
||||
const hook = new Hookable()
|
||||
|
||||
await hook.callHook('test:hook')
|
||||
|
||||
expect(consola.debug).not.toBeCalled()
|
||||
})
|
||||
|
||||
test('should report hook error', async () => {
|
||||
const hook = new Hookable()
|
||||
const error = new Error('Hook Error')
|
||||
hook.hook('test:hook', () => { throw error })
|
||||
|
||||
await hook.callHook('test:hook')
|
||||
|
||||
expect(consola.fatal).toBeCalledWith(error)
|
||||
})
|
||||
|
||||
test('should call error hook', async () => {
|
||||
const hook = new Hookable()
|
||||
const error = new Error('Hook Error')
|
||||
hook.hook('error', jest.fn())
|
||||
hook.hook('test:hook', () => { throw error })
|
||||
|
||||
await hook.callHook('test:hook')
|
||||
|
||||
expect(hook._hooks.error[0]).toBeCalledWith(error)
|
||||
expect(consola.fatal).toBeCalledWith(error)
|
||||
})
|
||||
|
||||
test('should clear registered hooks', () => {
|
||||
const hook = new Hookable()
|
||||
hook.hook('test:hook', () => {})
|
||||
|
||||
expect(hook._hooks['test:hook']).toHaveLength(1)
|
||||
expect(hook._hooks['test:before']).toBeUndefined()
|
||||
|
||||
hook.clearHook('test:hook')
|
||||
hook.clearHook('test:before')
|
||||
|
||||
expect(hook._hooks['test:hook']).toBeUndefined()
|
||||
expect(hook._hooks['test:before']).toBeUndefined()
|
||||
})
|
||||
|
||||
test('should clear all registered hooks', () => {
|
||||
const hook = new Hookable()
|
||||
hook.hook('test:hook', () => {})
|
||||
|
||||
expect(hook._hooks['test:hook']).toHaveLength(1)
|
||||
expect(hook._hooks['test:before']).toBeUndefined()
|
||||
|
||||
hook.clearHooks()
|
||||
|
||||
expect(hook._hooks['test:hook']).toBeUndefined()
|
||||
expect(hook._hooks['test:before']).toBeUndefined()
|
||||
expect(hook._hooks).toEqual({})
|
||||
})
|
||||
|
||||
test('should return flat hooks', () => {
|
||||
const hook = new Hookable()
|
||||
const hooks = hook.flatHooks({
|
||||
test: {
|
||||
hook: () => {},
|
||||
before: () => {}
|
||||
}
|
||||
})
|
||||
|
||||
expect(hooks).toEqual({
|
||||
'test:hook': expect.any(Function),
|
||||
'test:before': expect.any(Function)
|
||||
})
|
||||
})
|
||||
|
||||
test('should add object hooks', () => {
|
||||
const hook = new Hookable()
|
||||
hook.addHooks({
|
||||
test: {
|
||||
hook: () => {},
|
||||
before: () => {},
|
||||
after: null
|
||||
}
|
||||
})
|
||||
|
||||
expect(hook._hooks).toEqual({
|
||||
'test:hook': expect.any(Array),
|
||||
'test:before': expect.any(Array),
|
||||
'test:after': undefined
|
||||
})
|
||||
expect(hook._hooks['test:hook']).toHaveLength(1)
|
||||
expect(hook._hooks['test:before']).toHaveLength(1)
|
||||
})
|
||||
})
|
@ -1,10 +1,10 @@
|
||||
import { defineAlias } from '@nuxt/utils'
|
||||
import { getNuxtConfig } from '@nuxt/config'
|
||||
import { Server } from '@nuxt/server'
|
||||
import Hookable from 'hable'
|
||||
|
||||
import Nuxt from '../src/nuxt'
|
||||
import ModuleContainer from '../src/module'
|
||||
import Hookable from '../src/hookable'
|
||||
import Resolver from '../src/resolver'
|
||||
import { version } from '../package.json'
|
||||
|
||||
|
@ -5436,6 +5436,11 @@ gzip-size@^5.0.0:
|
||||
duplexer "^0.1.1"
|
||||
pify "^4.0.1"
|
||||
|
||||
hable@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/hable/-/hable-2.2.1.tgz#714ef141a7eda5bd8530d6e4e3b37c6807716290"
|
||||
integrity sha512-CuGRGMNnCp8RJ70zeoTX37sX4ctoT8BpmkStI2TYQwBBtWzQQFXQ/jsBUCqd34grt3IJQ+hkUXAU84/IuErVLQ==
|
||||
|
||||
handlebars@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
|
||||
|
Loading…
Reference in New Issue
Block a user