refactor(core): use hable (#6271)

This commit is contained in:
Pooya Parsa 2019-08-22 00:16:40 +04:30 committed by GitHub
parent 81b92b6395
commit 9ad02c4017
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 11 additions and 237 deletions

View File

@ -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"
},

View File

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

View File

@ -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'])

View File

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

View File

@ -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'

View File

@ -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"