{"id":20001728,"url":"https://github.com/franckfreiburger/module-invalidate","last_synced_at":"2025-05-04T15:33:25.763Z","repository":{"id":48473422,"uuid":"83570159","full_name":"FranckFreiburger/module-invalidate","owner":"FranckFreiburger","description":"Invalidate node.js modules loaded through require()","archived":false,"fork":false,"pushed_at":"2021-07-23T23:53:35.000Z","size":62,"stargazers_count":19,"open_issues_count":1,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-09T12:19:43.774Z","etag":null,"topics":["invalidation","module","nodejs","reload","require"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FranckFreiburger.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-01T15:30:13.000Z","updated_at":"2021-04-01T14:26:26.000Z","dependencies_parsed_at":"2022-08-27T23:50:48.472Z","dependency_job_id":null,"html_url":"https://github.com/FranckFreiburger/module-invalidate","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranckFreiburger%2Fmodule-invalidate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranckFreiburger%2Fmodule-invalidate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranckFreiburger%2Fmodule-invalidate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranckFreiburger%2Fmodule-invalidate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FranckFreiburger","download_url":"https://codeload.github.com/FranckFreiburger/module-invalidate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224394071,"owners_count":17303830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["invalidation","module","nodejs","reload","require"],"created_at":"2024-11-13T05:18:32.031Z","updated_at":"2024-11-13T05:18:32.528Z","avatar_url":"https://github.com/FranckFreiburger.png","language":"JavaScript","readme":"# module-invalidate\nInvalidate node.js modules loaded through `require()`\n\n\n## Description\n`module-invalidate` allows you to invalidate a given module (or all modules) and make it automatically reloaded on further access, no need to call `require()` again.  \n\n\n## Install\n\n`npm install --save module-invalidate`\n\n\n## Examples\n\n\n##### Example: simple case\n\n###### module `./myModule.js`\n```JavaScript\nmodule.invalidable = true;\n\nvar count = 0;\nexports.count = function() {\n\n\treturn count++;\n}\n```\n\n###### main module `./index.js`\n```JavaScript\nrequire('module-invalidate');\n\nvar myModule = require('./myModule.js');\n\nconsole.log( myModule.count() ); // 0\nconsole.log( myModule.count() ); // 1\n\nmodule.constructor.invalidateByExports(myModule);\n\nconsole.log( myModule.count() ); // 0\nconsole.log( myModule.count() ); // 1\n```\n\n\n##### Example: invalidate module on modification\n\n```JavaScript\nconst fs = require('fs');\n\nvar myModule = require('./myModule.js');\n\nfs.watch(require.resolve('./myModule.js'), function() {\n\t\n\tmodule.invalidateByPath('./myModule.js');\n});\n\nsetInterval(function() {\n\t\n\tconsole.log(myModule.count());\n}, 1000);\n```\n\n\n##### Example:\n\n```JavaScript\nrequire('module-invalidate');\n\nvar tmp_modulePath = require('path').join(__dirname, 'tmp_module.js');\n\nrequire('fs').writeFileSync(tmp_modulePath, `\n\tmodule.invalidable = true;\n\texports.a = 1;\n`);\n\n\nvar tmp_module = require('./tmp_module.js');\n\nconsole.log(tmp_module.a); // 1\n\n\nrequire('fs').writeFileSync(tmp_modulePath, `\n\tmodule.invalidable = true;\n\texports.a = 2;\n`);\n\nmodule.constructor.invalidateByExports(tmp_module);\n\nconsole.log(tmp_module.a); // 2\n\n\nrequire('fs').unlinkSync(tmp_modulePath);\n\n```\n\n\n\n\n## API\n\nIn the following API, `Module` refers to the Module constructor, available with `module.constructor` or `require('Module')`.  \nAnd `module` refers to a module instance, available in each module with `module`.\n\n\n#### `require('module-invalidate')`\nEnable the module-invalidate mechanism.  \nAny nodejs-non-internal module loaded after this call can be handled by this library.\n\n\n#### `module.invalidable`\nThis property controls whether the module can be invalidated. By default, modules are not invalidable.\n\n##### Example:\n###### module `./myModule.js`\n```JavaScript\nmodule.invalidable = true;\nmodule.exports = {\n\tfoo: function() {}\n}\n```\n\n#### `module.invalidateByPath(path)`\nInvalidates the specified module by its path (same syntax and context than `require()`). The module should have been flagged as invalidable using `module.invalidable`.\n\n##### Example:\n```JavaScript\nrequire('module-invalidate');\nvar myModule = require('./myModule.js');\nmodule.invalidateByPath('./myModule.js');\n```\n\n\n#### `Module.invalidateByExports(exports)`\nInvalidates the module by giving its exported object. The module should have been flagged as invalidable using `module.invalidable`.  \n\n##### Example:\n```JavaScript\nrequire('module-invalidate');\nvar myModule = require('./myModule.js');\nmodule.constructor.invalidateByExports(myModule);\n```\n\n`invalidateByExports()` only invalidates one module.\n###### module `B.js`\n```\n\tmodule.invalidable = true;\n\tconsole.log('load B');\n\tmodule.exports = {\n\t\tfoo: 123\n\t}\n```\n\n###### module `A.js`\n```\n\tmodule.invalidable = true;\n\tconsole.log('load A');\n\tmodule.exports = require('./B.js');\n\n```\n\n###### main module `index.js`\n```\n\trequire('module-invalidate');\n\tvar a = require('./A.js');\n\tconsole.log('invalidate');\n\tmodule.constructor.invalidateByExports(a);\n\tvar tmp = a.foo;\n```\t\n\noutput:\n```\t\nload A\nload B\ninvalidate\nload A\n```\t\n\n\n#### `Module.invalidate()`\nInvalidates all nodejs-non-internal modules. Only process modules that have been flagged as invalidable using `module.invalidable`.\n\n##### Example:\n```JavaScript\nrequire('module-invalidate');\nmodule.constructor.invalidate();\n```\n\n\n#### `module.invalidate()`\nInvalidates the module `module`. The module should have been flagged as invalidable using `module.invalidable`.\n\n##### Example:\n```JavaScript\nmodule.invalidate();\n```\n\n#### `module.unload()`\nDefinitely unloads the module `module`.\n\n\n#### `module.unloadByPath(path)`\nDefinitely unloads the module by its path (same syntax and context than `require()`).\n\n\n#### `Module.unloadByExports(exports)`\nDefinitely unloads the module by giving its exported object.\n\n\n#### `module.onInvalidate(callback)`\ncallback: `function(immutable_exports)`\n\nRegister a callback that will be called when the module is invalidated. The `immutable_exports` is a permanent reference to the current `module.exports`.  \n`onInvalidate` returns a function that unregisters the callback.\n\nGives you the opportunity to free resources created in the module.  \neg. temporary files, timers, web routes, ...\n\nThe `callback` can return function that is called after the module is reloaded. This can help you restore your module state.\n\n##### Example:\n```JavaScript\nmodule.invalidable = true;\nthis.connectedUsers = [];\nexports.connectUser = function(name) {\n\t\n\tthis.connectedUsers.push(name);\n}\n\nexports.getConnectedUsers = function() {\n\t\n\treturn this.connectedUsers;\n}\n\nmodule.onInvalidate(function(oldExports) {\n\n\treturn function(newExports) {\n\t\t\n\t\tnewExports.connectedUsers = oldExports.connectedUsers;\n\t}\n});\n\n```\n\n\n\n## How it works\n\n1. `Module.prototype.exports` is overridden by a No-op forwarding ES6 Proxy that handle all accesses to module exports.\n1. When a module is invalidated, it is marked as *invalidated* and is then reloaded on the next access (lazily).\n\n\n\n## Caveat\n\n#### `typeof module.exports` is always `'function'`\n\nBecause the library is unable to know in advance what type of value will be assigned to `module.export`, it choose the most generic one as ES6 Proxy target.\nHowever, `(function(){}) instanceof Object === true`.  \nAs workaround, you can use `instanceof` against the `module.exports`, this will always retuns the expected result.\n##### Example:\n\n###### module `./myModule.js`\n```\nmodule.invalidable = true;\nmodule.exports = new Date;\n```\n\n###### main module `index.js`\n```\nrequire('module-invalidate');\nvar myModule = require('./myModule.js');\nconsole.log(myModule instanceof Date); // true\n```\n\n#### Only direct variable access is handled\n\n##### Example:\n```  \nvar foo = require('foo.js');\nvar bar = foo.bar;\n```\nIn this case, `bar` will always refers to the initial `foo.bar` value. To avoid this, always refer `bar` using `foo.bar`.\n\n\n#### Invalidated modules will survive with the new child-module version\nIn a module, `module.exports` will always refers to the latest version of the module.\n\n##### Example:\n\n###### module `./child.js`\n```\nmodule.invalidable = true;\nmodule.exports = {};\n\nsetInterval(function() {\n\tconsole.log(module.exports.foo);\n}, 1000);\n\n```\n\n###### main module `index.js`\n```\nrequire('module-invalidate');\n\nvar child = require('./child.js');\nchild.foo = 1;\nmodule.constructor.invalidateByExports(child);\nchild.foo = 2;\n```\n\n###### output\n```\n2\n2\n2\n2\n2\n...\n\n```\n\n## How can you help?\n\nGive me some [feedback](https://github.com/FranckFreiburger/module-invalidate/issues/new?labels=feedback) and report [bugs](https://github.com/FranckFreiburger/module-invalidate/issues/new?labels=bug\u0026body=Node.js%20version:%20%0Amodule-invalidate%20version:%20%0AIssue%20description:%20%0A).\n\n\n## Credits\n\n[Franck Freiburger](https://www.franck-freiburger.com)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranckfreiburger%2Fmodule-invalidate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranckfreiburger%2Fmodule-invalidate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranckfreiburger%2Fmodule-invalidate/lists"}