
Security News
Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
@poppinss/hooks
Advanced tools
A no brainer hooks module for execute before/after lifecycle hooks
A simple yet effective implementation for executing hooks around an event.
This package is a zero-dependency implementation for running lifecycle hooks around an event. Following are some of the notable features.
Install the package from the npm packages registry.
npm i @poppinss/hooks
# yarn lovers
yarn add @poppinss/hooks
And import the Hooks
class as follows.
import Hooks from '@poppinss/hooks'
const hooks = new Hooks()
hooks.add('saving', function () {
console.log('called')
})
// Execute hooks using runner
await hooks.runner('saving').run()
The hooks are defined using the hooks.add
method. The method accepts the event name and a callback function to execute.
const hooks = new Hooks()
hooks.add('saving', function () {
console.log('called')
})
You can also define hook as an object with the name
and the handle
method property. This is usually helpful when you want to specify a custom name for the hook, or re-use the same handle method multiple times.
const hooks = new Hooks()
function handleSave() {}
hooks.add('saving', { name: 'beforeSave', handle: handleSave })
hooks.add('creating', { name: 'beforeCreate', handle: handleSave })
The handle
method receives the first argument as the event name, followed by the rest of the arguments supplied during runtime.
You can execute hooks using the Hooks Runner. You can create a new runner instance by calling the hooks.runner
method and passing the event name for which you want to execute hooks.
const hooks = new Hooks()
const runner = hooks.runner('saving')
await runner.run()
To run hooks in the reverse order, you can use the runner.runReverse
method.
const hooks = new Hooks()
const runner = hooks.runner('saving')
await runner.runReverse()
You can pass one or more arguments to the runner.run
method, which the runner will share with the hook callbacks. For example:
const hooks = new Hooks()
hooks.add('saving', function (model, transaction) {})
const runner = hooks.runner('saving')
await runner.run(model, transaction)
Cleanup functions allow hooks to clean up after themselves after the main action finishes successfully or with an error. Let's consider a real-world example of saving a model to the database.
saving
hooks.saving
hooks writes some files to the disk.Following is how you can express that with cleanup functions.
hooks.add('saving', function () {
await fs.writeFile()
// Return the cleanup function
return (error) => {
// In case of an error, remove the file
if (error) {
await fs.unlink()
}
}
})
The code responsible for issuing the insert query should run hooks as follows.
const runner = hooks.runner('saving')
try {
await runner.run(model)
await model.save()
} catch (error) {
// Perform cleanup and pass error
await runner.cleanup(error)
throw error
}
// Perform cleanup in case of success as well
await runner.cleanup()
Note: The
runner.cleanup
method is idempotent. Therefore you can call it multiple times, yet it will run the underlying cleanup methods only once.
You can exclude certain hook handlers from executing using the without
method.
In the following example, we run hooks without executing the generateDefaultAvatar
hook handler. As you can notice, you can specify the function name as a string.
hooks.add('saving', function hashPassword() {})
hooks.add('saving', function generateDefaultAvatar() {})
await hooks.runner('saving').without(['generateDefaultAvatar']).run()
You can also specify the types of supported events and their arguments well in advance as follows.
The first step is to define a type for all the events.
type Events = {
saving: [
[BaseModel], // for hook handler
[error: Error | null, BaseModel] // for cleanup function
]
finding: [
[QueryBuilder], // for hook handler
[error: Error | null, QueryBuilder] // for cleanup function
]
}
And then pass it as a generic to the Hooks
class.
const hooks = new Hooks<Events>()
FAQs
Hooks module for executing before/after lifecycle hooks
The npm package @poppinss/hooks receives a total of 45,924 weekly downloads. As such, @poppinss/hooks popularity was classified as popular.
We found that @poppinss/hooks demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Security News
React's CRA deprecation announcement sparked community criticism over framework recommendations, leading to quick updates acknowledging build tools like Vite as valid alternatives.
Security News
Ransomware payment rates hit an all-time low in 2024 as law enforcement crackdowns, stronger defenses, and shifting policies make attacks riskier and less profitable.