├── .gitignore ├── LICENSE ├── README.md ├── example ├── app.js └── handler.js ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 chanon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | re-require-module 2 | ========= 3 | 4 | ## What is it? 5 | 6 | Drop-in replacement for node.js ```require``` that always reads the required module again from disk. It actually automatically uncaches it before requiring it again for you. This allows changes to become live without restarting node. It is like a simple hot require. It is also similar to ```decache``` except it also does the ```require``` again part for you. 7 | 8 | ## Why and when would I use this? 9 | 10 | * Are you tired of having to restart your node server everytime you make a change to your server code? 11 | * Is code (such as request handlers) in your modules usually pure functions? 12 | 13 | If so, then ```re-require-module``` is an easy, simple and lightweight way for you to achieve 'hot' style code reloading. 14 | 15 | The way ```re-require-module``` works is it just uncaches the module you give it, before returning what you'd usually get out of ```require```. This way whatever change you make is always loaded at the point in code that you ```reRequire``` it. 16 | 17 | When using it, the key thing to make it work is that, you must put the ```reRequire``` call somewhere where it will be called each time a request is made. 18 | 19 | Also note that if your module has state inside, the state will be wiped out on ```reRequire```. 20 | 21 | ## Production Ready 22 | 23 | You can actually leave your ```reRequire``` call in production. ```re-require-module``` detects that if in production mode, it will not reload code and will hit the disk only on the first ```reRequire``` call. 24 | 25 | ## Install 26 | 27 | ```npm install re-require-module --save``` 28 | 29 | ## Example Usage 30 | 31 | ``` 32 | // app.js 33 | var http = require('http'); 34 | var reRequire = require('re-require-module').reRequire; 35 | 36 | var server = http.createServer(function(req, res) { 37 | // put reRequire in here so that a reRequire is made on each request 38 | reRequire('./handler').handleRequest(req, res); 39 | }); 40 | 41 | server.listen(8080); 42 | 43 | ``` 44 | 45 | ``` 46 | // handler.js 47 | module.exports.handleRequest = function(req, res){ 48 | res.end('Try editing this and refresh. No need to restart node!'); 49 | } 50 | ``` 51 | 52 | ## Trying out the example 53 | 54 | - Run the example: 55 | ``` 56 | node example/app 57 | ``` 58 | - Open your browser to ```http://localhost:8080```. 59 | - Try editing the text in ```handler.js``` 60 | - Refresh and see the changes immediately. No need to restart node. 61 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var reRequire = require('re-require-module').reRequire; 3 | 4 | var server = http.createServer(function(req, res) { 5 | // we reRequire inside this function so that everytime a request comes in, './handler' gets re-required 6 | // if we did http.createServer( reRequire('./handler').handleRequest(req, res) ), then it wouldn't work 7 | reRequire('./handler').handleRequest(req, res); 8 | }); 9 | 10 | server.listen(8080, function(){ 11 | console.log("Server listening on: http://localhost:8080"); 12 | console.log("Try making changes to the handleRequest function in handler.js and refresh!"); 13 | }); -------------------------------------------------------------------------------- /example/handler.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports.handleRequest = function(req, res){ 3 | res.end('Try editing this and refresh. No need to restart node!'); 4 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | 4 | // taken from callsites module 5 | function callsites() { 6 | var _ = Error.prepareStackTrace; 7 | Error.prepareStackTrace = function (_, stack) { 8 | return stack; 9 | }; 10 | var stack = new Error().stack.slice(1); 11 | Error.prepareStackTrace = _; 12 | return stack; 13 | }; 14 | 15 | function exists(path) { 16 | try { 17 | fs.statSync(path); 18 | return true; 19 | } 20 | catch (e) { 21 | return false; 22 | } 23 | } 24 | 25 | var existsCache = {}; 26 | 27 | // caches the 'exists' results so we don't hit the file system everytime in production 28 | function existsCached(testPath) { 29 | if (existsCache[testPath] == 1) { 30 | return true; 31 | } 32 | if (existsCache[testPath] == 0) { 33 | return false; 34 | } 35 | if (exists(testPath)) { 36 | existsCache[testPath] = 1; 37 | return true; 38 | } 39 | else { 40 | existsCache[testPath] = 0; 41 | return false; 42 | } 43 | } 44 | 45 | var environment = process.env.NODE_ENV || 'development'; 46 | 47 | module.exports.reRequire = function (moduleName) { 48 | 49 | // this part, we basically see whether the moduleName is supposed to be a node_modules module, or a relative path 50 | 51 | var callerPath = callsites()[1].getFileName(); 52 | var testRelativePath = path.resolve(path.dirname(callerPath), moduleName); 53 | 54 | if (testRelativePath.substr(testRelativePath.length - 3, 3) != '.js') { 55 | // we only support js files for now 56 | testRelativePath = testRelativePath + '.js'; 57 | } 58 | 59 | var modulePath; 60 | if (existsCached(testRelativePath)) { 61 | modulePath = testRelativePath; 62 | } 63 | else { 64 | modulePath = require.resolve(moduleName); 65 | } 66 | 67 | // for development mode, we delete the cached module 68 | 69 | if (environment == 'development') { 70 | // we just delete this module 71 | // other modules delete also all submodules loaded by this module - which is overkill and can cause a lot of slowness 72 | delete require.cache[modulePath]; 73 | } 74 | 75 | // return the require result 76 | 77 | return require(modulePath); 78 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "re-require-module", 3 | "version": "1.0.2", 4 | "description": "Replacement for node.js require that that always reads the required module again from disk. It actually automatically uncaches it before requiring it again for you. This allows changes to become live without restarting node. It is like a simple hot require.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/chanon/re-require-module.git" 12 | }, 13 | "keywords": [ 14 | "nodejs", 15 | "node", 16 | "require", 17 | "commonjs", 18 | "hot", 19 | "live", 20 | "un-require", 21 | "re-require", 22 | "uncache", 23 | "node_modules", 24 | "modules", 25 | "decache", 26 | "require-reload", 27 | "reload" 28 | ], 29 | "author": "Chanon Sajjamanochai ", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/chanon/re-require-module/issues" 33 | }, 34 | "homepage": "https://github.com/chanon/re-require-module#readme" 35 | } 36 | --------------------------------------------------------------------------------