Output File Ordering

Topics: General
May 18, 2014 at 3:10 AM
Edited May 18, 2014 at 3:12 AM
Hello Community,

I am diving into TypeScript, and one of the features I am exploring is the output into a single file. However, I am running into a problem and I am hoping to get assistance.

My app.ts:
var greeter = new Testing.Greeter("Hello TypeScript");   
var temp = greeter.sayHello();
My greeter.ts:
module Testing
{
    export class Greeter {
        subject: string;
        constructor(subject: string) {
            this.subject = subject || "World";
        }

        sayHello() {
            return "Hello " + this.subject;
        }
    }
}
My output.js:
var greeter = new Testing.Greeter("Hello TypeScript");
var temp = greeter.sayHello();

var Testing;
(function (Testing) {
    var Greeter = (function () {
        function Greeter(subject) {
            this.subject = subject || "World";
        }
        Greeter.prototype.sayHello = function () {
            return "Hello " + this.subject;
        };
        return Greeter;
    })();
    Testing.Greeter = Greeter;
})(Testing || (Testing = {}));
As you can see, Testing.Greeter is defined after the output from app.ts, and so when I new up a Testing.Greeter, it is undefined.

I realize I could use a setTimeout, but that always smells of a hack. In an HTML page, I could use the window.onload, however, I am in a NodeJS application.

So, the questions are:

1) Is there a way to change the ordering of the file output (preferred)? If not,
2) Is there an "onload" in NodeJS? (a search for this turned up empty).

Thank you in advance for any assistance you can lend,
Michael
Coordinator
May 18, 2014 at 7:40 PM
There are a couple of ways you can change order in the generated code:
  1. Order of arguments on the command line: tsc greeter.ts app.ts --out output.js
  2. /// references; the reference tag acts like a dependency declaration, the compiler will build a dependency graph following the reference tags and ensuring, in absence of cycles, that all dependencies come before the file declaring them in the output. In your example add to app.ts /// <reference path="greeter.ts" />
May 18, 2014 at 8:18 PM
Thank you for your reply, mhegazy. For the command line, I am actually using Visual Studio 2013. Is there a way to configure VS2013 to do this?

As for the 2nd option, this seems like VS2013 would know that the startup/main file should be the last file emitted in the output file. That is, there shouldn't be a need to reference dependencies, and they should be determined by the compiler...
Coordinator
May 18, 2014 at 10:35 PM
You are correct. In VS you can not use the command line argument order as the files will be passed to the compiler in the order they appear in the project file, and project files are not order-sensitive.

In VS, however, you can use _references.ts. If your project has a typescript file at the root named "_references.ts", the IDE will consider it the first file in the list. Since we are walking the depencency chain in the files following /// references, your /// references in this file (_references.ts) will take precedence. so in your example:
_references.ts
/// <reference path="greeter.ts" /> 
This guarantees that greeter comes before app in the output. Also note that you do not need to put a reference to all your files in this file, you only should put the files you care about their order. so in your case, a reference to greeter.ts is sufficient.

As for your second question, I am not sure I understand. TypeScript does not have a concept of a startup/main file. The IDE thinks of the project as a collection of files, and unless you specify the ordering using /// references (whether in each file, or in a the special _references.ts) the IDE has no way of knowing what is the desired order.
Marked as answer by MichaelDBang on 5/18/2014 at 2:53 PM
May 18, 2014 at 10:52 PM
Ah! I am getting my environments confused. I am also using NodeJS Tools for Visual Studio 2013, so yes you are correct, there is no "main" file for a typical TypeScript HTML Application. Sorry for the confusion.

However, I will say that NodeJS has the right idea in many regards. Because it does have a notion/concept of a main file (and also a startup file). It should be able to infer the dependencies (and their corresponding order) by starting with that file and working from there throughout a project.

As an aside, it's amazing (read: confounding) to see that as more technologies come out to reduce manual reference definitions (such as requirejs/node), there seems to be another technology that comes out to undo their hard work. That is, RequireJS was created to eliminate the following maintenance madness in a HTML page:
<script src="path/to/script1.js />
<script src="path/to/script2.js />
<script src="path/to/script3.js />
And now that this has been solved through RequireJS, TypeScript comes along and introduces its own version:
/// <reference path="path/to/script1.ts" />
/// <reference path="path/to/script2.ts" />
/// <reference path="path/to/script3.ts" />
Just an observation. It just seems like we should be past this unnecessary (and annoying, frustrating, etc.) aspect of JavaScript development by now.