tessera-metrics / tessera

A dashboard front-end for graphite.
http://tessera-metrics.github.io/tessera/
Apache License 2.0
1.19k stars 81 forks source link

Split client side code up into multiple modules #467

Open aalpern opened 9 years ago

aalpern commented 9 years ago

One of the things we'd like to do is script the creation and maintenance of dashboards from other automated internal tooling. To do that, we need to extract a clean API client library, so the front-end code needs to be split into modules.

Likely modules:

This will end up complicating the process of adding new dashboard items a bit, as we'll need to separate the model object from the rendering code, but (a) that's a good separation to have, and (b) adding new dashboard items isn't that frequent a task; we've got quite an extensive roster of them already.

aalpern commented 9 years ago

Sigh.

Typescript isn't quite ready for packaging separate modules the way I want it to be. Although some of it might just be Javascript, I'm not sure which. So it appears to be impossible to export classes intended to be subclassed from one library to another, at least with es6 class and extends syntax, as well as some other general import/export hassles with naming and visibility.

For example:

/Users/alpern/src/tessera/tessera-js-model/src/ts/models/transform/transform.ts(40,14): 
error TS4023: Exported variable 'transforms' has or is using name 'Registry' from 
external module "/Users/alpern/src/tessera/tessera-js-model/node_modules/tessera-core/dist/core/registry" 
but cannot be named.

The only google hit for that "but cannot be named" error is the source code for the typescript compiler itself. And all I'm doing there is instantiating a class (a generic class, yes, but it's fully described as generic in the .d.ts file, so one could quite reasonable assume that there shouldn't be an issue...)

aalpern commented 9 years ago

Apparently the problem is with aliasing - the core packages are bundled up with this:

export { json, extend } from './core/util';
export { logger, Level as LogLevel } from './core/log';
export { NamedObject, Registry } from './core/registry';
export { default as EventSource } from './core/event-source';

Apparent that turns the exported Registry into an aliased object literal, rather than a generic class identifier, and aliased object literals can't be subclassed (or event instantiated with new? must be something to do with generics).

If I put this import in transform.ts it compiles:

import * as core from '../../../../node_modules/tessera-core/dist/core/registry'

But that's really clumsy, and the aliasing issue means we can't centralize imports to isolate the reference paths (which it looks like should go away with node_modules support in Typescript 2.0).

aalpern commented 9 years ago

node_modules support is available now in TS 1.6 (via --moduleResolution node), and internal tests indicate that it's entirely feasible to create an npm package of javascript bundled with type information and import it with a relative ES6 import statement (i.e. import * as core from "tessera-core") and it Just Works if you set it all up right.

aalpern commented 9 years ago

Just found a new HTTP client lib with browser+node support that looks like it may be an improvement over superagent (my current go-to lib): https://github.com/mzabriskie/axios