uProxy/uproxy-lib — pull request #72 by trevj (2014-09-23 19:01:54+00:00)
Title: switch to grunt-ts for timestamp-based conditional recompilation

So, slow compiles annoy me too:
https://github.com/uProxy/uproxy-networking/issues/110

The big missing feature for us, I believe, was support for outputting compiled JS to a separate folder hierarchy, i.e. from `build/typescript-src/xxx` -> `build/xxx`.

This pull request proposes a slightly different build process in which TypeScript files _can_ be compiled "in-place". Roughly, the steps are:

1. symlink each file in every folder under `src/` under `build/`
2. symlink each directory under `third_party/` under `build/`
3. for each folder under `build/`:
1. compile all the source files inside
2. run all the tests inside
3. create a folder under `dist/` and copy all the `*.js` and `*.d.ts` files to it

Lastly, each sample app's directory (in `dist/`) gets a copy of `dist/` in a `lib/` folder.

I spent a lot of time considering how to prevent breaking dependant repos and I believe, apart from sample apps, the eventual output is identical to today.

Graphically, you will end up with something like this on disk:

```
test/
├── build
│ ├── bar
│ │ ├── bar.d.ts -> ../../src/bar/bar.d.ts
│ │ ├── bar.js
│ │ ├── bar.js.map
│ │ ├── bar.spec.js
│ │ ├── bar.spec.js.map
│ │ ├── bar.spec.ts -> ../../src/bar/bar.spec.ts
│ │ └── bar.ts -> ../../src/bar/bar.ts
│ ├── foo
│ │ ├── foo.html -> ../../src/foo/foo.html
│ │ ├── foo.js
│ │ ├── foo.js.map
│ │ └── foo.ts -> ../../src/foo/foo.ts
│ ├── samples
│ │ └── helloworld
│ │ ├── helloworld.js
│ │ ├── helloworld.js.map
│ │ ├── helloworld.ts -> ../../../src/samples/helloworld/helloworld.ts
│ │ └── manifest.json -> ../../../src/samples/helloworld/manifest.json
│ └── third_party
│ └── angular -> ../../third_party/angular/
├── dist
│ ├── bar
│ │ ├── bar.d.ts
│ │ ├── bar.js
│ │ ├── bar.js.map
│ │ └── bar.ts
│ ├── foo
│ │ ├── foo.html
│ │ ├── foo.js
│ │ ├── foo.js.map
│ │ └── foo.ts
│ └── samples
│ └── helloworld
│ ├── helloworld.js
│ ├── helloworld.js.map
│ ├── helloworld.ts
│ ├── lib
│ │ ├── bar
│ │ │ ├── bar.d.ts
│ │ │ ├── bar.js
│ │ │ ├── bar.js.map
│ │ │ └── bar.ts
│ │ └── foo
│ │ ├── foo.html
│ │ ├── foo.js
│ │ ├── foo.js.map
│ │ └── foo.ts
│ └── manifest.json
├── Gruntfile.js
├── src
│ ├── bar
│ │ ├── bar.d.ts
│ │ ├── bar.spec.ts
│ │ └── bar.ts
│ ├── foo
│ │ ├── foo.html
│ │ └── foo.ts
│ └── samples
│ └── helloworld
│ ├── helloworld.ts
│ └── manifest.json
└── third_party
└── angular
└── angular.js
```

Ideally, only `dist/` would end up in the NPM. For now, we keep `build/` just to prevent disruption to dependant repos.

Time-wise, I see an initial time of ~44s for `grunt build` which drops to ~8s for subsequent builds without changes. Changing one source file, subsequent `grunt build`s take ~11s. Most of that ~8s is spent re-building Freedom and we can be smarter about that, e.g. use `grunt-contrib-watch`.

Nothing in this precludes future use of `grunt-contrib-watch` or Karma.

What's still TODO? I tried compiling churn against this version of `uproxy-lib` and I think the `base` target needs to be made re-useable. This was unavoidable, and shouldn't be hard to implement. Of course, I'll take the time to update the dependant repos if we feel this is worthwhile overall.