Royi Bernthal
Royi Bernthal

Reputation: 462

TypeScript Compile Order to Single File

I'm compiling my TypeScript project into a single JS file, at the moment by specifying an outFile in the compiler options. In my project each class is defined in a different file.

The problem is that classes that depend on each other are not concatenated in the output JS in the right order.

For example, if I have class A that extends class B, it'd mean class B would have to be compiled before class A.

(1)

class A extends B { } //error - can't find B

class B { }

(2)

class B { }

class A extends B { } //works as expected

The problem is the file order in TypeScript compile is not defined according to class dependencies, resulting in many instances of (1).

It can be solved by manually defining the compile order with many lines of:

/// <reference path="myFile.ts"/>

however it is not ideal and can quickly become a headache in large projects.

The other option from what I read is to use external modules and be able to require/import relevant classes/files.

It sounds good, but it seems to only take care of ASYNC loading during runtime of the required files after each ts file has been compiled into its own js file.

What I need is defining the right compile order according to class dependencies during compile time from ts to js.

I googled "typescript compile order" and read thoroughly the first 10 results - meaning following references to turoials, documentations, videos, etc...

It seems people have been experiencing the same problem but their questions have never been answered to satisfaction.

From what I understand it should be possible to do using the CommonJS external module, but all I can understand from the answers is a general sense of what should be happening rather than a simple and straightforward answer of how to actually do it.

If you know the answer, let's solve this issue once and for all :)

Upvotes: 8

Views: 3670

Answers (2)

sgrtho
sgrtho

Reputation: 218

It is safe to say that there's no one way to do this. But I advise you to aim for the safest and most sophisticated build/bundling setup you can get. Depending on the scale of your project, consider the following points.

You can manually define a sort order for your output. Will it scale? No. Sorting hundreds of files and resolving conditional or circular dependencies can be a real pain, and erroneous by the way.

You can rely on reference tags and the compiler's ordering when using the out option. I think of this as the worst solution to aim for. At a certain project size and assuming there is a reasonable amount of non-perfect software design in it, you might end up with non-deterministic output ordering and zero warning or protection against dependency problems.

That is why I advise the following:

  • Use import/export to enforce your dependencies, you'll have compiled modules, and you'll need a loader/bundler, yes
  • Avoid circular dependencies, use the dependency graph or tools like madge to find them
  • Use a loader and a pleasent workflow to create your dist files (we use gulp/browserify/tsify/concat/...) - the core of it is about 20 lines of code

Is your project going to be tiny? 20 files? 50? Choose any. Is your project large enough? Modules it is. Enjoy several benefits like slicker node modules bundling or less need for name spacing.

Upvotes: 1

Paleo
Paleo

Reputation: 23682

It is not an issue with TypeScript, but with ECMAScript: classes are not hoisted.

See the book of Dr. Axel Rauschmayer:

Function declarations are hoisted: When entering a scope, the functions that are declared in it are immediately available – independently of where the declarations happen. That means that you can call a function that is declared later:

foo(); // works, because `foo` is hoisted

function foo() {}

In contrast, class declarations are not hoisted. Therefore, a class only > exists after execution reached its definition and it was evaluated. Accessing it beforehand leads to a ReferenceError:

new Foo(); // ReferenceError

class Foo {}

You have to take care to the order.

… or to use a bundler (Webpack) or a loader (SystemJS) with ES6 modules.

Upvotes: 1

Related Questions