node package manager

@nrser/ugh

Ugh

Don't use this.

I wrote it because I was dealing with way too many cross-dependent co-developed node packages at one time and I couldn't get gulp to work in a way I considered consistent or reliable and I couldn't find anything that seemed like it would.

But you can. You're better than me. I believe in you. Please. The last thing the world needs is another shitty over-engineered, under-understood, widely-misused build tool.

Everything past here is just assorted dribble I half-wrote at various times during "development".

What I Want

or, "motivation"...

Incremental-First Approach

most all the building everyone does is incremental. full builds are stupid easy. i care about optimizing for reactive, correct, fast incremental builds during development.

Reactive

things should do what they need to do in response to changes to the source files. this is called watching in most build systems, and seems to be implemented as a bit of an add-on or afterthought, where to me it's the central concern.

Correct

  1. don't leave destination files in place if the source file was deleted. this can cause major confusion if there are old import lines accidentally left behind (which there often are) as the old compiled file gets used.

    ugh should automatically delete destination files when the source file is removed. the "watch" functionality in both gulp and fly seems like an afterthought that exhibits this behavior.

  2. don't leave the build in an inconsistent state.

    • clean out dependent files when their upstream sources change. this includes cleaning bundles when source files change so that developers aren't seeing an old bundle in the client when compilation fails. i think it's better to clearly on the client that the bundle is not there then load the old one.

    • don't write some compiled files if other fail.

Fast

  1. don't waste time with unnecessary spin-up and IO.

    just like it's super easy to do a full build every time, it's also super easy to spin up a new process, read in all the source files, and write all the destination files each time you need to execute a task - but it's slow as shit. don't do this.

    this means that:

    1. tasks should keep their libraries in memory if possible (not spawn).

      this can be tricky since most of these build tools were written under the presumption they would execute in their own process. mocha for instance seems to often break unless it starts clean every time. luckily, it spins up fast enough that it's not a huge problem.

    2. file contents should be kept in memory if possible.

      writing to the disk just for another task to read it in is stupid and slow. we can pass the buffer directly and write to the disk asynchronously.

      i would say we want to use streams to process as available, but i don't think nearly any of the build tools we use are capable of processing streams.

  2. don't thrash.

    for what i'm going to call pipe tasks that map in files to out files 1:1 the task can be executed whenever files change (though you might want a cooldown, what grunt seems to call debounce delay).

    for what i'm going to call funnel tasks that map in file to out files n:m where n > m (usually m = 1), i don't want the task run several times

Sub-Package Inclusion

i want to be able to include sub-packages that live under the project tree (most often as git sub-modules during co-development).

Versions

v0.6.X

Dropped Gulp tasks as a CLI front-end.

v0.5.X

API changes to do with upgrading from Webpack 1 to 2 and having Webpack directly read JavaScript source files instead of using the Babel transformed ES3 versions.

v0.4.X

Changed how Mocha tasks are configured:

https://github.com/nrser/ugh/commit/0c34eb863db11b80396e9b5aa3552665644d0727

v0.3.X

This was started to work on the task dependency graph stuff that never really materialized.

v0.2.X

The current version, which has the web UI.

v0.1.X

ugh before the web UI was added. i don't indent to keep developing on that branch, but it's there in case it's needed for some reason. v0.2 is almost totally compatible, so i don't see any reason for packages to stay depended on v0.1 versions.