Closed DesignByOnyx closed 1 year ago
You should support all node LTS versions. I know 14 and 16 will be dead later this year, but if you install turbowatch on 14 or 16 today it says that that version is not supported. This isn't a very good first taste for new users. FWIW - I'm on node 16.19.0 and it seems to be working just fine!
See the point about the start time below.
Export ProcessPromise, et al. I am needing to save a reference to one of the processes that I spawn, and I need the types.
Generally, I am careful about not exporting anything that is not a public interface. ProcessPromise
is an oversight though. Anything else that you were missing?
Add an onStart callback, or explain that onChange is called during startup with an empty files array.
That's what the initialRun
is for. The benefit of the current approach VS adding onStart
is that you can re-use the logic in your onChange
callback between initial run and future change events.
However, I am open to considering getting rid of initialRun
in place of onStart
, as the latter is more explicit. Will open a separate issue to track it.
Show some use cases for using multiple triggers. I don't understand the need for an array.
Example: In the same project, we have a steps to...
I am open to adding examples, but it is effectively any time when you need several different workflows.
Using project: __dirname is very slow on a small monorepo, even if I have an expression to ignore node_modules. It takes roughly ~6s to start. If I watch a single folder, it takes ~40ms. I usually only need to watch 4-5 folders at a time. It would be nice if I could pass an array of these folders to the project instead of passing the repo root __dirname.
Regarding start time, this is because of your Node.js version. Node.js v19 and upwards supports fs.watch
recursively. Earlier versions require scanning the entire file tree, which is going to be very slow. Therefore, realistically, this project will only have desirable DX in Node.js v19 and upwards.
You can of course bring your own backend. However, that most likely will require installing a third-party software like Watchman, so it isn't the default.
Coming from nodemon, maybe consider a simplistic API for easy use cases and easy adoption, keeping the existing [more verbose] API for more advanced scenarios. The expression syntax is kinda weird.
I am open to exploring it (in a separate issues), but generally speaking it is not a simple problem b/c of BYO backend architecture. The most simple abstraction is "watch all, and use Turbowatch to filter relevant results". The moment you lift some of this logic up to the backends, then you make some of them incompatible with Turbowatch, e.g. Watchman very much relies on a single root + filter logic, and it is by far the most cross-platform compatible backend.
Thanks for your suggestions. Will open separate threads for some of these suggestions to track them.
Thanks for all of your feedback (and sorry to dump it in one big message). Everything you said makes perfect sense.
ProcessPromise
was the only thing I really needed - you might want to expose ProcessOutput
as well.initialRun
- the single callback makes perfect sense and totally agree it helps avoid code duplication.type SimpleConfig = {
script?: string;
ext?: string;
exec?: string;
delay?: number;
watch?: string | string[];
ignore?: string | string[];
}
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
function watch(config: SimpleConfig | TurbowatchConfigurationInput) {
if (!('triggers' in config)) {
// using simple syntax
const { script, ext, exec, delay, watch: directories, ignore } = config;
const extensions = ext || 'js,mjs,coffee,litcoffee,json';
const expression: Expression = ['allof'];
const waitMS = delay || 1000;
expression.push(['anyof', ...extensions.split(',').map(e => ['match', `*.${e}`, 'basename'])])
if (directories) {
const dirArr = typeof directories === 'string' ? [directories] : directories;
expression.push(['anyof', ...dirArr.map(w => ['directory', w])])
}
if (ignore) {
const ignoreArr = typeof ignore === 'string' ? [ignore] : ignore;
expression.push(['not', ['anyof', ...ignoreArr.map(i => ['match', i, 'wholename'])]])
}
return watch({
project: process.cwd(),
triggers: [{
name: 'simple-watch-task',
initialRun: true,
interruptible: true,
expression,
onChange: async ({ spawn, first, abortSignal }) => {
if (!first) await sleep(waitMS);
if (abortSignal.aborted) return;
if (script) await spawn`node ${script}`;
else if (exec) await spawn(exec);
}
}]
});
}
// existing code here
}
Desired Behavior
I am a new user and am now a huge fan of this tool (I'm a long time nodemon user)! Thanks so much! I started an issue for one thing, but as I've been using the tool there are several other things... so I thought I'd list them in one place for triage. Please let me know if you'd like me to break this into smaller pieces.
ProcessPromise
, et al. I am needing to save a reference to one of the processes that I spawn, and I need the types.onStart
callback, or explain thatonChange
is called during startup with an empty files array.project: __dirname
is very slow on a small monorepo, even if I have an expression to ignore node_modules. It takes roughly ~6s to start. If I watch a single folder, it takes ~40ms. I usually only need to watch 4-5 folders at a time. It would be nice if I could pass an array of these folders to theproject
instead of passing the repo root __dirname.Coming from nodemon, maybe consider a simplistic API for easy use cases and easy adoption, keeping the existing [more verbose] API for more advanced scenarios. The expression syntax is kinda weird.
Motivation
I just want to make this tool cool as ever. These are merely suggestions, coming from a long-time nodemon user and a turborepo user who desperately wants a watch script.