{"id":16742360,"url":"https://github.com/alexispuga/precise-watcher","last_synced_at":"2025-04-10T13:32:43.077Z","repository":{"id":42634361,"uuid":"343597220","full_name":"AlexisPuga/precise-watcher","owner":"AlexisPuga","description":"Automate tasks on file change, run them in parallel, and forget about tool-specific plugins.","archived":false,"fork":false,"pushed_at":"2023-07-19T01:37:07.000Z","size":703,"stargazers_count":3,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T12:11:31.280Z","etag":null,"topics":["build-tool","cli","concurrently","dev-tool","file-watcher","npm-tool","task-automation","task-runner"],"latest_commit_sha":null,"homepage":"","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/AlexisPuga.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-02T00:30:02.000Z","updated_at":"2023-04-27T20:51:52.000Z","dependencies_parsed_at":"2025-02-17T08:31:14.131Z","dependency_job_id":"824a6862-039b-4f32-a3eb-f92bacb9f924","html_url":"https://github.com/AlexisPuga/precise-watcher","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexisPuga%2Fprecise-watcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexisPuga%2Fprecise-watcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexisPuga%2Fprecise-watcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexisPuga%2Fprecise-watcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AlexisPuga","download_url":"https://codeload.github.com/AlexisPuga/precise-watcher/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248225712,"owners_count":21068078,"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":["build-tool","cli","concurrently","dev-tool","file-watcher","npm-tool","task-automation","task-runner"],"created_at":"2024-10-13T01:23:31.727Z","updated_at":"2025-04-10T13:32:43.030Z","avatar_url":"https://github.com/AlexisPuga.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align='right'\u003e\u003ca href='https://github.com/standard/standard'\u003e\u003cimg src='https://cdn.rawgit.com/standard/standard/master/badge.svg' alt='JavaScript Style Guide'/\u003e\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 align='left'\u003ePrecise Watcher\u003c/h1\u003e\n\u003cp align='left'\u003eAutomate tasks on file change, run them in parallel, and forget about tool-specific plugins.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThink NPM scripts + (Precise) File watcher + Parallel scripting - Task Runner/Build Tool - Tool-specific plugins.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003cp align='right'\u003e\u003cem\u003e\u003cstrong\u003e\u003cdfn\u003ePrecise\u003c/dfn\u003e\u003c/strong\u003e: \u003cq cite='https://www.dictionary.com/browse/precise'\u003edefinitely or strictly stated, defined, or fixed\u003c/q\u003e.\u003c/em\u003e\u003c/p\u003e\n\n## Contents\n1. [Status](#status)\n2. [Installation](#installation)\n3. [Usage](#usage)\n    1. [Posibilities](#posibilities)\n    2. [Watch files using NPM scripts](#watch-files-using-npm-scripts)\n        1. [Setting options in a configuration file](#setting-options-in-a-configuration-file)\n    3. [Watch files using your console](#watch-files-using-your-console)\n        1. [Supported options](#supported-options)\n    4. [Watch files using js](#watch-files-using-js)\n4. [Examples](#examples)\n    1. [Run `eslint --fix` on 1 single file, when it changes](#run-eslint---fix-on-1-single-file-when-it-changes)\n    2. [Copy /static content to /public. On development, serve /public; on production, exit](#copy-static-content-to-public-on-development-serve-public-on-production-exit)\n5. [Supported options](#supported-options)\n6. [Credits](#credits)\n7. [License](#license)\n\n## Status\n![Linux \u0026 MacOS CI](https://github.com/AlexisPuga/precise-watcher/workflows/Linux%20%26%20MacOS%20CI/badge.svg)\n[![NPM version](https://badge.fury.io/js/precise-watcher.svg)](https://badge.fury.io/js/precise-watcher)\n\n## Installation\nRun `npm i precise-watcher` or `yarn add precise-watcher`.\n\n## Usage\nUsing `precise-watcher` is as simple as adding the following to your `package.json` and running `npm run watch`:\n``` js\n{\n  \"precise-watcher\": {\n    \"src\": [{\n      \"pattern\": [\"**/*\"],\n      \"on\": \"change\",\n      \"run\": [{\n        \"cmd\": \"echo\",\n        \"args\": [\"\u003cfile\u003e changed.\"]\n      }]\n    }]\n  },\n  \"scripts\": {\n    \"watch\": \"precise-watcher\"\n  },\n  \"devDependency\": {\n    \"precise-watcher\": \"^1.0.0\"\n  }\n}\n```\nTo run it, just modify any file not included in your .gitignore file...\n\n### Posibilities\nThis tool allows you to:\n- Run commands on 1 single file when it changes (by using \"\u0026lt;file\u0026gt;\" in src.run.args).\n- Call as many commands in parallel or serial as you want.\n- Watch not only for changes but errors, removals, addings, ...\n- Watch multiple sources and run multiple scoped commands.\n- Write complex solutions easily.\n- [From v2.0]: Run all your commands and exit. Useful for production!\n\nOnce you see what it does and why you need it, you can use it in any of the following ways:\n1. [NPM scripts](#watch-files-using-npm-scripts)\n2. [CLI](#watch-files-using-your-console)\n3. [Javascript](#watch-files-using-js)\n\n### Watch files using NPM scripts\nAdd `precise-watcher` to your `package.json` file in the following way:\n``` js\n{\n  \"precise-watcher\": {\n    // Your options go here.\n  },\n  \"scripts\": {\n    // Replace \"watch\" with whatever you want.\n    \"watch\": \"precise-watcher\"\n  }\n}\n```\nThen, run the NPM script (`npm run watch` in this case) and press `ctrl + c`, as normal, to stop watching files.\n\nAddittionaly, you can remove the options from your `package.json` file and use a config. file to set your options:\n\n#### Setting options in a configuration file\n[Create a config. file](#create-a-config-file) called ` precise-watcher.config.js ` (for example), and reference it using the ` --config ` option in the command you added before.\n\n``` js\n// precise-watcher.config.js\nmodule.exports = {\n  // Your options go here.\n}\n```\n``` json\n{\n  \"scripts\": {\n    \"watch\": \"precise-watcher --config precise-watcher.config.js\"\n  }\n}\n```\nAs you can see, you no longer need the `precise-watcher` property anymore.\n\n### Watch files using your console\nTo start watching file changes:\n1. [Create a config file](#create-a-config-file) called `precise-watcher.config.js`, for example.\n2. Run `./node_modules/.bin/precise-watcher --config precise-watcher.config.js`.\n\nTo stop watching file changes:\n- Press `ctrl + c`.\n\n#### Supported options\nBelow are a list of options that you can use with `precise-watcher`:\n\nOption   | Defaults      | Description \n:------- | :------------ | :----------\n--cwd    | process.cwd() | Directory for chokidar, config file, and child_process.spawn().\n--config | package.json  | Path to your config. file, relative to cwd.\n\n### Watch files using js\nShould be as easy as:\n``` js\nconst { start, stop, shutdown } = require('precise-watcher')\n\n// Resolves to an array of chokidar.watch() instances:\nstart().then(async (watchers) =\u003e {\n  // To remove some watchers:\n  // Resolves to an array of each watcher.close() result.\n  const closedWatchers = await stop(watchers)\n  // To remove all watchers:\n  const allClosedWatchers = await stop()\n\n  // To exit:\n  shutdown() // Calls stop() internally.\n}) // ...\n```\nWith async/await:\n``` js\nconst { start, stop, shutdown } = require('precise-watcher')\n\n(async () =\u003e {\n  try {\n    const watchers = await start()\n    const closedWatchers = await stop(watchers)\n    const allClosedWatchers = await stop()\n\n    shutdown()\n  } catch (error) {\n    // Log error...\n  }\n})()\n```\n\n## Examples\nIf you need more inspiration, you can check out these examples:\n\n### Run `eslint --fix` on 1 single file, when it changes\n1. Run `npm install eslint --save-dev`.\n2. Add the following to your `package.json`:\n``` json\n{\n  \"precise-watcher\": {\n    \"src\": [{\n      \"pattern\": [\"**/*.js\"],\n      \"on\": \"change\",\n      \"run\": [{\n        \"cmd\": \"echo\",\n        \"args\": [\n          \"Running eslint \u003cfile\u003e --fix\"\n        ],\n        \"callNext\": \"parallel\"\n      }, {\n        \"cmd\": \"eslint\",\n        \"args\": [\n          \"\u003cfile\u003e\",\n          \"--fix\"\n        ],\n        \"callNext\": \"serial\"\n      }, {\n        \"cmd\": \"echo\",\n        \"args\": [\"Done\"]\n      }]\n    }]\n  },\n  \"scripts\": {\n    \"watch\": \"precise-watcher\"\n  }\n}\n```\n3. Run `npm run watch`.\n4. Modify any .js file.\n\n\n\n### Copy /static content to /public. On development, serve /public; on production, exit.\n\n1. Install requirements: Run `npm install live-server precise-watcher@^2.0 cpy-cli --save-dev`.\n2. Create some files: `/static/index.html` and `/static/img/favicon.svg`, for example.\n3. Add the following to `precise-watcher.config.js`:\n\n```js\nconst {NODE_ENV} = process.env;\nconst isProduction = NODE_ENV === 'production';\nconst isDevelopment = !isProduction;\n\nmodule.exports = {\n    \"src\": [].concat(isDevelopment ? {\n        \"pattern\": \"public\",\n        \"on\": \"ready\",\n        \"run\": [{\n            // Start development server.\n            \"cmd\": \"live-server\",\n            \"args\": [\"public\"]\n        }]\n    } : {\n        \"pattern\": \"dist\",\n        // Empty the /dist dir.\n        \"run\": [{\n            \"cmd\": \"rm\",\n            \"args\": [\"dist -R\"]\n        }, {\n            \"cmd\": \"mkdir\",\n            \"args\": [\"dist\"]\n        }]\n    }).concat({\n        \"pattern\": [\"static/**/*.{jpg,jpeg,png,ico,svg,html}\"],\n        \"baseDir\": \"static\",\n        \"on\": (isProduction\n            ? null // Run as soon as possible.\n            : [\"ready\", \"change\"] // Run when chokidar is ready and when it detects a change.\n        )\n        \"run\": {\n            // Copy your static content (images and HTMLs), one by one.\n            \"cmd\": \"cpy\",\n            \"args\": `\u003cfile\u003e ../${isDevelopment ? \"public\" : \"dist\"} --cwd=static --parents`.split(\" \")\n        }\n    })\n};\n```\n\n3. Update your npm scripts (update your `package.json`):\n```json\n\"scripts\": {\n    \"start\": \"precise-watcher --config precise-watcher.config.js\",\n    \"dev\": \"NODE_ENV=development npm run start\",\n    \"prod\": \"NODE_ENV=production npm run start\"\n}\n```\n\n4. Run `npm run dev` and wait for your browser to start. Then, modify any file (e.g, `static/index.html`) and your changes should be visible right away.\n\n5. When you're done, hit `ctrl + c` and run `npm run prod`. Your `/dist` folder will now contain all your final files.\n\n## Supported options\n``` js\n{\n  /** @type {?object} (Optional) chokidar options that will apply to all sources. Defaults to the following, as of chokidar@3.5: */\n  \"chokidar\": {\n    \"persistent\": true,\n    // Concatenated with src.ignoreFrom sources.\n    \"ignored\": [],\n    \"ignoreInitial\": false,\n    \"followSymlinks\": false,\n    // Defaults to value passed via --cwd, \"cwd\" param in src/start.js' main function, or process.cwd()\n    \"cwd\": \"\",\n    \"disableGlobbing\": false,\n    \"usePolling\": false,\n    \"useFsEvents\": true,\n    \"alwaysStat\": false,\n    \"depth\": undefined,\n    \"awaitWriteFinish\": false,\n    \"ignorePermissionErrors\": false,\n    \"atomic\": true\n  },\n  /** @type {object|object[]} Source(s) to watch. */\n  \"src\": [{\n    /** @type {string|RegExp|string[]|RegExp[]} Pattern(s) to watch. */\n    \"pattern\": [],\n    /** @type {?string} (Optional) Set \"\u003cfile\u003e\" replacement relative to this value. Basically: path.relative(baseDir, watchedFile). Useful to convert /some/path/file to /file, for example */\n    \"baseDir\": \"\",\n    /** @type {?string} A path to a .gitignore-like file to ignore sources matched by src.pattern. Relative to cwd. */\n    \"ignoreFrom\": \".gitignore\",\n    /** @type {object|object[]} An array of commands. */\n    \"run\": [{\n      /** @type {?string} The command to run. */\n      \"cmd\": \"\",\n      /**\n       * @type {?string[]} List of arguments for cmd.\n       *\n       * Use \"\u003cfile\u003e\" to replace it with the changed filepath if the event\n       * supports it, or set each src.pattern value as default (and call\n       * this command in parallel multiple times with each given pattern).\n       */\n      \"args\": [],\n      /** @type {?string} Any of \"serial\" or \"parallel\". Defaults to \"serial\". */\n      \"callNext\": \"serial\",\n      /**\n       * @type {?function} A function triggered before running the command.\n       * @return {?boolean} If false is returned, the command won't run.\n       */\n      beforeRun (cmdInfo, eventInfo) {\n        const {\n          callNext,\n          patterns,\n          baseDir,\n          commands\n        } = this;\n        const {\n          cmd,\n          args: cmdArgs,\n          options: cmdOptions\n        } = cmdInfo;\n        const {\n          name: eventName,\n          args: eventArgs\n        } = eventInfo;\n        let keepRunning = true;\n\n        return keepRunning;\n      }\n    }],\n    /** @see https://github.com/paulmillr/chokidar */\n    /** @type {?string[]|?string} One or many chokidar events: \"add\", \"unlink\", \"addDir\", \"unlinkDir\", \"error\", \"ready\", \"raw\". */\n    \"on\": [],\n    /** @see https://github.com/paulmillr/chokidar */\n    /** @type {?object} Chokidar options that will apply to these sources only. Merged with global \"chokidar\" options. */\n    \"chokidar\": {}\n  }]\n}\n```\n## Credits\nThanks to \u003ca href='https://github.com/paulmillr/chokidar'\u003eChokidar\u003c/a\u003e's author and contributors and this project's contributors.\n\n## License\nThis project is \u003ca href='https://github.com/AlexisPuga/precise-watcher/blob/master/LICENSE'\u003eMIT Licensed\u003c/a\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexispuga%2Fprecise-watcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexispuga%2Fprecise-watcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexispuga%2Fprecise-watcher/lists"}