{"id":17714583,"url":"https://github.com/cyriacbr/modules-watcher","last_synced_at":"2025-06-29T14:32:40.204Z","repository":{"id":191651920,"uuid":"459572692","full_name":"CyriacBr/modules-watcher","owner":"CyriacBr","description":"Resolve JS files and detect changes throughout their dependency tree.","archived":false,"fork":false,"pushed_at":"2023-09-11T20:59:16.000Z","size":3468,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-16T14:25:03.006Z","etag":null,"topics":["module","resolve","watch"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CyriacBr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-15T12:39:14.000Z","updated_at":"2024-05-30T22:24:15.000Z","dependencies_parsed_at":"2024-10-25T12:49:20.014Z","dependency_job_id":"4b39b516-4f99-42b0-aa8c-4242ea00c276","html_url":"https://github.com/CyriacBr/modules-watcher","commit_stats":null,"previous_names":["cyriacbr/modules-watcher"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/CyriacBr/modules-watcher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyriacBr%2Fmodules-watcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyriacBr%2Fmodules-watcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyriacBr%2Fmodules-watcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyriacBr%2Fmodules-watcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CyriacBr","download_url":"https://codeload.github.com/CyriacBr/modules-watcher/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyriacBr%2Fmodules-watcher/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260648461,"owners_count":23041745,"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":["module","resolve","watch"],"created_at":"2024-10-25T11:16:09.967Z","updated_at":"2025-06-29T14:32:40.182Z","avatar_url":"https://github.com/CyriacBr.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Modules Watcher\n\n[![CI](https://github.com/CyriacBr/modules-watcher/actions/workflows/CI.yml/badge.svg)](https://github.com/CyriacBr/modules-watcher/actions/workflows/CI.yml)\n\nThis library provides a way to implement smart watch mode or hot module reloading for your javascript projects.  \n`modules-watcher` is standalone, and doesn't rely on any existing bundler or compile tool. It simply takes the\npaths and/or globs of the files you wish to \"watch\" (entries) and will walk through every one of their dependencies to appropriatly react when an entry change.\nDependencies are resolved using these rules:  \n* ESM imports  \n  * `import [whatever] from 'bar'`\n  * `import('bar')`\n* CJS imports\n  * `require('foo')`\n* (S)CSS imports\n  * `@import foo.css`\n  * `@import \"foo.css\", url('bar.css')`\n* Supports both node modules and relative imports\n  * When importing a node module, `modules-watcher` will resolve it's entry file the same way `require.resolve` does.\n* Supports `~/`\n\n`modules-watcher` uses a custom parser to scan imports depending on the extension of the file being parsed.\nFurthermore, it comes with a cache, allowing you to get the changes between multiple usages. So you can detect changes that happened to your entries\nwhile you weren't actively watching.\n\n## Usage\n\nFirst, instantiate the `Watcher` class using the `setup` factory.\n```ts\nimport { ModulesWatcher } from 'modules-watcher';\n\nconst watcher = ModulesWatcher.setup({\n  project: 'my-doc',\n  projectRoot: 'absolute-path-to-project', // used for resolving `~/` and more\n  globEntries: ['**/*.mdx'], // watch all files matching the globs\n  entries: ['./config.ts'] // also watch specific files\n});\n```\n\nThen, you can either:\n* Get the changes since the last time the program was executed.\n* Or actively watch any changes from now on.\n\n### Getting changes from last usage\n\n`makeChanges()` will return changes based on the cache and the current checksum of the dependency tree of your entries.  \nThis means that changes that occurred when `modules-watcher` wasn't running will be picked up.  \nThe first time this method is called (there's no cache yet), every entry will be marked as `Added`.\n\n```ts\nconst changes = watcher.makeChanges();\nchanges[0];\n/**\n * {\n *    changeType: 'Added',\n *    entry: 'path/foo.mdx',\n * }\n **/\n\nchanges[1];\n/**\n * {\n *    changeType: 'DepAdded',\n *    entry: 'path/foo.mdx',\n *    cause: {\n *      file: 'path/foo-component.js',\n *      state: 'Created',\n *    }\n *    tree: ['path/foo-component.js', 'path/foo.mdx'] \n * }\n **/\n```\n\nLater on, `modules-watcher` will leverage the cache to detect entries that got added, deleted or removed in the meantime.\n\n\n```ts\nalterFooComponent();\naddBarMdx();\ndeleteBazMdx();\n\nconst changes = watcher.makeChanges();\nchanges[0];\n/**\n * {\n *    changeType: 'DepModified',\n *    entry: 'path/foo.mdx',\n *    cause: {\n *      file: 'path/foo-component.js',\n *      state: 'Modified',\n *    }\n *    tree: ['path/foo-component.js', 'path/foo.mdx'] \n * }\n **/\n\nchanges[1];\n/**\n * {\n *    changeType: 'Added',\n *    entry: 'path/bar.mdx',\n * }\n **/\n\nchanges[2];\n/**\n * {\n *    changeType: 'Deleted',\n *    entry: 'path/baz.mdx',\n * }\n **/\n```\nBased on `changeType` and `cause`, it's possible to know if an entry was directly modified or if its dependencies are the ones that changed.  \nNaturally, if an entry is modified with a new import statement, you'll get a change with `DepAdded` for that entry.\n\n### Actively watching for changes\n\nThe method `watch` lets you watch in real-time any modification to your entries or their dependencies.   \nThe callback to `watch` is called with the result of `makeChanges` every time a change is detected.\nUse `stopWatch` to stop watching.\n\n```ts\nwatcher.watch((err, changes) =\u003e {\n    if (!err \u0026\u0026 changes.some(change =\u003e change.entry === 'path/config.ts')) {\n      fullReload();\n    }\n});\n\nwatcher.stopWatch();\n```\nNote that `watch` can't be called consecutively without `stopWatch` after each `watch`.\n\n### Configure the parser\n\nWhen using `setup`, it's possible to specify how imports are parsed according to the extension of the file being read.\n```ts\nconst watcher = ModulesWatcher.setup({\n  ...,\n  // default values:\n  supportedPaths: {\n    // parse ESM imports on these extensions\n    esm: [\"cjs\", \"esm\", \"js\", \"ts\", \"tsx\", \"jsx\", \"cts\", \"mts\", \"mdx\"],\n    // parse import() on these extensions\n    dyn_esm: [\"cjs\", \"esm\", \"js\", \"ts\", \"tsx\", \"jsx\", \"cts\", \"mts\"],\n    // parse require() on these extensions\n    cjs: [\"cjs\", \"esm\", \"js\", \"ts\", \"tsx\", \"jsx\", \"cts\", \"mts\"],\n    // parse CSS imports on these extensions\n    css: [\"css\", \"scss\", \"sass\"]\n  }\n})\n```\n\n### Other methods\n\n**`getDirsToWatch`**: If you want to handle yourself the watching, this method gives you all the directory paths that need to be watched.\n```ts\nconst paths = watcher.getDirsToWatch();\npaths; // ['path/docs', 'path/docs/components', 'path/to/node-modules/react/dist']\n```\n\n**`getEntries`**: returns all entries with their dependencies.  \nNote that they don't necessarily come out ordered.\n```ts\nconst entries = watcher.getEntries();\nentries[0];\n/**\n * {\n *    path: 'path/foo.mdx',\n *    deps: [\n *      'path/foo-component.js', \n *      'path/to/node-modules/react/index.js'\n *    ] \n * }\n **/\n```\n\nTBD.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyriacbr%2Fmodules-watcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcyriacbr%2Fmodules-watcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyriacbr%2Fmodules-watcher/lists"}