HyperRequire is an interactive development tool designed to speed up your workflow. It's like a souped-up React Hot Loader for the backend. 🔥 Just save a file and HyperRequire will auto-magically ✨ patch the new code into your running program.
Unlike typical HMR, HyperRequire auto-magically updates all of your exported functions, class prototypes and objects in-place.
HyperRequire watches all your imported modules and can patch almost any type at runtime, including:
- Functions
- Class prototypes and constructors
- Objects and arrays
- Any any property on
module.exports
Note: HyperRequire doesn't play well with ESM/MJS yet.
yarn add -D hyper-require # or npm install -D hyper-require
node -r hyper-require/register
# or
babel-node -r hyper-require/register
# or
ts-node -r hyper-require/register
# or even
ts-node -r hyper-require/register -r tsconfig-paths/register
// 1. watch and auto-patch all modules
require("hyper-require/register");
// ... or 2. same as #1, but you control start/stop
const hyperRequireWatch = require("hyper-require/watch");
const watcher = hyperRequireWatch();
watcher.dispose();
// ... or 3. control module patching
const hyperRequire = require("hyper-require");
let mod = require("./a-module");
hyperRequire("./a-module");
Provides a function to reload and patch a specified module
const hyperRequire = require("hyper-require");
hyperRequire("./a-module");
Requiring this file will immediately begin watching files for changes.
Watch accepts an object specifying path
and ignore
path globs anymatch.
const watcher = require("hyper-require/watch")({
path: "./dir",
ignore: "./other",
});
If path
is unspecified, HyperRequire will fall back to HYPER_REQUIRE_WATCH_PATH
, then the app root path.
If path
is unspecified, HyperRequire will fall back to HYPER_REQUIRE_IGNORE_PATH
, then the glob **/node_modules**
.
HyperRequire checks for a onHyperRequire
function on every module and will call it evey time a module is reloaded. module.onHyperRequire
will be called with two arguments: the id of the reloaded module, and the value of it's module.exports
.
Please be mindful that HyperRequire will re-evaluate the module's underlying file, which could lead to contention over sockets from web servers or database connections.
To gracefully wind down these types of resources, HyperRequire will call module.detach
on the running module before it's replacement is loaded, and module.dispose
on the previous module after a new one is successfully loaded.
let i = 0;
const timer = setInterval(() => console.log(i++), 1000);
module.detach = () => clearInterval(timer);
module.dispose = () => {}
If you're exporting and modifying primitives (numbers, strings, booleans) and want those changes to propagate, avoid destructuring the returned object from require
.
// # num.js
module.exports = { num: 1 };
// # main.js
// ## ex 1 - with destructuring assignment
const { num } = require("./mod");
// programmer updates num.js:num to 2
hyperRequire("./mod");
console.log(num); // it's still 1 :(
// ## ex 2 - with reference to module.exports
const mod = require("./mod");
// programmer updates num.js:num to 2
hyperRequire("./mod");
console.log(num); // it's 2!
// ## ex 3 - with controlled updates
let { num } = require("./mod");
// programmer updates num.js:num to 2
const { num: newNum } = hyperRequire("./mod"); // `hyperRequire` returns the fresh module.exports
num = newNum;
console.log(num); // it's 2!
This does not work yet. WIP.
module.exports = function () {
/*...*/
};
WIP. Right now, all values in module.exports are overwritten on reload. In the future, there will be an API (e.g. const myVal = module.persisted.myVal;
) to enable retaining values between reloads.
This is WIP.